diff --git a/examples/device-dashboard/Makefile b/examples/device-dashboard/Makefile index d3f89de3..423bd428 100644 --- a/examples/device-dashboard/Makefile +++ b/examples/device-dashboard/Makefile @@ -1,6 +1,6 @@ PROG ?= example SOURCES ?= ../../mongoose.c main.c net.c packed_fs.c -CFLAGS ?= -I../.. -DMG_ENABLE_PACKED_FS=1 $(EXTRA) +CFLAGS ?= -I../.. -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_LINES=1 $(EXTRA) FILES_TO_EMBED ?= $(wildcard web_root/*) ROOT ?= $(realpath $(CURDIR)/../../..) DOCKER ?= docker run --rm -e Tmp=. -e WINEDEBUG=-all -v $(ROOT):$(ROOT) -w $(CURDIR) diff --git a/examples/device-dashboard/main.c b/examples/device-dashboard/main.c index 431b4767..87dcfa11 100644 --- a/examples/device-dashboard/main.c +++ b/examples/device-dashboard/main.c @@ -2,15 +2,17 @@ // All rights reserved #include "mongoose.h" +const char *s_listening_url = "http://0.0.0.0:8000"; void device_dashboard_fn(struct mg_connection *, int, void *, void *); int main(void) { struct mg_mgr mgr; - mg_log_set("3"); + mg_log_set("2"); // Set to 3 for debug, to 4 for very verbose level mg_mgr_init(&mgr); - mg_http_listen(&mgr, "http://0.0.0.0:8000", device_dashboard_fn, &mgr); - for (;;) mg_mgr_poll(&mgr, 1000); + mg_http_listen(&mgr, s_listening_url, device_dashboard_fn, &mgr); + MG_INFO(("Listening on %s", s_listening_url)); + while (mgr.conns != NULL) mg_mgr_poll(&mgr, 500); mg_mgr_free(&mgr); return 0; } diff --git a/examples/device-dashboard/net.c b/examples/device-dashboard/net.c index f0b76a85..a0d05335 100644 --- a/examples/device-dashboard/net.c +++ b/examples/device-dashboard/net.c @@ -25,6 +25,7 @@ static struct config { } s_config; static struct mg_connection *s_mqtt = NULL; // MQTT connection +static bool s_connected = false; // MQTT connection established // Try to update a single configuration value static void update_config(struct mg_str *body, const char *name, char **value) { @@ -66,8 +67,10 @@ static void send_notification(struct mg_mgr *mgr, const char *name, const char *data) { struct mg_connection *c; for (c = mgr->conns; c != NULL; c = c->next) { - if (c->label[0] == 'W') - mg_http_printf_chunk(c, "{\"name\": \"%s\", \"data\": %s}", name, data); + if (c->label[0] != 'W') continue; + // c->is_hexdumping = 1; + mg_ws_printf(c, WEBSOCKET_OP_TEXT, "{\"name\": \"%s\", \"data\": %s}", name, + data); } } @@ -76,33 +79,40 @@ static void timer_metrics_fn(void *param) { char buf[50]; mg_snprintf(buf, sizeof(buf), "[ %lu, %d ]", (unsigned long) time(NULL), 10 + (int) ((double) rand() * 10 / RAND_MAX)); - // MG_INFO(("%s", buf)); send_notification(param, "metrics", buf); + // MG_INFO(("%s", buf)); } // MQTT event handler function static void mqtt_fn(struct mg_connection *c, int ev, void *evd, void *fnd) { if (ev == MG_EV_MQTT_OPEN) { - struct mg_str topic = mg_str(s_config.pub); - mg_mqtt_sub(s_mqtt, &topic, 1); + s_connected = true; + // c->is_hexdumping = 1; + mg_mqtt_sub(s_mqtt, mg_str(s_config.sub), 1); + send_notification(c->mgr, "config", "null"); } else if (ev == MG_EV_MQTT_MSG) { struct mg_mqtt_message *mm = evd; char buf[256]; snprintf(buf, sizeof(buf), "{\"topic\":\"%.*s\",\"data\":\"%.*s\"}", (int) mm->topic.len, mm->topic.ptr, (int) mm->data.len, mm->data.ptr); - send_notification(param, "message", buf); + send_notification(c->mgr, "message", buf); } else if (ev == MG_EV_CLOSE) { s_mqtt = NULL; + if (s_connected) { + s_connected = false; + send_notification(c->mgr, "config", "null"); + } } + (void) fnd; } // Keep MQTT connection open - reconnect if closed -static void timer_metrics_fn(void *param) { +static void timer_mqtt_fn(void *param) { struct mg_mgr *mgr = (struct mg_mgr *) param; if (s_mqtt == NULL) { struct mg_mqtt_opts opts = {}; - s_mqtt = mg_mqtt_connect(mgr, s_config.rl, &opts, mqtt_fn, NULL); + s_mqtt = mg_mqtt_connect(mgr, s_config.url, &opts, mqtt_fn, NULL); } } @@ -127,8 +137,10 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data, mg_printf(c, "%s", "HTTP/1.1 403 Denied\r\nContent-Length: 0\r\n\r\n"); } else if (mg_http_match_uri(hm, "/api/config/get")) { mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); - mg_http_printf_chunk(c, "{\"url\":\"%s\",\"pub\":\"%s\",\"sub\":\"%s\"}", - s_config.url, s_config.pub, s_config.sub); + mg_http_printf_chunk( + c, "{\"url\":\"%s\",\"pub\":\"%s\",\"sub\":\"%s\",\"connected\":%s}", + s_config.url, s_config.pub, s_config.sub, + s_connected ? "true" : "false"); mg_http_printf_chunk(c, ""); } else if (mg_http_match_uri(hm, "/api/config/set")) { // Admins only @@ -136,6 +148,7 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data, update_config(&hm->body, "url", &s_config.url); update_config(&hm->body, "pub", &s_config.pub); update_config(&hm->body, "sub", &s_config.sub); + if (s_mqtt) s_mqtt->is_closing = 1; // Ask to disconnect from MQTT send_notification(fn_data, "config", "null"); mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); } else { @@ -143,14 +156,15 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data, } } else if (mg_http_match_uri(hm, "/api/message/send")) { char buf[256]; - if (mg_http_get_var(&hm->body, "message", buf + 1, sizeof(buf) - 2) > 0) { - buf[0] = buf[strlen(buf)] = '"'; - send_notification(fn_data, "message", buf); + if (s_connected && + mg_http_get_var(&hm->body, "message", buf, sizeof(buf)) > 0) { + mg_mqtt_pub(s_mqtt, mg_str(s_config.pub), mg_str(buf), 1, false); } mg_printf(c, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); } else if (mg_http_match_uri(hm, "/api/watch")) { c->label[0] = 'W'; // Mark ourselves as a event listener - mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); + mg_ws_upgrade(c, hm, NULL); + // mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); } else if (mg_http_match_uri(hm, "/api/login")) { mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); mg_http_printf_chunk(c, "{\"user\":\"%s\",\"token\":\"%s\"}\n", u->name, @@ -158,7 +172,7 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data, mg_http_printf_chunk(c, ""); } else { struct mg_http_serve_opts opts = {0}; -#if 0 +#if 1 opts.root_dir = "/web_root"; opts.fs = &mg_fs_packed; #else diff --git a/examples/device-dashboard/packed_fs.c b/examples/device-dashboard/packed_fs.c index 777d560b..454757e1 100644 --- a/examples/device-dashboard/packed_fs.c +++ b/examples/device-dashboard/packed_fs.c @@ -48,7 +48,43 @@ static const unsigned char v2[] = { 110, 46, 106, 115, 39, 59, 10, 10, 99, 111, 110, 115, // n.js';..cons 116, 32, 77, 97, 120, 77, 101, 116, 114, 105, 99, 115, // t MaxMetrics 68, 97, 116, 97, 80, 111, 105, 110, 116, 115, 32, 61, // DataPoints = - 32, 53, 48, 59, 10, 10, 99, 111, 110, 115, 116, 32, // 50;..const + 32, 53, 48, 59, 10, 10, 47, 47, 32, 84, 104, 105, // 50;..// Thi + 115, 32, 115, 105, 109, 112, 108, 101, 32, 112, 117, 98, // s simple pub + 108, 105, 115, 104, 47, 115, 117, 98, 115, 99, 114, 105, // lish/subscri + 98, 101, 32, 105, 115, 32, 117, 115, 101, 100, 32, 116, // be is used t + 111, 32, 112, 97, 115, 115, 32, 110, 111, 116, 105, 102, // o pass notif + 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, 104, 97, // ications tha + 116, 32, 119, 101, 114, 101, 10, 47, 47, 32, 114, 101, // t were.// re + 99, 101, 105, 118, 101, 100, 32, 102, 114, 111, 109, 32, // ceived from + 116, 104, 101, 32, 115, 101, 114, 118, 101, 114, 44, 32, // the server, + 116, 111, 32, 97, 108, 108, 32, 99, 104, 105, 108, 100, // to all child + 32, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 32, // components + 111, 102, 32, 116, 104, 101, 32, 97, 112, 112, 46, 10, // of the app.. + 118, 97, 114, 32, 80, 117, 98, 83, 117, 98, 32, 61, // var PubSub = + 32, 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, 41, // (function() + 32, 123, 10, 32, 32, 118, 97, 114, 32, 104, 97, 110, // {. var han + 100, 108, 101, 114, 115, 32, 61, 32, 123, 125, 44, 32, // dlers = {}, + 105, 100, 32, 61, 32, 48, 59, 10, 32, 32, 114, 101, // id = 0;. re + 116, 117, 114, 110, 32, 123, 10, 32, 32, 32, 32, 115, // turn {. s + 117, 98, 115, 99, 114, 105, 98, 101, 58, 32, 102, 117, // ubscribe: fu + 110, 99, 116, 105, 111, 110, 40, 102, 110, 41, 32, 123, // nction(fn) { + 10, 32, 32, 32, 32, 32, 32, 104, 97, 110, 100, 108, // . handl + 101, 114, 115, 91, 105, 100, 43, 43, 93, 32, 61, 32, // ers[id++] = + 102, 110, 59, 10, 32, 32, 32, 32, 125, 44, 10, 32, // fn;. },. + 32, 32, 32, 117, 110, 115, 117, 98, 115, 99, 114, 105, // unsubscri + 98, 101, 58, 32, 102, 117, 110, 99, 116, 105, 111, 110, // be: function + 40, 105, 100, 41, 32, 123, 10, 32, 32, 32, 32, 32, // (id) {. + 32, 100, 101, 108, 101, 116, 101, 32, 104, 97, 110, 100, // delete hand + 108, 101, 114, 115, 91, 105, 100, 93, 59, 10, 32, 32, // lers[id];. + 32, 32, 125, 44, 10, 32, 32, 32, 32, 112, 117, 98, // },. pub + 108, 105, 115, 104, 58, 32, 102, 117, 110, 99, 116, 105, // lish: functi + 111, 110, 40, 100, 97, 116, 97, 41, 32, 123, 10, 32, // on(data) {. + 32, 32, 32, 32, 32, 102, 111, 114, 32, 40, 118, 97, // for (va + 114, 32, 107, 32, 105, 110, 32, 104, 97, 110, 100, 108, // r k in handl + 101, 114, 115, 41, 32, 104, 97, 110, 100, 108, 101, 114, // ers) handler + 115, 91, 107, 93, 40, 100, 97, 116, 97, 41, 59, 10, // s[k](data);. + 32, 32, 32, 32, 125, 10, 32, 32, 125, 59, 10, 125, // }. };.} + 41, 40, 41, 59, 10, 10, 99, 111, 110, 115, 116, 32, // )();..const 78, 97, 118, 32, 61, 32, 112, 114, 111, 112, 115, 32, // Nav = props 61, 62, 32, 104, 116, 109, 108, 96, 10, 60, 100, 105, // => html`..

. - 32, 32, 68, 101, 118, 105, 99, 101, 32, 67, 111, 110, // Device Con - 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 60, 47, // figuration.
. M - 81, 84, 84, 32, 115, 101, 114, 118, 101, 114, 58, 60, // QTT server:< - 47, 115, 112, 97, 110, 62, 10, 32, 32, 32, 32, 60, // /span>. < - 105, 110, 112, 117, 116, 32, 116, 121, 112, 101, 61, 34, // input type=" - 116, 101, 120, 116, 34, 32, 115, 116, 121, 108, 101, 61, // text" style= - 34, 102, 108, 101, 120, 58, 32, 49, 32, 49, 48, 48, // "flex: 1 100 - 37, 59, 34, 10, 32, 32, 32, 32, 32, 32, 32, 32, // %;". - 32, 32, 118, 97, 108, 117, 101, 61, 36, 123, 117, 114, // value=${ur - 108, 125, 32, 111, 110, 99, 104, 97, 110, 103, 101, 61, // l} onchange= - 36, 123, 117, 112, 100, 97, 116, 101, 117, 114, 108, 125, // ${updateurl} - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 111, // . o - 110, 105, 110, 112, 117, 116, 61, 36, 123, 101, 118, 32, // ninput=${ev - 61, 62, 32, 115, 101, 116, 85, 114, 108, 40, 101, 118, // => setUrl(ev - 46, 116, 97, 114, 103, 101, 116, 46, 118, 97, 108, 117, // .target.valu - 101, 41, 125, 32, 47, 62, 10, 32, 32, 32, 32, 60, // e)} />. < - 98, 117, 116, 116, 111, 110, 32, 99, 108, 97, 115, 115, // button class - 61, 34, 98, 116, 110, 34, 32, 100, 105, 115, 97, 98, // ="btn" disab - 108, 101, 100, 61, 36, 123, 33, 117, 114, 108, 125, 32, // led=${!url} - 111, 110, 99, 108, 105, 99, 107, 61, 36, 123, 117, 112, // onclick=${up - 100, 97, 116, 101, 117, 114, 108, 125, 10, 32, 32, 32, // dateurl}. - 32, 32, 32, 115, 116, 121, 108, 101, 61, 34, 109, 97, // style="ma - 114, 103, 105, 110, 45, 108, 101, 102, 116, 58, 32, 49, // rgin-left: 1 - 101, 109, 59, 32, 98, 97, 99, 107, 103, 114, 111, 117, // em; backgrou - 110, 100, 58, 32, 35, 56, 97, 97, 59, 34, 62, 85, // nd: #8aa;">U - 112, 100, 97, 116, 101, 60, 47, 98, 117, 116, 116, 111, // pdate.
. - 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, //
. - 32, 32, 32, 32, 60, 115, 112, 97, 110, 32, 99, 108, // Publi - 115, 104, 32, 116, 111, 112, 105, 99, 58, 60, 47, 115, // sh topic:. setVa - 108, 117, 101, 50, 40, 101, 118, 46, 116, 97, 114, 103, // lue2(ev.targ - 101, 116, 46, 118, 97, 108, 117, 101, 41, 125, 32, 47, // et.value)} / - 62, 10, 32, 32, 32, 32, 60, 98, 117, 116, 116, 111, // >. - 85, 112, 100, 97, 116, 101, 60, 47, 98, 117, 116, 116, // Update.
- 10, 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, // .
. Sub - 115, 99, 114, 105, 98, 101, 32, 116, 111, 112, 105, 99, // scribe topic - 58, 60, 47, 115, 112, 97, 110, 62, 10, 32, 32, 32, // :. - 32, 60, 105, 110, 112, 117, 116, 32, 116, 121, 112, 101, // setVa - 108, 117, 101, 50, 40, 101, 118, 46, 116, 97, 114, 103, // lue2(ev.targ - 101, 116, 46, 118, 97, 108, 117, 101, 41, 125, 32, 47, // et.value)} / - 62, 10, 32, 32, 32, 32, 60, 98, 117, 116, 116, 111, // >. - 85, 112, 100, 97, 116, 101, 60, 47, 98, 117, 116, 116, // Update.
- 10, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, // .
. - 32, 68, 101, 118, 105, 99, 101, 32, 107, 101, 101, 112, // Device keep - 115, 32, 97, 32, 112, 101, 114, 115, 105, 115, 116, 101, // s a persiste - 110, 116, 32, 99, 111, 110, 110, 101, 99, 116, 105, 111, // nt connectio - 110, 32, 116, 111, 32, 116, 104, 101, 32, 99, 111, 110, // n to the con - 102, 105, 103, 117, 114, 101, 100, 32, 77, 81, 84, 84, // figured MQTT - 32, 115, 101, 114, 118, 101, 114, 46, 10, 32, 32, 32, // server.. - 32, 67, 104, 97, 110, 103, 101, 115, 32, 116, 111, 32, // Changes to - 116, 104, 105, 115, 32, 99, 111, 110, 102, 105, 103, 117, // this configu - 114, 97, 116, 105, 111, 110, 32, 97, 114, 101, 32, 112, // ration are p - 114, 111, 112, 97, 103, 97, 116, 101, 100, 32, 116, 111, // ropagated to - 32, 97, 108, 108, 32, 100, 97, 115, 104, 98, 111, 97, // all dashboa - 114, 100, 115, 58, 32, 116, 114, 121, 10, 32, 32, 32, // rds: try. - 32, 99, 104, 97, 110, 103, 105, 110, 103, 32, 116, 104, // changing th - 101, 109, 32, 105, 110, 32, 116, 104, 105, 115, 32, 100, // em in this d - 97, 115, 104, 98, 111, 97, 114, 100, 32, 97, 110, 100, // ashboard and - 32, 111, 98, 115, 101, 114, 118, 101, 32, 99, 104, 97, // observe cha - 110, 103, 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, // nges in the - 111, 116, 104, 101, 114, 32, 111, 112, 101, 110, 101, 100, // other opened - 10, 32, 32, 32, 32, 100, 97, 115, 104, 98, 111, 97, // . dashboa - 114, 100, 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, // rd..
- 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, //
. No - 116, 101, 58, 32, 97, 100, 109, 105, 110, 105, 115, 116, // te: administ - 114, 97, 116, 111, 114, 115, 32, 99, 97, 110, 32, 115, // rators can s - 101, 101, 32, 116, 104, 105, 115, 32, 115, 101, 99, 116, // ee this sect - 105, 111, 110, 32, 97, 110, 100, 32, 99, 97, 110, 32, // ion and can - 99, 104, 97, 110, 103, 101, 32, 100, 101, 118, 105, 99, // change devic - 101, 10, 32, 32, 32, 32, 99, 111, 110, 102, 105, 103, // e. config - 117, 114, 97, 116, 105, 111, 110, 44, 32, 119, 104, 105, // uration, whi - 108, 115, 116, 32, 117, 115, 101, 114, 115, 32, 99, 97, // lst users ca - 110, 110, 111, 116, 46, 10, 32, 32, 60, 47, 100, 105, // nnot.. .
`;. - 125, 59, 10, 10, 99, 111, 110, 115, 116, 32, 76, 111, // };..const Lo + 108, 111, 39, 60, 47, 99, 111, 100, 101, 62, 32, 60, // lo' < + 47, 100, 105, 118, 62, 10, 10, 32, 32, 60, 112, 62, // /div>..

+ 10, 32, 32, 65, 32, 100, 101, 118, 105, 99, 101, 32, // . A device + 99, 97, 110, 32, 115, 101, 110, 100, 32, 110, 111, 116, // can send not + 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, // ifications t + 111, 32, 116, 104, 105, 115, 32, 100, 97, 115, 104, 98, // o this dashb + 111, 97, 114, 100, 32, 97, 116, 32, 97, 110, 121, 116, // oard at anyt + 105, 109, 101, 46, 32, 78, 111, 116, 105, 102, 105, 99, // ime. Notific + 97, 116, 105, 111, 110, 115, 10, 32, 32, 97, 114, 101, // ations. are + 32, 115, 101, 110, 116, 32, 111, 118, 101, 114, 32, 87, // sent over W + 101, 98, 115, 111, 99, 107, 101, 116, 32, 97, 116, 32, // ebsocket at + 85, 82, 73, 32, 60, 99, 111, 100, 101, 62, 99, 117, // URI cu + 114, 108, 32, 108, 111, 99, 97, 108, 104, 111, 115, 116, // rl localhost + 58, 56, 48, 48, 48, 47, 97, 112, 105, 47, 119, 97, // :8000/api/wa + 116, 99, 104, 60, 47, 99, 111, 100, 101, 62, 10, 32, // tch. + 32, 97, 115, 32, 74, 83, 79, 78, 32, 115, 116, 114, // as JSON str + 105, 110, 103, 115, 32, 60, 99, 111, 100, 101, 62, 123, // ings { + 34, 110, 97, 109, 101, 34, 58, 32, 34, 46, 46, 34, // "name": ".." + 44, 32, 34, 100, 97, 116, 97, 34, 58, 32, 46, 46, // , "data": .. + 46, 125, 60, 47, 99, 111, 100, 101, 62, 10, 32, 32, // .}. + 60, 47, 112, 62, 10, 10, 60, 47, 100, 105, 118, 62, //

.. + 96, 59, 10, 10, 99, 111, 110, 115, 116, 32, 76, 111, // `;..const Lo 103, 105, 110, 32, 61, 32, 102, 117, 110, 99, 116, 105, // gin = functi 111, 110, 40, 112, 114, 111, 112, 115, 41, 32, 123, 10, // on(props) {. 32, 32, 99, 111, 110, 115, 116, 32, 91, 117, 115, 101, // const [use @@ -503,402 +348,650 @@ static const unsigned char v2[] = { 32, 117, 115, 101, 114, 50, 58, 112, 97, 115, 115, 50, // user2:pass2 10, 32, 32, 32, 32, 60, 47, 100, 105, 118, 62, 10, // . . 32, 32, 60, 47, 100, 105, 118, 62, 10, 60, 47, 100, // .`;.};..co - 110, 115, 116, 32, 77, 101, 115, 115, 97, 103, 101, 32, // nst Message - 61, 32, 116, 101, 120, 116, 32, 61, 62, 32, 104, 116, // = text => ht - 109, 108, 96, 60, 100, 105, 118, 32, 115, 116, 121, 108, // ml`
${t - 101, 120, 116, 125, 60, 47, 100, 105, 118, 62, 96, 59, // ext}
`; - 10, 10, 99, 111, 110, 115, 116, 32, 77, 101, 115, 115, // ..const Mess - 97, 103, 101, 115, 32, 61, 32, 102, 117, 110, 99, 116, // ages = funct - 105, 111, 110, 40, 112, 114, 111, 112, 115, 41, 32, 123, // ion(props) { - 10, 32, 32, 99, 111, 110, 115, 116, 32, 91, 109, 101, // . const [me - 115, 115, 97, 103, 101, 44, 32, 115, 101, 116, 77, 101, // ssage, setMe - 115, 115, 97, 103, 101, 93, 32, 61, 32, 117, 115, 101, // ssage] = use - 83, 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, 32, // State('');. - 32, 99, 111, 110, 115, 116, 32, 115, 101, 110, 100, 109, // const sendm - 101, 115, 115, 97, 103, 101, 32, 61, 32, 101, 118, 32, // essage = ev - 61, 62, 32, 102, 101, 116, 99, 104, 40, 39, 47, 97, // => fetch('/a - 112, 105, 47, 109, 101, 115, 115, 97, 103, 101, 47, 115, // pi/message/s - 101, 110, 100, 39, 44, 32, 123, 10, 32, 32, 32, 32, // end', {. + 105, 118, 62, 96, 59, 10, 125, 59, 10, 10, 10, 99, // iv>`;.};...c + 111, 110, 115, 116, 32, 67, 111, 110, 102, 105, 103, 117, // onst Configu + 114, 97, 116, 105, 111, 110, 32, 61, 32, 102, 117, 110, // ration = fun + 99, 116, 105, 111, 110, 40, 112, 114, 111, 112, 115, 41, // ction(props) + 32, 123, 10, 32, 32, 99, 111, 110, 115, 116, 32, 91, // {. const [ + 117, 114, 108, 44, 32, 115, 101, 116, 85, 114, 108, 93, // url, setUrl] + 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, 101, 40, // = useState( + 39, 39, 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, // '');. const + 32, 91, 112, 117, 98, 44, 32, 115, 101, 116, 80, 117, // [pub, setPu + 98, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, // b] = useStat + 101, 40, 39, 39, 41, 59, 10, 32, 32, 99, 111, 110, // e('');. con + 115, 116, 32, 91, 115, 117, 98, 44, 32, 115, 101, 116, // st [sub, set + 83, 117, 98, 93, 32, 61, 32, 117, 115, 101, 83, 116, // Sub] = useSt + 97, 116, 101, 40, 39, 39, 41, 59, 10, 10, 32, 32, // ate('');.. + 117, 115, 101, 69, 102, 102, 101, 99, 116, 40, 40, 41, // useEffect(() + 32, 61, 62, 32, 123, 10, 32, 32, 32, 32, 99, 111, // => {. co + 110, 115, 116, 32, 105, 100, 32, 61, 32, 80, 117, 98, // nst id = Pub + 83, 117, 98, 46, 115, 117, 98, 115, 99, 114, 105, 98, // Sub.subscrib + 101, 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, 109, // e(function(m + 115, 103, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, // sg) {. + 105, 102, 32, 40, 109, 115, 103, 46, 110, 97, 109, 101, // if (msg.name + 32, 61, 61, 32, 39, 110, 101, 119, 99, 111, 110, 102, // == 'newconf + 105, 103, 39, 41, 32, 123, 10, 32, 32, 32, 32, 32, // ig') {. + 32, 32, 32, 115, 101, 116, 85, 114, 108, 40, 109, 115, // setUrl(ms + 103, 46, 100, 97, 116, 97, 46, 117, 114, 108, 41, 59, // g.data.url); + 10, 32, 32, 32, 32, 32, 32, 32, 32, 115, 101, 116, // . set + 80, 117, 98, 40, 109, 115, 103, 46, 100, 97, 116, 97, // Pub(msg.data + 46, 112, 117, 98, 41, 59, 10, 32, 32, 32, 32, 32, // .pub);. + 32, 32, 32, 115, 101, 116, 83, 117, 98, 40, 109, 115, // setSub(ms + 103, 46, 100, 97, 116, 97, 46, 115, 117, 98, 41, 59, // g.data.sub); + 10, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, // . }. + 32, 125, 41, 59, 10, 32, 32, 32, 32, 114, 101, 116, // });. ret + 117, 114, 110, 32, 80, 117, 98, 83, 117, 98, 46, 117, // urn PubSub.u + 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, 40, 105, // nsubscribe(i + 100, 41, 59, 10, 32, 32, 125, 44, 32, 91, 93, 41, // d);. }, []) + 59, 10, 10, 32, 32, 99, 111, 110, 115, 116, 32, 117, // ;.. const u + 112, 100, 97, 116, 101, 32, 61, 32, 40, 110, 97, 109, // pdate = (nam + 101, 44, 32, 118, 97, 108, 41, 32, 61, 62, 32, 102, // e, val) => f + 101, 116, 99, 104, 40, 39, 47, 97, 112, 105, 47, 99, // etch('/api/c + 111, 110, 102, 105, 103, 47, 115, 101, 116, 39, 44, 32, // onfig/set', + 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // {. 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // - 32, 32, 109, 101, 116, 104, 111, 100, 58, 32, 39, 112, // method: 'p - 111, 115, 116, 39, 44, 10, 32, 32, 32, 32, 32, 32, // ost',. + 109, 101, 116, 104, 111, 100, 58, 32, 39, 112, 111, 115, // method: 'pos + 116, 39, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, // t',. 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // - 98, 111, 100, 121, 58, 32, 96, 109, 101, 115, 115, 97, // body: `messa - 103, 101, 61, 36, 123, 101, 110, 99, 111, 100, 101, 85, // ge=${encodeU - 82, 73, 67, 111, 109, 112, 111, 110, 101, 110, 116, 40, // RIComponent( - 109, 101, 115, 115, 97, 103, 101, 41, 125, 96, 10, 32, // message)}`. + 32, 32, 98, 111, 100, 121, 58, 32, 96, 36, 123, 110, // body: `${n + 97, 109, 101, 125, 61, 36, 123, 101, 110, 99, 111, 100, // ame}=${encod + 101, 85, 82, 73, 67, 111, 109, 112, 111, 110, 101, 110, // eURIComponen + 116, 40, 118, 97, 108, 41, 125, 96, 10, 32, 32, 32, // t(val)}`. 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // - 32, 32, 32, 125, 41, 46, 116, 104, 101, 110, 40, 114, // }).then(r - 32, 61, 62, 32, 115, 101, 116, 77, 101, 115, 115, 97, // => setMessa - 103, 101, 40, 39, 39, 41, 41, 59, 10, 10, 32, 32, // ge(''));.. - 99, 111, 110, 115, 116, 32, 109, 101, 115, 115, 97, 103, // const messag - 101, 115, 32, 61, 32, 112, 114, 111, 112, 115, 46, 109, // es = props.m - 101, 115, 115, 97, 103, 101, 115, 46, 109, 97, 112, 40, // essages.map( - 10, 32, 32, 32, 32, 32, 32, 116, 101, 120, 116, 32, // . text - 61, 62, 32, 104, 116, 109, 108, 96, 60, 100, 105, 118, // => html`
${text}`);. ret - 117, 114, 110, 32, 104, 116, 109, 108, 96, 10, 60, 100, // urn html`..

MQT - 84, 32, 109, 101, 115, 115, 97, 103, 101, 115, 60, 47, // T messages.
. - 32, 32, 36, 123, 109, 101, 115, 115, 97, 103, 101, 115, // ${messages - 125, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, // }.
. - 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, //
. - 32, 32, 60, 115, 112, 97, 110, 32, 99, 108, 97, 115, // Publish - 32, 109, 101, 115, 115, 97, 103, 101, 58, 60, 47, 115, // message:. - 32, 115, 101, 116, 77, 101, 115, 115, 97, 103, 101, 40, // setMessage( - 101, 118, 46, 116, 97, 114, 103, 101, 116, 46, 118, 97, // ev.target.va - 108, 117, 101, 41, 125, 32, 47, 62, 10, 32, 32, 60, // lue)} />. < - 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, 118, // /div>.
. Messag - 101, 32, 103, 101, 116, 115, 32, 112, 97, 115, 115, 101, // e gets passe - 100, 32, 116, 111, 32, 116, 104, 101, 32, 100, 101, 118, // d to the dev - 105, 99, 101, 32, 118, 105, 97, 32, 82, 69, 83, 84, // ice via REST - 46, 32, 84, 104, 101, 110, 32, 97, 32, 100, 101, 118, // . Then a dev - 105, 99, 101, 32, 115, 101, 110, 100, 115, 32, 105, 116, // ice sends it - 32, 116, 111, 10, 32, 32, 32, 32, 116, 104, 101, 32, // to. the - 77, 81, 84, 84, 32, 115, 101, 114, 118, 101, 114, 32, // MQTT server - 111, 118, 101, 114, 32, 77, 81, 84, 84, 46, 32, 65, // over MQTT. A - 108, 108, 32, 77, 81, 84, 84, 32, 109, 101, 115, 115, // ll MQTT mess - 97, 103, 101, 115, 32, 111, 110, 32, 97, 32, 115, 117, // ages on a su - 98, 115, 99, 114, 105, 98, 101, 100, 32, 116, 111, 112, // bscribed top - 105, 99, 10, 32, 32, 32, 32, 114, 101, 99, 101, 105, // ic. recei - 118, 101, 100, 32, 98, 121, 32, 97, 32, 100, 101, 118, // ved by a dev - 105, 99, 101, 44, 32, 97, 114, 101, 32, 112, 114, 111, // ice, are pro - 112, 97, 103, 97, 116, 101, 100, 32, 116, 111, 32, 116, // pagated to t - 104, 105, 115, 32, 100, 97, 115, 104, 98, 111, 97, 114, // his dashboar - 100, 32, 118, 105, 97, 32, 116, 104, 101, 10, 32, 32, // d via the. - 32, 32, 47, 97, 112, 105, 47, 119, 97, 116, 99, 104, // /api/watch - 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 60, // ..
.< - 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, 10, 10, // /div>`;.};.. - 47, 47, 32, 69, 120, 112, 101, 99, 116, 101, 100, 32, // // Expected - 97, 114, 103, 117, 109, 101, 110, 116, 115, 58, 10, 47, // arguments:./ - 47, 32, 100, 97, 116, 97, 58, 32, 116, 105, 109, 101, // / data: time - 115, 101, 114, 105, 101, 115, 44, 32, 101, 46, 103, 46, // series, e.g. - 32, 91, 32, 91, 49, 54, 53, 52, 51, 54, 49, 51, // [ [16543613 - 53, 50, 44, 32, 49, 57, 93, 44, 32, 91, 49, 54, // 52, 19], [16 - 53, 52, 51, 54, 49, 51, 53, 51, 44, 32, 49, 56, // 54361353, 18 - 93, 44, 32, 46, 46, 46, 32, 93, 10, 47, 47, 32, // ], ... ].// - 119, 105, 100, 116, 104, 44, 32, 104, 101, 105, 103, 104, // width, heigh - 116, 44, 32, 121, 116, 105, 99, 107, 115, 44, 32, 120, // t, yticks, x - 116, 105, 99, 107, 115, 44, 32, 121, 109, 105, 110, 44, // ticks, ymin, - 32, 121, 109, 97, 120, 44, 32, 120, 109, 105, 110, 44, // ymax, xmin, - 32, 120, 109, 97, 120, 10, 99, 111, 110, 115, 116, 32, // xmax.const - 83, 86, 71, 32, 61, 32, 102, 117, 110, 99, 116, 105, // SVG = functi - 111, 110, 40, 112, 114, 111, 112, 115, 41, 32, 123, 10, // on(props) {. - 32, 32, 47, 47, 32, 32, 32, 32, 32, 32, 32, 32, // // - 32, 32, 32, 32, 119, 10, 32, 32, 47, 47, 32, 32, // w. // - 32, 43, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, // +---------- - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 43, // -----------+ - 10, 32, 32, 47, 47, 32, 32, 32, 124, 32, 32, 32, // . // | - 32, 32, 32, 32, 32, 104, 49, 32, 32, 32, 32, 32, // h1 - 32, 32, 32, 32, 32, 32, 124, 10, 32, 32, 47, 47, // |. // - 32, 32, 32, 124, 32, 32, 32, 32, 43, 45, 45, 45, // | +--- - 45, 45, 45, 45, 45, 45, 45, 45, 43, 32, 32, 32, // --------+ - 32, 124, 10, 32, 32, 47, 47, 32, 32, 32, 124, 32, // |. // | - 32, 32, 32, 124, 32, 32, 32, 32, 32, 32, 32, 32, // | - 32, 32, 32, 124, 32, 32, 32, 32, 124, 32, 32, 104, // | | h - 10, 32, 32, 47, 47, 32, 32, 32, 124, 32, 119, 49, // . // | w1 - 32, 124, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // | - 32, 124, 32, 119, 50, 32, 124, 10, 32, 32, 47, 47, // | w2 |. // - 32, 32, 32, 124, 32, 32, 32, 32, 43, 45, 45, 45, // | +--- - 45, 45, 45, 45, 45, 45, 45, 45, 43, 32, 32, 32, // --------+ - 32, 124, 10, 32, 32, 47, 47, 32, 32, 32, 124, 32, // |. // | - 32, 32, 32, 32, 32, 32, 32, 32, 104, 50, 32, 32, // h2 - 32, 32, 32, 32, 32, 32, 32, 32, 124, 10, 32, 32, // |. - 47, 47, 32, 32, 32, 43, 45, 45, 45, 45, 45, 45, // // +------ - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, // ------------ - 45, 45, 45, 43, 10, 32, 32, 47, 47, 10, 32, 32, // ---+. //. - 108, 101, 116, 32, 119, 32, 61, 32, 112, 114, 111, 112, // let w = prop - 115, 46, 119, 105, 100, 116, 104, 44, 32, 104, 32, 61, // s.width, h = - 32, 112, 114, 111, 112, 115, 46, 104, 101, 105, 103, 104, // props.heigh - 116, 44, 32, 119, 49, 32, 61, 32, 51, 48, 44, 32, // t, w1 = 30, - 119, 50, 32, 61, 32, 48, 44, 32, 104, 49, 32, 61, // w2 = 0, h1 = - 32, 56, 44, 32, 104, 50, 32, 61, 32, 49, 56, 59, // 8, h2 = 18; - 10, 32, 32, 108, 101, 116, 32, 121, 116, 105, 99, 107, // . let ytick - 115, 32, 61, 32, 112, 114, 111, 112, 115, 46, 121, 116, // s = props.yt - 105, 99, 107, 115, 32, 124, 124, 32, 52, 44, 32, 120, // icks || 4, x - 116, 105, 99, 107, 115, 32, 61, 32, 112, 114, 111, 112, // ticks = prop - 115, 46, 120, 116, 105, 99, 107, 115, 32, 124, 124, 32, // s.xticks || - 53, 59, 10, 32, 32, 108, 101, 116, 32, 100, 97, 116, // 5;. let dat - 97, 32, 61, 32, 112, 114, 111, 112, 115, 46, 100, 97, // a = props.da - 116, 97, 32, 124, 124, 32, 91, 93, 59, 10, 32, 32, // ta || [];. - 108, 101, 116, 32, 121, 109, 105, 110, 32, 61, 32, 112, // let ymin = p - 114, 111, 112, 115, 46, 121, 109, 105, 110, 32, 124, 124, // rops.ymin || - 32, 48, 59, 10, 32, 32, 108, 101, 116, 32, 121, 109, // 0;. let ym - 97, 120, 32, 61, 32, 112, 114, 111, 112, 115, 46, 121, // ax = props.y - 109, 97, 120, 32, 124, 124, 32, 77, 97, 116, 104, 46, // max || Math. - 109, 97, 120, 46, 97, 112, 112, 108, 121, 40, 110, 117, // max.apply(nu - 108, 108, 44, 32, 100, 97, 116, 97, 46, 109, 97, 112, // ll, data.map - 40, 112, 32, 61, 62, 32, 112, 91, 49, 93, 41, 41, // (p => p[1])) - 59, 10, 32, 32, 108, 101, 116, 32, 120, 109, 105, 110, // ;. let xmin - 32, 61, 32, 112, 114, 111, 112, 115, 46, 120, 109, 105, // = props.xmi - 110, 32, 124, 124, 32, 77, 97, 116, 104, 46, 109, 105, // n || Math.mi - 110, 46, 97, 112, 112, 108, 121, 40, 110, 117, 108, 108, // n.apply(null - 44, 32, 100, 97, 116, 97, 46, 109, 97, 112, 40, 112, // , data.map(p - 32, 61, 62, 32, 112, 91, 48, 93, 41, 41, 59, 10, // => p[0]));. - 32, 32, 108, 101, 116, 32, 120, 109, 97, 120, 32, 61, // let xmax = - 32, 112, 114, 111, 112, 115, 46, 120, 109, 97, 120, 32, // props.xmax - 124, 124, 32, 77, 97, 116, 104, 46, 109, 97, 120, 46, // || Math.max. - 97, 112, 112, 108, 121, 40, 110, 117, 108, 108, 44, 32, // apply(null, - 100, 97, 116, 97, 46, 109, 97, 112, 40, 112, 32, 61, // data.map(p = - 62, 32, 112, 91, 48, 93, 41, 41, 59, 10, 10, 32, // > p[0]));.. - 32, 47, 47, 32, 89, 45, 97, 120, 105, 115, 32, 116, // // Y-axis t - 105, 99, 107, 32, 108, 105, 110, 101, 115, 32, 97, 110, // ick lines an - 100, 32, 108, 97, 98, 101, 108, 115, 10, 32, 32, 108, // d labels. l - 101, 116, 32, 121, 116, 97, 32, 61, 32, 40, 110, 101, // et yta = (ne - 119, 32, 65, 114, 114, 97, 121, 40, 121, 116, 105, 99, // w Array(ytic - 107, 115, 32, 43, 32, 49, 41, 41, 46, 102, 105, 108, // ks + 1)).fil - 108, 40, 48, 41, 46, 109, 97, 112, 40, 40, 95, 44, // l(0).map((_, - 32, 105, 41, 32, 61, 62, 32, 105, 41, 59, 32, 32, // i) => i); - 47, 47, 32, 105, 110, 100, 105, 99, 101, 115, 10, 32, // // indices. - 32, 108, 101, 116, 32, 121, 116, 105, 32, 61, 32, 105, // let yti = i - 32, 61, 62, 32, 104, 32, 45, 32, 104, 50, 32, 45, // => h - h2 - - 32, 40, 104, 32, 45, 32, 104, 49, 32, 45, 32, 104, // (h - h1 - h - 50, 41, 32, 42, 32, 105, 32, 47, 32, 121, 116, 105, // 2) * i / yti - 99, 107, 115, 59, 32, 32, 32, 32, 32, 32, 32, 32, // cks; - 32, 32, 47, 47, 32, 105, 110, 100, 101, 120, 39, 115, // // index's - 32, 89, 10, 32, 32, 108, 101, 116, 32, 121, 116, 118, // Y. let ytv - 32, 61, 32, 105, 32, 61, 62, 32, 40, 121, 109, 97, // = i => (yma - 120, 32, 45, 32, 121, 109, 105, 110, 41, 32, 42, 32, // x - ymin) * - 105, 32, 47, 32, 121, 116, 105, 99, 107, 115, 59, 10, // i / yticks;. - 32, 32, 108, 101, 116, 32, 121, 116, 108, 32, 61, 32, // let ytl = - 121, 32, 61, 62, 32, 104, 116, 109, 108, 96, 60, 108, // y => html``;. let - 121, 116, 116, 32, 61, 32, 40, 121, 44, 32, 118, 41, // ytt = (y, v) - 32, 61, 62, 32, 104, 116, 109, 108, 96, 60, 116, 101, // => html`${v} - 60, 47, 116, 101, 120, 116, 62, 96, 59, 10, 10, 32, // `;.. - 32, 47, 47, 32, 88, 45, 97, 120, 105, 115, 32, 116, // // X-axis t - 105, 99, 107, 32, 108, 105, 110, 101, 115, 32, 97, 110, // ick lines an - 100, 32, 108, 97, 98, 101, 108, 115, 10, 32, 32, 108, // d labels. l - 101, 116, 32, 100, 97, 116, 101, 102, 109, 116, 32, 61, // et datefmt = - 32, 117, 110, 105, 120, 32, 61, 62, 32, 40, 110, 101, // unix => (ne - 119, 32, 68, 97, 116, 101, 40, 117, 110, 105, 120, 32, // w Date(unix - 42, 32, 49, 48, 48, 48, 41, 41, 46, 116, 111, 73, // * 1000)).toI - 83, 79, 83, 116, 114, 105, 110, 103, 40, 41, 46, 115, // SOString().s - 117, 98, 115, 116, 114, 40, 49, 52, 44, 32, 53, 41, // ubstr(14, 5) - 59, 10, 32, 32, 108, 101, 116, 32, 120, 116, 97, 32, // ;. let xta - 61, 32, 40, 110, 101, 119, 32, 65, 114, 114, 97, 121, // = (new Array - 40, 120, 116, 105, 99, 107, 115, 32, 43, 32, 49, 41, // (xticks + 1) - 41, 46, 102, 105, 108, 108, 40, 48, 41, 46, 109, 97, // ).fill(0).ma - 112, 40, 40, 95, 44, 32, 105, 41, 32, 61, 62, 32, // p((_, i) => - 105, 41, 59, 32, 32, 47, 47, 32, 105, 110, 100, 105, // i); // indi - 99, 101, 115, 10, 32, 32, 108, 101, 116, 32, 120, 116, // ces. let xt - 105, 32, 61, 32, 105, 32, 61, 62, 32, 119, 49, 32, // i = i => w1 - 43, 32, 40, 119, 32, 45, 32, 119, 49, 32, 45, 32, // + (w - w1 - - 119, 50, 41, 32, 42, 32, 105, 32, 47, 32, 120, 116, // w2) * i / xt - 105, 99, 107, 115, 59, 32, 32, 32, 32, 32, 32, 32, // icks; - 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, 105, 110, // // in - 100, 101, 120, 39, 115, 32, 88, 10, 32, 32, 108, 101, // dex's X. le - 116, 32, 120, 116, 118, 32, 61, 32, 105, 32, 61, 62, // t xtv = i => - 32, 100, 97, 116, 101, 102, 109, 116, 40, 120, 109, 105, // datefmt(xmi - 110, 32, 43, 32, 40, 120, 109, 97, 120, 32, 45, 32, // n + (xmax - - 120, 109, 105, 110, 41, 32, 42, 32, 105, 32, 47, 32, // xmin) * i / - 120, 116, 105, 99, 107, 115, 41, 59, 10, 32, 32, 108, // xticks);. l - 101, 116, 32, 120, 116, 108, 32, 61, 32, 120, 32, 61, // et xtl = x = - 62, 32, 104, 116, 109, 108, 96, 60, 112, 97, 116, 104, // > html``;. let xt - 116, 32, 61, 32, 40, 120, 44, 32, 118, 41, 32, 61, // t = (x, v) = - 62, 10, 32, 32, 32, 32, 32, 32, 104, 116, 109, 108, // >. html - 96, 60, 116, 101, 120, 116, 32, 120, 61, 36, 123, 120, // `${v} - 60, 47, 116, 101, 120, 116, 62, 96, 59, 10, 10, 32, // `;.. - 32, 47, 47, 32, 84, 114, 97, 110, 115, 102, 111, 114, // // Transfor - 109, 32, 100, 97, 116, 97, 32, 112, 111, 105, 110, 116, // m data point - 115, 32, 97, 114, 114, 97, 121, 32, 105, 110, 116, 111, // s array into - 32, 99, 111, 111, 114, 100, 105, 110, 97, 116, 101, 10, // coordinate. - 32, 32, 108, 101, 116, 32, 100, 120, 32, 61, 32, 118, // let dx = v - 32, 61, 62, 32, 119, 49, 32, 43, 32, 40, 118, 32, // => w1 + (v - 45, 32, 120, 109, 105, 110, 41, 32, 47, 32, 40, 40, // - xmin) / (( - 120, 109, 97, 120, 32, 45, 32, 120, 109, 105, 110, 41, // xmax - xmin) - 32, 124, 124, 32, 49, 41, 32, 42, 32, 40, 119, 32, // || 1) * (w - 45, 32, 119, 49, 32, 45, 32, 119, 50, 41, 59, 10, // - w1 - w2);. - 32, 32, 108, 101, 116, 32, 100, 121, 32, 61, 32, 118, // let dy = v - 32, 61, 62, 32, 104, 32, 45, 32, 104, 50, 32, 45, // => h - h2 - - 32, 40, 118, 32, 45, 32, 121, 109, 105, 110, 41, 32, // (v - ymin) - 47, 32, 40, 40, 121, 109, 97, 120, 32, 45, 32, 121, // / ((ymax - y - 109, 105, 110, 41, 32, 124, 124, 32, 49, 41, 32, 42, // min) || 1) * - 32, 40, 104, 32, 45, 32, 104, 49, 32, 45, 32, 104, // (h - h1 - h - 50, 41, 59, 10, 32, 32, 108, 101, 116, 32, 100, 100, // 2);. let dd - 32, 61, 32, 100, 97, 116, 97, 46, 109, 97, 112, 40, // = data.map( - 112, 32, 61, 62, 32, 91, 77, 97, 116, 104, 46, 114, // p => [Math.r - 111, 117, 110, 100, 40, 100, 120, 40, 112, 91, 48, 93, // ound(dx(p[0] - 41, 41, 44, 32, 77, 97, 116, 104, 46, 114, 111, 117, // )), Math.rou - 110, 100, 40, 100, 121, 40, 112, 91, 49, 93, 41, 41, // nd(dy(p[1])) - 93, 41, 59, 10, 32, 32, 108, 101, 116, 32, 100, 100, // ]);. let dd - 108, 32, 61, 32, 100, 100, 46, 108, 101, 110, 103, 116, // l = dd.lengt - 104, 59, 10, 32, 32, 47, 47, 32, 65, 110, 100, 32, // h;. // And - 112, 108, 111, 116, 32, 116, 104, 101, 32, 100, 97, 116, // plot the dat - 97, 32, 97, 115, 32, 60, 112, 97, 116, 104, 62, 32, // a as - 101, 108, 101, 109, 101, 110, 116, 10, 32, 32, 108, 101, // element. le - 116, 32, 98, 101, 103, 105, 110, 48, 32, 61, 32, 100, // t begin0 = d - 100, 108, 32, 63, 32, 96, 77, 32, 36, 123, 100, 100, // dl ? `M ${dd - 91, 48, 93, 91, 48, 93, 125, 44, 36, 123, 100, 100, // [0][0]},${dd - 91, 48, 93, 91, 49, 93, 125, 96, 32, 58, 32, 96, // [0][1]}` : ` - 77, 32, 48, 44, 48, 96, 59, 10, 32, 32, 108, 101, // M 0,0`;. le - 116, 32, 98, 101, 103, 105, 110, 32, 61, 32, 96, 77, // t begin = `M - 32, 36, 123, 119, 49, 125, 44, 36, 123, 104, 32, 45, // ${w1},${h - - 32, 104, 50, 125, 96, 59, 32, 32, 47, 47, 32, 73, // h2}`; // I - 110, 105, 116, 105, 97, 108, 32, 112, 111, 105, 110, 116, // nitial point - 10, 32, 32, 108, 101, 116, 32, 101, 110, 100, 32, 61, // . let end = - 32, 100, 100, 108, 32, 63, 32, 96, 76, 32, 36, 123, // ddl ? `L ${ - 100, 100, 91, 100, 100, 108, 32, 45, 32, 49, 93, 91, // dd[ddl - 1][ - 48, 93, 125, 44, 36, 123, 104, 32, 45, 32, 104, 50, // 0]},${h - h2 - 125, 96, 32, 58, 32, 96, 76, 32, 36, 123, 119, 49, // }` : `L ${w1 - 125, 44, 36, 123, 104, 32, 45, 32, 104, 50, 125, 96, // },${h - h2}` - 59, 10, 32, 32, 108, 101, 116, 32, 115, 101, 114, 105, // ;. let seri - 101, 115, 32, 61, 32, 100, 100, 108, 32, 63, 32, 100, // es = ddl ? d - 100, 46, 109, 97, 112, 40, 112, 32, 61, 62, 32, 96, // d.map(p => ` - 76, 32, 36, 123, 112, 91, 48, 93, 125, 32, 36, 123, // L ${p[0]} ${ - 112, 91, 49, 93, 125, 96, 41, 32, 58, 32, 91, 93, // p[1]}`) : [] - 59, 10, 10, 32, 32, 47, 47, 32, 99, 111, 110, 115, // ;.. // cons - 111, 108, 101, 46, 108, 111, 103, 40, 120, 109, 97, 120, // ole.log(xmax - 41, 59, 10, 10, 32, 32, 114, 101, 116, 117, 114, 110, // );.. return - 32, 104, 116, 109, 108, 96, 10, 60, 115, 118, 103, 32, // html`. - 10, 32, 32, 60, 115, 116, 121, 108, 101, 62, 10, 32, // . - 96, 59, 10, 125, 59, 10, 10, 10, 99, 111, 110, 115, // `;.};...cons - 116, 32, 67, 104, 97, 114, 116, 32, 61, 32, 102, 117, // t Chart = fu - 110, 99, 116, 105, 111, 110, 40, 112, 114, 111, 112, 115, // nction(props - 41, 32, 123, 10, 32, 32, 108, 101, 116, 32, 120, 109, // ) {. let xm - 97, 120, 32, 61, 32, 48, 44, 32, 109, 105, 115, 115, // ax = 0, miss - 105, 110, 103, 32, 61, 32, 77, 97, 120, 77, 101, 116, // ing = MaxMet - 114, 105, 99, 115, 68, 97, 116, 97, 80, 111, 105, 110, // ricsDataPoin - 116, 115, 32, 45, 32, 112, 114, 111, 112, 115, 46, 109, // ts - props.m - 101, 116, 114, 105, 99, 115, 46, 108, 101, 110, 103, 116, // etrics.lengt - 104, 59, 10, 32, 32, 105, 102, 32, 40, 109, 105, 115, // h;. if (mis - 115, 105, 110, 103, 32, 62, 32, 48, 41, 32, 120, 109, // sing > 0) xm - 97, 120, 32, 61, 32, 77, 97, 116, 104, 46, 114, 111, // ax = Math.ro - 117, 110, 100, 40, 68, 97, 116, 101, 46, 110, 111, 119, // und(Date.now - 40, 41, 32, 47, 32, 49, 48, 48, 48, 41, 32, 43, // () / 1000) + - 32, 109, 105, 115, 115, 105, 110, 103, 59, 10, 32, 32, // missing;. + 32, 32, 32, 32, 32, 125, 41, 46, 99, 97, 116, 99, // }).catc + 104, 40, 101, 114, 114, 32, 61, 62, 32, 101, 114, 114, // h(err => err + 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, 117, // );. const u + 112, 100, 97, 116, 101, 117, 114, 108, 32, 61, 32, 101, // pdateurl = e + 118, 32, 61, 62, 32, 117, 112, 100, 97, 116, 101, 40, // v => update( + 39, 117, 114, 108, 39, 44, 32, 117, 114, 108, 41, 59, // 'url', url); + 10, 32, 32, 99, 111, 110, 115, 116, 32, 117, 112, 100, // . const upd + 97, 116, 101, 112, 117, 98, 32, 61, 32, 101, 118, 32, // atepub = ev + 61, 62, 32, 117, 112, 100, 97, 116, 101, 40, 39, 112, // => update('p + 117, 98, 39, 44, 32, 112, 117, 98, 41, 59, 10, 32, // ub', pub);. + 32, 99, 111, 110, 115, 116, 32, 117, 112, 100, 97, 116, // const updat + 101, 115, 117, 98, 32, 61, 32, 101, 118, 32, 61, 62, // esub = ev => + 32, 117, 112, 100, 97, 116, 101, 40, 39, 115, 117, 98, // update('sub + 39, 44, 32, 115, 117, 98, 41, 59, 10, 10, 32, 32, // ', sub);.. 114, 101, 116, 117, 114, 110, 32, 104, 116, 109, 108, 96, // return html` 10, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, // .
. Dat - 97, 32, 67, 104, 97, 114, 116, 60, 47, 104, 51, 62, // a Chart

- 10, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, // .
. - 32, 84, 104, 105, 115, 32, 99, 104, 97, 114, 116, 32, // This chart - 112, 108, 111, 116, 115, 32, 108, 105, 118, 101, 32, 115, // plots live s - 101, 110, 115, 111, 114, 32, 100, 97, 116, 97, 44, 32, // ensor data, - 115, 101, 110, 116, 32, 98, 121, 32, 97, 32, 100, 101, // sent by a de - 118, 105, 99, 101, 32, 118, 105, 97, 32, 47, 97, 112, // vice via /ap - 105, 47, 119, 97, 116, 99, 104, 46, 10, 32, 32, 60, // i/watch.. < - 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, 118, // /div>.
+ 10, 32, 32, 32, 32, 68, 101, 118, 105, 99, 101, 32, // . Device + 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, // Configuratio + 110, 60, 47, 104, 51, 62, 10, 32, 32, 60, 100, 105, // n

. . < + 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, // span class=" + 97, 100, 100, 111, 110, 32, 110, 111, 119, 114, 97, 112, // addon nowrap + 34, 62, 77, 81, 84, 84, 32, 115, 101, 114, 118, 101, // ">MQTT serve + 114, 58, 60, 47, 115, 112, 97, 110, 62, 10, 32, 32, // r:. + 32, 32, 60, 105, 110, 112, 117, 116, 32, 116, 121, 112, // setUrl + 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, 46, 118, // (ev.target.v + 97, 108, 117, 101, 41, 125, 32, 47, 62, 10, 32, 32, // alue)} />. + 32, 32, 60, 98, 117, 116, 116, 111, 110, 32, 99, 108, // + 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, // . . + 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, //
. De + 118, 105, 99, 101, 32, 107, 101, 101, 112, 115, 32, 97, // vice keeps a + 32, 112, 101, 114, 115, 105, 115, 116, 101, 110, 116, 32, // persistent + 99, 111, 110, 110, 101, 99, 116, 105, 111, 110, 32, 116, // connection t + 111, 32, 116, 104, 101, 32, 99, 111, 110, 102, 105, 103, // o the config + 117, 114, 101, 100, 32, 77, 81, 84, 84, 32, 115, 101, // ured MQTT se + 114, 118, 101, 114, 46, 10, 32, 32, 32, 32, 67, 104, // rver.. Ch + 97, 110, 103, 101, 115, 32, 116, 111, 32, 116, 104, 105, // anges to thi + 115, 32, 99, 111, 110, 102, 105, 103, 117, 114, 97, 116, // s configurat + 105, 111, 110, 32, 97, 114, 101, 32, 112, 114, 111, 112, // ion are prop + 97, 103, 97, 116, 101, 100, 32, 116, 111, 32, 97, 108, // agated to al + 108, 32, 100, 97, 115, 104, 98, 111, 97, 114, 100, 115, // l dashboards + 58, 32, 116, 114, 121, 10, 32, 32, 32, 32, 99, 104, // : try. ch + 97, 110, 103, 105, 110, 103, 32, 116, 104, 101, 109, 32, // anging them + 105, 110, 32, 116, 104, 105, 115, 32, 100, 97, 115, 104, // in this dash + 98, 111, 97, 114, 100, 32, 97, 110, 100, 32, 111, 98, // board and ob + 115, 101, 114, 118, 101, 32, 99, 104, 97, 110, 103, 101, // serve change + 115, 32, 105, 110, 32, 116, 104, 101, 32, 111, 116, 104, // s in the oth + 101, 114, 32, 111, 112, 101, 110, 101, 100, 10, 32, 32, // er opened. + 32, 32, 100, 97, 115, 104, 98, 111, 97, 114, 100, 46, // dashboard. + 10, 32, 32, 60, 47, 100, 105, 118, 62, 60, 100, 105, // .
. Note: + 32, 97, 100, 109, 105, 110, 105, 115, 116, 114, 97, 116, // administrat + 111, 114, 115, 32, 99, 97, 110, 32, 115, 101, 101, 32, // ors can see + 116, 104, 105, 115, 32, 115, 101, 99, 116, 105, 111, 110, // this section + 32, 97, 110, 100, 32, 99, 97, 110, 32, 99, 104, 97, // and can cha + 110, 103, 101, 32, 100, 101, 118, 105, 99, 101, 10, 32, // nge device. + 32, 32, 32, 99, 111, 110, 102, 105, 103, 117, 114, 97, // configura + 116, 105, 111, 110, 44, 32, 119, 104, 105, 108, 115, 116, // tion, whilst + 32, 117, 115, 101, 114, 115, 32, 99, 97, 110, 110, 111, // users canno + 116, 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, // t.. . + 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, 10, // `;.};. + 10, 10, 99, 111, 110, 115, 116, 32, 77, 101, 115, 115, // ..const Mess + 97, 103, 101, 32, 61, 32, 109, 32, 61, 62, 32, 104, // age = m => h + 116, 109, 108, 96, 60, 100, 105, 118, 32, 115, 116, 121, // tml`
. + 32, 60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, // top + 105, 99, 58, 32, 36, 123, 109, 46, 109, 101, 115, 115, // ic: ${m.mess + 97, 103, 101, 46, 116, 111, 112, 105, 99, 125, 32, 60, // age.topic} < + 47, 115, 112, 97, 110, 62, 10, 32, 32, 60, 115, 112, // /span>. data: ${ + 109, 46, 109, 101, 115, 115, 97, 103, 101, 46, 100, 97, // m.message.da + 116, 97, 125, 60, 47, 115, 112, 97, 110, 62, 10, 60, // ta}.< + 47, 100, 105, 118, 62, 96, 59, 10, 10, 99, 111, 110, // /div>`;..con + 115, 116, 32, 77, 101, 115, 115, 97, 103, 101, 115, 32, // st Messages + 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 112, // = function(p + 114, 111, 112, 115, 41, 32, 123, 10, 32, 32, 99, 111, // rops) {. co + 110, 115, 116, 32, 91, 109, 101, 115, 115, 97, 103, 101, // nst [message + 115, 44, 32, 115, 101, 116, 77, 101, 115, 115, 97, 103, // s, setMessag + 101, 115, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, // es] = useSta + 116, 101, 40, 91, 93, 41, 59, 10, 32, 32, 99, 111, // te([]);. co + 110, 115, 116, 32, 91, 99, 102, 103, 44, 32, 115, 101, // nst [cfg, se + 116, 67, 102, 103, 93, 32, 61, 32, 117, 115, 101, 83, // tCfg] = useS + 116, 97, 116, 101, 40, 123, 125, 41, 59, 10, 32, 32, // tate({});. + 99, 111, 110, 115, 116, 32, 91, 116, 120, 116, 44, 32, // const [txt, + 115, 101, 116, 84, 120, 116, 93, 32, 61, 32, 117, 115, // setTxt] = us + 101, 83, 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, // eState('');. + 10, 32, 32, 117, 115, 101, 69, 102, 102, 101, 99, 116, // . useEffect + 40, 40, 41, 32, 61, 62, 32, 123, 10, 32, 32, 32, // (() => {. + 32, 99, 111, 110, 115, 116, 32, 105, 100, 32, 61, 32, // const id = + 80, 117, 98, 83, 117, 98, 46, 115, 117, 98, 115, 99, // PubSub.subsc + 114, 105, 98, 101, 40, 102, 117, 110, 99, 116, 105, 111, // ribe(functio + 110, 40, 109, 115, 103, 41, 32, 123, 10, 32, 32, 32, // n(msg) {. + 32, 32, 32, 105, 102, 32, 40, 109, 115, 103, 46, 110, // if (msg.n + 97, 109, 101, 32, 61, 61, 32, 39, 110, 101, 119, 99, // ame == 'newc + 111, 110, 102, 105, 103, 39, 41, 32, 115, 101, 116, 67, // onfig') setC + 102, 103, 40, 120, 32, 61, 62, 32, 109, 115, 103, 46, // fg(x => msg. + 100, 97, 116, 97, 41, 59, 10, 32, 32, 32, 32, 32, // data);. + 32, 105, 102, 32, 40, 109, 115, 103, 46, 110, 97, 109, // if (msg.nam + 101, 32, 61, 61, 32, 39, 109, 101, 115, 115, 97, 103, // e == 'messag + 101, 39, 41, 32, 115, 101, 116, 77, 101, 115, 115, 97, // e') setMessa + 103, 101, 115, 40, 120, 32, 61, 62, 32, 120, 46, 99, // ges(x => x.c + 111, 110, 99, 97, 116, 40, 91, 109, 115, 103, 46, 100, // oncat([msg.d + 97, 116, 97, 93, 41, 41, 59, 10, 32, 32, 32, 32, // ata]));. + 125, 41, 59, 10, 32, 32, 32, 32, 114, 101, 116, 117, // });. retu + 114, 110, 32, 80, 117, 98, 83, 117, 98, 46, 117, 110, // rn PubSub.un + 115, 117, 98, 115, 99, 114, 105, 98, 101, 40, 105, 100, // subscribe(id + 41, 59, 10, 32, 32, 125, 44, 32, 91, 93, 41, 59, // );. }, []); + 10, 10, 32, 32, 99, 111, 110, 115, 116, 32, 115, 101, // .. const se + 110, 100, 109, 101, 115, 115, 97, 103, 101, 32, 61, 32, // ndmessage = + 101, 118, 32, 61, 62, 32, 102, 101, 116, 99, 104, 40, // ev => fetch( + 39, 47, 97, 112, 105, 47, 109, 101, 115, 115, 97, 103, // '/api/messag + 101, 47, 115, 101, 110, 100, 39, 44, 32, 123, 10, 32, // e/send', {. + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // + 32, 32, 32, 32, 32, 109, 101, 116, 104, 111, 100, 58, // method: + 32, 39, 112, 111, 115, 116, 39, 44, 10, 32, 32, 32, // 'post',. + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // + 32, 32, 32, 98, 111, 100, 121, 58, 32, 96, 109, 101, // body: `me + 115, 115, 97, 103, 101, 61, 36, 123, 101, 110, 99, 111, // ssage=${enco + 100, 101, 85, 82, 73, 67, 111, 109, 112, 111, 110, 101, // deURICompone + 110, 116, 40, 116, 120, 116, 41, 125, 96, 10, 32, 32, // nt(txt)}`. + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // + 32, 32, 125, 41, 46, 116, 104, 101, 110, 40, 114, 32, // }).then(r + 61, 62, 32, 115, 101, 116, 84, 120, 116, 40, 39, 39, // => setTxt('' + 41, 41, 59, 10, 10, 32, 32, 114, 101, 116, 117, 114, // ));.. retur + 110, 32, 104, 116, 109, 108, 96, 10, 60, 100, 105, 118, // n html`.
.

MQTT + 109, 101, 115, 115, 97, 103, 101, 115, 60, 47, 104, 51, // messages

.
. + 32, 32, 77, 81, 84, 84, 32, 115, 101, 114, 118, 101, // MQTT serve + 114, 32, 115, 116, 97, 116, 117, 115, 58, 32, 60, 98, // r status: ${cfg.conne + 99, 116, 101, 100, 32, 63, 32, 39, 99, 111, 110, 110, // cted ? 'conn + 101, 99, 116, 101, 100, 39, 32, 58, 32, 39, 100, 105, // ected' : 'di + 99, 111, 110, 110, 101, 99, 116, 101, 100, 39, 125, 60, // connected'}< + 47, 98, 62, 10, 32, 32, 60, 47, 100, 105, 118, 62, // /b>.
+ 10, 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, // .
. $ + 123, 109, 101, 115, 115, 97, 103, 101, 115, 46, 109, 97, // {messages.ma + 112, 40, 109, 101, 115, 115, 97, 103, 101, 32, 61, 62, // p(message => + 32, 104, 40, 77, 101, 115, 115, 97, 103, 101, 44, 32, // h(Message, + 123, 109, 101, 115, 115, 97, 103, 101, 125, 41, 41, 125, // {message}))} + 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, // .
. + 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, //
. + 32, 60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, // Publish + 109, 101, 115, 115, 97, 103, 101, 58, 60, 47, 115, 112, // message:. setT + 120, 116, 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, // xt(ev.target + 46, 118, 97, 108, 117, 101, 41, 125, 32, 47, 62, 10, // .value)} />. + 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, //
. < + 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, 109, // div class="m + 115, 103, 34, 62, 10, 32, 32, 32, 32, 77, 101, 115, // sg">. Mes + 115, 97, 103, 101, 32, 103, 101, 116, 115, 32, 112, 97, // sage gets pa + 115, 115, 101, 100, 32, 116, 111, 32, 116, 104, 101, 32, // ssed to the + 100, 101, 118, 105, 99, 101, 32, 118, 105, 97, 32, 82, // device via R + 69, 83, 84, 46, 32, 84, 104, 101, 110, 32, 97, 32, // EST. Then a + 100, 101, 118, 105, 99, 101, 32, 115, 101, 110, 100, 115, // device sends + 32, 105, 116, 32, 116, 111, 10, 32, 32, 32, 32, 116, // it to. t + 104, 101, 32, 77, 81, 84, 84, 32, 115, 101, 114, 118, // he MQTT serv + 101, 114, 32, 111, 118, 101, 114, 32, 77, 81, 84, 84, // er over MQTT + 46, 32, 65, 108, 108, 32, 77, 81, 84, 84, 32, 109, // . All MQTT m + 101, 115, 115, 97, 103, 101, 115, 32, 111, 110, 32, 97, // essages on a + 32, 115, 117, 98, 115, 99, 114, 105, 98, 101, 100, 32, // subscribed + 116, 111, 112, 105, 99, 10, 32, 32, 32, 32, 114, 101, // topic. re + 99, 101, 105, 118, 101, 100, 32, 98, 121, 32, 97, 32, // ceived by a + 100, 101, 118, 105, 99, 101, 44, 32, 97, 114, 101, 32, // device, are + 112, 114, 111, 112, 97, 103, 97, 116, 101, 100, 32, 116, // propagated t + 111, 32, 116, 104, 105, 115, 32, 100, 97, 115, 104, 98, // o this dashb + 111, 97, 114, 100, 32, 118, 105, 97, 32, 116, 104, 101, // oard via the + 10, 32, 32, 32, 32, 47, 97, 112, 105, 47, 119, 97, // . /api/wa + 116, 99, 104, 46, 10, 32, 32, 60, 47, 100, 105, 118, // tch..
.
`;.} + 59, 10, 10, 47, 47, 32, 69, 120, 112, 101, 99, 116, // ;..// Expect + 101, 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 115, // ed arguments + 58, 10, 47, 47, 32, 100, 97, 116, 97, 58, 32, 116, // :.// data: t + 105, 109, 101, 115, 101, 114, 105, 101, 115, 44, 32, 101, // imeseries, e + 46, 103, 46, 32, 91, 32, 91, 49, 54, 53, 52, 51, // .g. [ [16543 + 54, 49, 51, 53, 50, 44, 32, 49, 57, 93, 44, 32, // 61352, 19], + 91, 49, 54, 53, 52, 51, 54, 49, 51, 53, 51, 44, // [1654361353, + 32, 49, 56, 93, 44, 32, 46, 46, 46, 32, 93, 10, // 18], ... ]. + 47, 47, 32, 119, 105, 100, 116, 104, 44, 32, 104, 101, // // width, he + 105, 103, 104, 116, 44, 32, 121, 116, 105, 99, 107, 115, // ight, yticks + 44, 32, 120, 116, 105, 99, 107, 115, 44, 32, 121, 109, // , xticks, ym + 105, 110, 44, 32, 121, 109, 97, 120, 44, 32, 120, 109, // in, ymax, xm + 105, 110, 44, 32, 120, 109, 97, 120, 10, 99, 111, 110, // in, xmax.con + 115, 116, 32, 83, 86, 71, 32, 61, 32, 102, 117, 110, // st SVG = fun + 99, 116, 105, 111, 110, 40, 112, 114, 111, 112, 115, 41, // ction(props) + 32, 123, 10, 32, 32, 47, 47, 32, 32, 32, 32, 32, // {. // + 32, 32, 32, 32, 32, 32, 32, 119, 10, 32, 32, 47, // w. / + 47, 32, 32, 32, 43, 45, 45, 45, 45, 45, 45, 45, // / +------- + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, // ------------ + 45, 45, 43, 10, 32, 32, 47, 47, 32, 32, 32, 124, // --+. // | + 32, 32, 32, 32, 32, 32, 32, 32, 104, 49, 32, 32, // h1 + 32, 32, 32, 32, 32, 32, 32, 32, 32, 124, 10, 32, // |. + 32, 47, 47, 32, 32, 32, 124, 32, 32, 32, 32, 43, // // | + + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 43, // -----------+ + 32, 32, 32, 32, 124, 10, 32, 32, 47, 47, 32, 32, // |. // + 32, 124, 32, 32, 32, 32, 124, 32, 32, 32, 32, 32, // | | + 32, 32, 32, 32, 32, 32, 124, 32, 32, 32, 32, 124, // | | + 32, 32, 104, 10, 32, 32, 47, 47, 32, 32, 32, 124, // h. // | + 32, 119, 49, 32, 124, 32, 32, 32, 32, 32, 32, 32, // w1 | + 32, 32, 32, 32, 124, 32, 119, 50, 32, 124, 10, 32, // | w2 |. + 32, 47, 47, 32, 32, 32, 124, 32, 32, 32, 32, 43, // // | + + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 43, // -----------+ + 32, 32, 32, 32, 124, 10, 32, 32, 47, 47, 32, 32, // |. // + 32, 124, 32, 32, 32, 32, 32, 32, 32, 32, 32, 104, // | h + 50, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 124, // 2 | + 10, 32, 32, 47, 47, 32, 32, 32, 43, 45, 45, 45, // . // +--- + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, // ------------ + 45, 45, 45, 45, 45, 45, 43, 10, 32, 32, 47, 47, // ------+. // + 10, 32, 32, 108, 101, 116, 32, 119, 32, 61, 32, 112, // . let w = p + 114, 111, 112, 115, 46, 119, 105, 100, 116, 104, 44, 32, // rops.width, + 104, 32, 61, 32, 112, 114, 111, 112, 115, 46, 104, 101, // h = props.he + 105, 103, 104, 116, 44, 32, 119, 49, 32, 61, 32, 51, // ight, w1 = 3 + 48, 44, 32, 119, 50, 32, 61, 32, 48, 44, 32, 104, // 0, w2 = 0, h + 49, 32, 61, 32, 56, 44, 32, 104, 50, 32, 61, 32, // 1 = 8, h2 = + 49, 56, 59, 10, 32, 32, 108, 101, 116, 32, 121, 116, // 18;. let yt + 105, 99, 107, 115, 32, 61, 32, 112, 114, 111, 112, 115, // icks = props + 46, 121, 116, 105, 99, 107, 115, 32, 124, 124, 32, 52, // .yticks || 4 + 44, 32, 120, 116, 105, 99, 107, 115, 32, 61, 32, 112, // , xticks = p + 114, 111, 112, 115, 46, 120, 116, 105, 99, 107, 115, 32, // rops.xticks + 124, 124, 32, 53, 59, 10, 32, 32, 108, 101, 116, 32, // || 5;. let + 100, 97, 116, 97, 32, 61, 32, 112, 114, 111, 112, 115, // data = props + 46, 100, 97, 116, 97, 32, 124, 124, 32, 91, 93, 59, // .data || []; + 10, 32, 32, 108, 101, 116, 32, 121, 109, 105, 110, 32, // . let ymin + 61, 32, 112, 114, 111, 112, 115, 46, 121, 109, 105, 110, // = props.ymin + 32, 124, 124, 32, 48, 59, 10, 32, 32, 108, 101, 116, // || 0;. let + 32, 121, 109, 97, 120, 32, 61, 32, 112, 114, 111, 112, // ymax = prop + 115, 46, 121, 109, 97, 120, 32, 124, 124, 32, 77, 97, // s.ymax || Ma + 116, 104, 46, 109, 97, 120, 46, 97, 112, 112, 108, 121, // th.max.apply + 40, 110, 117, 108, 108, 44, 32, 100, 97, 116, 97, 46, // (null, data. + 109, 97, 112, 40, 112, 32, 61, 62, 32, 112, 91, 49, // map(p => p[1 + 93, 41, 41, 59, 10, 32, 32, 108, 101, 116, 32, 120, // ]));. let x + 109, 105, 110, 32, 61, 32, 112, 114, 111, 112, 115, 46, // min = props. + 120, 109, 105, 110, 32, 124, 124, 32, 77, 97, 116, 104, // xmin || Math + 46, 109, 105, 110, 46, 97, 112, 112, 108, 121, 40, 110, // .min.apply(n + 117, 108, 108, 44, 32, 100, 97, 116, 97, 46, 109, 97, // ull, data.ma + 112, 40, 112, 32, 61, 62, 32, 112, 91, 48, 93, 41, // p(p => p[0]) + 41, 59, 10, 32, 32, 108, 101, 116, 32, 120, 109, 97, // );. let xma + 120, 32, 61, 32, 112, 114, 111, 112, 115, 46, 120, 109, // x = props.xm + 97, 120, 32, 124, 124, 32, 77, 97, 116, 104, 46, 109, // ax || Math.m + 97, 120, 46, 97, 112, 112, 108, 121, 40, 110, 117, 108, // ax.apply(nul + 108, 44, 32, 100, 97, 116, 97, 46, 109, 97, 112, 40, // l, data.map( + 112, 32, 61, 62, 32, 112, 91, 48, 93, 41, 41, 59, // p => p[0])); + 10, 10, 32, 32, 47, 47, 32, 89, 45, 97, 120, 105, // .. // Y-axi + 115, 32, 116, 105, 99, 107, 32, 108, 105, 110, 101, 115, // s tick lines + 32, 97, 110, 100, 32, 108, 97, 98, 101, 108, 115, 10, // and labels. + 32, 32, 108, 101, 116, 32, 121, 116, 97, 32, 61, 32, // let yta = + 40, 110, 101, 119, 32, 65, 114, 114, 97, 121, 40, 121, // (new Array(y + 116, 105, 99, 107, 115, 32, 43, 32, 49, 41, 41, 46, // ticks + 1)). + 102, 105, 108, 108, 40, 48, 41, 46, 109, 97, 112, 40, // fill(0).map( + 40, 95, 44, 32, 105, 41, 32, 61, 62, 32, 105, 41, // (_, i) => i) + 59, 32, 32, 47, 47, 32, 105, 110, 100, 105, 99, 101, // ; // indice + 115, 10, 32, 32, 108, 101, 116, 32, 121, 116, 105, 32, // s. let yti + 61, 32, 105, 32, 61, 62, 32, 104, 32, 45, 32, 104, // = i => h - h + 50, 32, 45, 32, 40, 104, 32, 45, 32, 104, 49, 32, // 2 - (h - h1 + 45, 32, 104, 50, 41, 32, 42, 32, 105, 32, 47, 32, // - h2) * i / + 121, 116, 105, 99, 107, 115, 59, 32, 32, 32, 32, 32, // yticks; + 32, 32, 32, 32, 32, 47, 47, 32, 105, 110, 100, 101, // // inde + 120, 39, 115, 32, 89, 10, 32, 32, 108, 101, 116, 32, // x's Y. let + 121, 116, 118, 32, 61, 32, 105, 32, 61, 62, 32, 40, // ytv = i => ( + 121, 109, 97, 120, 32, 45, 32, 121, 109, 105, 110, 41, // ymax - ymin) + 32, 42, 32, 105, 32, 47, 32, 121, 116, 105, 99, 107, // * i / ytick + 115, 59, 10, 32, 32, 108, 101, 116, 32, 121, 116, 108, // s;. let ytl + 32, 61, 32, 121, 32, 61, 62, 32, 104, 116, 109, 108, // = y => html + 96, 60, 108, 105, 110, 101, 32, 120, 49, 61, 36, 123, // ``;. l + 101, 116, 32, 121, 116, 116, 32, 61, 32, 40, 121, 44, // et ytt = (y, + 32, 118, 41, 32, 61, 62, 32, 104, 116, 109, 108, 96, // v) => html` + 60, 116, 101, 120, 116, 32, 120, 61, 48, 32, 121, 61, // $ + 123, 118, 125, 60, 47, 116, 101, 120, 116, 62, 96, 59, // {v}`; + 10, 10, 32, 32, 47, 47, 32, 88, 45, 97, 120, 105, // .. // X-axi + 115, 32, 116, 105, 99, 107, 32, 108, 105, 110, 101, 115, // s tick lines + 32, 97, 110, 100, 32, 108, 97, 98, 101, 108, 115, 10, // and labels. + 32, 32, 108, 101, 116, 32, 100, 97, 116, 101, 102, 109, // let datefm + 116, 32, 61, 32, 117, 110, 105, 120, 32, 61, 62, 32, // t = unix => + 40, 110, 101, 119, 32, 68, 97, 116, 101, 40, 117, 110, // (new Date(un + 105, 120, 32, 42, 32, 49, 48, 48, 48, 41, 41, 46, // ix * 1000)). + 116, 111, 73, 83, 79, 83, 116, 114, 105, 110, 103, 40, // toISOString( + 41, 46, 115, 117, 98, 115, 116, 114, 40, 49, 52, 44, // ).substr(14, + 32, 53, 41, 59, 10, 32, 32, 108, 101, 116, 32, 120, // 5);. let x + 116, 97, 32, 61, 32, 40, 110, 101, 119, 32, 65, 114, // ta = (new Ar + 114, 97, 121, 40, 120, 116, 105, 99, 107, 115, 32, 43, // ray(xticks + + 32, 49, 41, 41, 46, 102, 105, 108, 108, 40, 48, 41, // 1)).fill(0) + 46, 109, 97, 112, 40, 40, 95, 44, 32, 105, 41, 32, // .map((_, i) + 61, 62, 32, 105, 41, 59, 32, 32, 47, 47, 32, 105, // => i); // i + 110, 100, 105, 99, 101, 115, 10, 32, 32, 108, 101, 116, // ndices. let + 32, 120, 116, 105, 32, 61, 32, 105, 32, 61, 62, 32, // xti = i => + 119, 49, 32, 43, 32, 40, 119, 32, 45, 32, 119, 49, // w1 + (w - w1 + 32, 45, 32, 119, 50, 41, 32, 42, 32, 105, 32, 47, // - w2) * i / + 32, 120, 116, 105, 99, 107, 115, 59, 32, 32, 32, 32, // xticks; + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, // // + 32, 105, 110, 100, 101, 120, 39, 115, 32, 88, 10, 32, // index's X. + 32, 108, 101, 116, 32, 120, 116, 118, 32, 61, 32, 105, // let xtv = i + 32, 61, 62, 32, 100, 97, 116, 101, 102, 109, 116, 40, // => datefmt( + 120, 109, 105, 110, 32, 43, 32, 40, 120, 109, 97, 120, // xmin + (xmax + 32, 45, 32, 120, 109, 105, 110, 41, 32, 42, 32, 105, // - xmin) * i + 32, 47, 32, 120, 116, 105, 99, 107, 115, 41, 59, 10, // / xticks);. + 32, 32, 108, 101, 116, 32, 120, 116, 108, 32, 61, 32, // let xtl = + 120, 32, 61, 62, 32, 104, 116, 109, 108, 96, 60, 112, // x => html`

`;. let + 32, 120, 116, 116, 32, 61, 32, 40, 120, 44, 32, 118, // xtt = (x, v + 41, 32, 61, 62, 10, 32, 32, 32, 32, 32, 32, 104, // ) =>. h + 116, 109, 108, 96, 60, 116, 101, 120, 116, 32, 120, 61, // tml`$ + 123, 118, 125, 60, 47, 116, 101, 120, 116, 62, 96, 59, // {v}`; + 10, 10, 32, 32, 47, 47, 32, 84, 114, 97, 110, 115, // .. // Trans + 102, 111, 114, 109, 32, 100, 97, 116, 97, 32, 112, 111, // form data po + 105, 110, 116, 115, 32, 97, 114, 114, 97, 121, 32, 105, // ints array i + 110, 116, 111, 32, 99, 111, 111, 114, 100, 105, 110, 97, // nto coordina + 116, 101, 10, 32, 32, 108, 101, 116, 32, 100, 120, 32, // te. let dx + 61, 32, 118, 32, 61, 62, 32, 119, 49, 32, 43, 32, // = v => w1 + + 40, 118, 32, 45, 32, 120, 109, 105, 110, 41, 32, 47, // (v - xmin) / + 32, 40, 40, 120, 109, 97, 120, 32, 45, 32, 120, 109, // ((xmax - xm + 105, 110, 41, 32, 124, 124, 32, 49, 41, 32, 42, 32, // in) || 1) * + 40, 119, 32, 45, 32, 119, 49, 32, 45, 32, 119, 50, // (w - w1 - w2 + 41, 59, 10, 32, 32, 108, 101, 116, 32, 100, 121, 32, // );. let dy + 61, 32, 118, 32, 61, 62, 32, 104, 32, 45, 32, 104, // = v => h - h + 50, 32, 45, 32, 40, 118, 32, 45, 32, 121, 109, 105, // 2 - (v - ymi + 110, 41, 32, 47, 32, 40, 40, 121, 109, 97, 120, 32, // n) / ((ymax + 45, 32, 121, 109, 105, 110, 41, 32, 124, 124, 32, 49, // - ymin) || 1 + 41, 32, 42, 32, 40, 104, 32, 45, 32, 104, 49, 32, // ) * (h - h1 + 45, 32, 104, 50, 41, 59, 10, 32, 32, 108, 101, 116, // - h2);. let + 32, 100, 100, 32, 61, 32, 100, 97, 116, 97, 46, 109, // dd = data.m + 97, 112, 40, 112, 32, 61, 62, 32, 91, 77, 97, 116, // ap(p => [Mat + 104, 46, 114, 111, 117, 110, 100, 40, 100, 120, 40, 112, // h.round(dx(p + 91, 48, 93, 41, 41, 44, 32, 77, 97, 116, 104, 46, // [0])), Math. + 114, 111, 117, 110, 100, 40, 100, 121, 40, 112, 91, 49, // round(dy(p[1 + 93, 41, 41, 93, 41, 59, 10, 32, 32, 108, 101, 116, // ]))]);. let + 32, 100, 100, 108, 32, 61, 32, 100, 100, 46, 108, 101, // ddl = dd.le + 110, 103, 116, 104, 59, 10, 32, 32, 47, 47, 32, 65, // ngth;. // A + 110, 100, 32, 112, 108, 111, 116, 32, 116, 104, 101, 32, // nd plot the + 100, 97, 116, 97, 32, 97, 115, 32, 60, 112, 97, 116, // data as element. + 32, 108, 101, 116, 32, 98, 101, 103, 105, 110, 48, 32, // let begin0 + 61, 32, 100, 100, 108, 32, 63, 32, 96, 77, 32, 36, // = ddl ? `M $ + 123, 100, 100, 91, 48, 93, 91, 48, 93, 125, 44, 36, // {dd[0][0]},$ + 123, 100, 100, 91, 48, 93, 91, 49, 93, 125, 96, 32, // {dd[0][1]}` + 58, 32, 96, 77, 32, 48, 44, 48, 96, 59, 10, 32, // : `M 0,0`;. + 32, 108, 101, 116, 32, 98, 101, 103, 105, 110, 32, 61, // let begin = + 32, 96, 77, 32, 36, 123, 119, 49, 125, 44, 36, 123, // `M ${w1},${ + 104, 32, 45, 32, 104, 50, 125, 96, 59, 32, 32, 47, // h - h2}`; / + 47, 32, 73, 110, 105, 116, 105, 97, 108, 32, 112, 111, // / Initial po + 105, 110, 116, 10, 32, 32, 108, 101, 116, 32, 101, 110, // int. let en + 100, 32, 61, 32, 100, 100, 108, 32, 63, 32, 96, 76, // d = ddl ? `L + 32, 36, 123, 100, 100, 91, 100, 100, 108, 32, 45, 32, // ${dd[ddl - + 49, 93, 91, 48, 93, 125, 44, 36, 123, 104, 32, 45, // 1][0]},${h - + 32, 104, 50, 125, 96, 32, 58, 32, 96, 76, 32, 36, // h2}` : `L $ + 123, 119, 49, 125, 44, 36, 123, 104, 32, 45, 32, 104, // {w1},${h - h + 50, 125, 96, 59, 10, 32, 32, 108, 101, 116, 32, 115, // 2}`;. let s + 101, 114, 105, 101, 115, 32, 61, 32, 100, 100, 108, 32, // eries = ddl + 63, 32, 100, 100, 46, 109, 97, 112, 40, 112, 32, 61, // ? dd.map(p = + 62, 32, 96, 76, 32, 36, 123, 112, 91, 48, 93, 125, // > `L ${p[0]} + 32, 36, 123, 112, 91, 49, 93, 125, 96, 41, 32, 58, // ${p[1]}`) : + 32, 91, 93, 59, 10, 10, 32, 32, 114, 101, 116, 117, // [];.. retu + 114, 110, 32, 104, 116, 109, 108, 96, 10, 60, 115, 118, // rn html`.. . + 36, 123, 121, 116, 97, 46, 109, 97, 112, 40, 105, 32, // ${yta.map(i + 61, 62, 32, 121, 116, 108, 40, 121, 116, 105, 40, 105, // => ytl(yti(i + 41, 41, 41, 125, 10, 32, 32, 36, 123, 121, 116, 97, // )))}. ${yta + 46, 109, 97, 112, 40, 105, 32, 61, 62, 32, 121, 116, // .map(i => yt + 116, 40, 121, 116, 105, 40, 105, 41, 44, 32, 121, 116, // t(yti(i), yt + 118, 40, 105, 41, 41, 41, 125, 10, 32, 32, 36, 123, // v(i)))}. ${ + 120, 116, 97, 46, 109, 97, 112, 40, 105, 32, 61, 62, // xta.map(i => + 32, 120, 116, 108, 40, 120, 116, 105, 40, 105, 41, 41, // xtl(xti(i)) + 41, 125, 10, 32, 32, 36, 123, 100, 97, 116, 97, 46, // )}. ${data. + 108, 101, 110, 103, 116, 104, 32, 63, 32, 120, 116, 97, // length ? xta + 46, 109, 97, 112, 40, 105, 32, 61, 62, 32, 120, 116, // .map(i => xt + 116, 40, 120, 116, 105, 40, 105, 41, 44, 32, 120, 116, // t(xti(i), xt + 118, 40, 105, 41, 41, 41, 32, 58, 32, 39, 39, 125, // v(i))) : ''} + 10, 32, 32, 60, 112, 97, 116, 104, 32, 100, 61, 34, // . . < + 112, 97, 116, 104, 32, 100, 61, 34, 36, 123, 98, 101, // path d="${be + 103, 105, 110, 48, 125, 32, 36, 123, 115, 101, 114, 105, // gin0} ${seri + 101, 115, 46, 106, 111, 105, 110, 40, 39, 32, 39, 41, // es.join(' ') + 125, 34, 32, 99, 108, 97, 115, 115, 61, 34, 115, 101, // }" class="se + 114, 105, 101, 115, 34, 32, 47, 62, 10, 60, 47, 115, // ries" />.`;.};...c + 111, 110, 115, 116, 32, 67, 104, 97, 114, 116, 32, 61, // onst Chart = + 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 112, 114, // function(pr + 111, 112, 115, 41, 32, 123, 10, 32, 32, 99, 111, 110, // ops) {. con + 115, 116, 32, 91, 100, 97, 116, 97, 44, 32, 115, 101, // st [data, se + 116, 68, 97, 116, 97, 93, 32, 61, 32, 117, 115, 101, // tData] = use + 83, 116, 97, 116, 101, 40, 91, 93, 41, 59, 10, 32, // State([]);. + 32, 117, 115, 101, 69, 102, 102, 101, 99, 116, 40, 40, // useEffect(( + 41, 32, 61, 62, 32, 123, 10, 32, 32, 32, 32, 99, // ) => {. c + 111, 110, 115, 116, 32, 105, 100, 32, 61, 32, 80, 117, // onst id = Pu + 98, 83, 117, 98, 46, 115, 117, 98, 115, 99, 114, 105, // bSub.subscri + 98, 101, 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, // be(function( + 109, 115, 103, 41, 32, 123, 10, 32, 32, 32, 32, 32, // msg) {. + 32, 105, 102, 32, 40, 109, 115, 103, 46, 110, 97, 109, // if (msg.nam + 101, 32, 33, 61, 32, 39, 109, 101, 116, 114, 105, 99, // e != 'metric + 115, 39, 41, 32, 114, 101, 116, 117, 114, 110, 59, 10, // s') return;. + 32, 32, 32, 32, 32, 32, 115, 101, 116, 68, 97, 116, // setDat + 97, 40, 120, 32, 61, 62, 32, 120, 46, 99, 111, 110, // a(x => x.con + 99, 97, 116, 40, 91, 109, 115, 103, 46, 100, 97, 116, // cat([msg.dat + 97, 93, 41, 46, 115, 112, 108, 105, 99, 101, 40, 45, // a]).splice(- + 77, 97, 120, 77, 101, 116, 114, 105, 99, 115, 68, 97, // MaxMetricsDa + 116, 97, 80, 111, 105, 110, 116, 115, 41, 41, 59, 10, // taPoints));. + 32, 32, 32, 32, 125, 41, 59, 10, 32, 32, 32, 32, // });. + 114, 101, 116, 117, 114, 110, 32, 80, 117, 98, 83, 117, // return PubSu + 98, 46, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, // b.unsubscrib + 101, 40, 105, 100, 41, 59, 10, 32, 32, 125, 44, 32, // e(id);. }, + 91, 93, 41, 59, 10, 10, 32, 32, 108, 101, 116, 32, // []);.. let + 120, 109, 97, 120, 32, 61, 32, 48, 44, 32, 109, 105, // xmax = 0, mi + 115, 115, 105, 110, 103, 32, 61, 32, 77, 97, 120, 77, // ssing = MaxM + 101, 116, 114, 105, 99, 115, 68, 97, 116, 97, 80, 111, // etricsDataPo + 105, 110, 116, 115, 32, 45, 32, 100, 97, 116, 97, 46, // ints - data. + 108, 101, 110, 103, 116, 104, 59, 10, 32, 32, 105, 102, // length;. if + 32, 40, 109, 105, 115, 115, 105, 110, 103, 32, 62, 32, // (missing > + 48, 41, 32, 120, 109, 97, 120, 32, 61, 32, 77, 97, // 0) xmax = Ma + 116, 104, 46, 114, 111, 117, 110, 100, 40, 68, 97, 116, // th.round(Dat + 101, 46, 110, 111, 119, 40, 41, 32, 47, 32, 49, 48, // e.now() / 10 + 48, 48, 41, 32, 43, 32, 109, 105, 115, 115, 105, 110, // 00) + missin + 103, 59, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, // g;. return + 104, 116, 109, 108, 96, 10, 60, 100, 105, 118, 32, 115, // html`.

+ 10, 32, 32, 60, 104, 51, 32, 115, 116, 121, 108, 101, // .

Data Chart + 60, 47, 104, 51, 62, 10, 32, 32, 60, 100, 105, 118, //

.
+ 10, 32, 32, 32, 32, 84, 104, 105, 115, 32, 99, 104, // . This ch + 97, 114, 116, 32, 112, 108, 111, 116, 115, 32, 108, 105, // art plots li + 118, 101, 32, 115, 101, 110, 115, 111, 114, 32, 100, 97, // ve sensor da + 116, 97, 44, 32, 115, 101, 110, 116, 32, 98, 121, 32, // ta, sent by + 97, 32, 100, 101, 118, 105, 99, 101, 32, 118, 105, 97, // a device via + 32, 47, 97, 112, 105, 47, 119, 97, 116, 99, 104, 46, // /api/watch. + 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 60, 47, // .
.`;.};..c + 111, 110, 115, 116, 32, 65, 112, 112, 32, 61, 32, 102, // onst App = f + 117, 110, 99, 116, 105, 111, 110, 40, 112, 114, 111, 112, // unction(prop + 115, 41, 32, 123, 10, 32, 32, 99, 111, 110, 115, 116, // s) {. const + 32, 91, 117, 115, 101, 114, 44, 32, 115, 101, 116, 85, // [user, setU + 115, 101, 114, 93, 32, 61, 32, 117, 115, 101, 83, 116, // ser] = useSt + 97, 116, 101, 40, 39, 39, 41, 59, 10, 10, 32, 32, // ate('');.. + 99, 111, 110, 115, 116, 32, 103, 101, 116, 99, 111, 110, // const getcon + 102, 105, 103, 32, 61, 32, 40, 41, 32, 61, 62, 10, // fig = () =>. + 32, 32, 32, 32, 32, 32, 102, 101, 116, 99, 104, 40, // fetch( + 39, 47, 97, 112, 105, 47, 99, 111, 110, 102, 105, 103, // '/api/config + 47, 103, 101, 116, 39, 44, 32, 123, 104, 101, 97, 100, // /get', {head + 101, 114, 115, 58, 32, 123, 65, 117, 116, 104, 111, 114, // ers: {Author + 105, 122, 97, 116, 105, 111, 110, 58, 32, 39, 39, 125, // ization: ''} + 125, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, // }). + 32, 46, 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, // .then(r => + 114, 46, 106, 115, 111, 110, 40, 41, 41, 10, 32, 32, // r.json()). + 32, 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, // .the + 110, 40, 114, 32, 61, 62, 32, 80, 117, 98, 83, 117, // n(r => PubSu + 98, 46, 112, 117, 98, 108, 105, 115, 104, 40, 123, 110, // b.publish({n + 97, 109, 101, 58, 32, 39, 110, 101, 119, 99, 111, 110, // ame: 'newcon + 102, 105, 103, 39, 44, 32, 100, 97, 116, 97, 58, 32, // fig', data: + 114, 125, 41, 41, 59, 10, 10, 32, 32, 99, 111, 110, // r}));.. con 115, 116, 32, 108, 111, 103, 105, 110, 32, 61, 32, 102, // st login = f 117, 110, 99, 116, 105, 111, 110, 40, 117, 41, 32, 123, // unction(u) { 10, 32, 32, 32, 32, 100, 111, 99, 117, 109, 101, 110, // . documen @@ -956,81 +1045,87 @@ static const unsigned char v2[] = { 103, 101, 61, 51, 54, 48, 48, 96, 59, 10, 32, 32, // ge=3600`;. 32, 32, 115, 101, 116, 85, 115, 101, 114, 40, 117, 46, // setUser(u. 117, 115, 101, 114, 41, 59, 10, 32, 32, 32, 32, 114, // user);. r - 101, 102, 114, 101, 115, 104, 40, 41, 59, 10, 32, 32, // efresh();. - 125, 59, 10, 10, 32, 32, 99, 111, 110, 115, 116, 32, // };.. const - 108, 111, 103, 111, 117, 116, 32, 61, 32, 101, 118, 32, // logout = ev - 61, 62, 32, 123, 10, 32, 32, 32, 32, 100, 111, 99, // => {. doc - 117, 109, 101, 110, 116, 46, 99, 111, 111, 107, 105, 101, // ument.cookie - 32, 61, 32, 96, 97, 99, 99, 101, 115, 115, 95, 116, // = `access_t - 111, 107, 101, 110, 61, 59, 112, 97, 116, 104, 61, 47, // oken=;path=/ - 59, 109, 97, 120, 45, 97, 103, 101, 61, 48, 96, 59, // ;max-age=0`; - 10, 32, 32, 32, 32, 115, 101, 116, 85, 115, 101, 114, // . setUser - 40, 39, 39, 41, 59, 10, 32, 32, 125, 59, 10, 10, // ('');. };.. - 32, 32, 99, 111, 110, 115, 116, 32, 119, 97, 116, 99, // const watc - 104, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, // h = function - 40, 41, 32, 123, 10, 32, 32, 32, 32, 118, 97, 114, // () {. var - 32, 102, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, // f = functio - 110, 40, 114, 101, 97, 100, 101, 114, 41, 32, 123, 10, // n(reader) {. - 32, 32, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, // return - 32, 114, 101, 97, 100, 101, 114, 46, 114, 101, 97, 100, // reader.read - 40, 41, 46, 116, 104, 101, 110, 40, 102, 117, 110, 99, // ().then(func - 116, 105, 111, 110, 40, 114, 101, 115, 117, 108, 116, 41, // tion(result) - 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 118, // {. v - 97, 114, 32, 100, 97, 116, 97, 32, 61, 32, 83, 116, // ar data = St - 114, 105, 110, 103, 46, 102, 114, 111, 109, 67, 104, 97, // ring.fromCha - 114, 67, 111, 100, 101, 46, 97, 112, 112, 108, 121, 40, // rCode.apply( - 110, 117, 108, 108, 44, 32, 114, 101, 115, 117, 108, 116, // null, result - 46, 118, 97, 108, 117, 101, 41, 59, 10, 32, 32, 32, // .value);. - 32, 32, 32, 32, 32, 118, 97, 114, 32, 109, 115, 103, // var msg - 32, 61, 32, 74, 83, 79, 78, 46, 112, 97, 114, 115, // = JSON.pars - 101, 40, 100, 97, 116, 97, 41, 59, 10, 32, 32, 32, // e(data);. - 32, 32, 32, 32, 32, 105, 102, 32, 40, 109, 115, 103, // if (msg - 46, 110, 97, 109, 101, 32, 61, 61, 32, 39, 99, 111, // .name == 'co - 110, 102, 105, 103, 39, 41, 32, 123, 10, 32, 32, 32, // nfig') {. - 32, 32, 32, 32, 32, 32, 32, 114, 101, 102, 114, 101, // refre - 115, 104, 40, 41, 59, 10, 32, 32, 32, 32, 32, 32, // sh();. - 32, 32, 125, 32, 101, 108, 115, 101, 32, 105, 102, 32, // } else if - 40, 109, 115, 103, 46, 110, 97, 109, 101, 32, 61, 61, // (msg.name == - 32, 39, 109, 101, 115, 115, 97, 103, 101, 39, 41, 32, // 'message') + 101, 116, 117, 114, 110, 32, 103, 101, 116, 99, 111, 110, // eturn getcon + 102, 105, 103, 40, 41, 59, 10, 32, 32, 125, 59, 10, // fig();. };. + 10, 32, 32, 99, 111, 110, 115, 116, 32, 108, 111, 103, // . const log + 111, 117, 116, 32, 61, 32, 101, 118, 32, 61, 62, 32, // out = ev => + 123, 10, 32, 32, 32, 32, 100, 111, 99, 117, 109, 101, // {. docume + 110, 116, 46, 99, 111, 111, 107, 105, 101, 32, 61, 32, // nt.cookie = + 96, 97, 99, 99, 101, 115, 115, 95, 116, 111, 107, 101, // `access_toke + 110, 61, 59, 112, 97, 116, 104, 61, 47, 59, 109, 97, // n=;path=/;ma + 120, 45, 97, 103, 101, 61, 48, 96, 59, 10, 32, 32, // x-age=0`;. + 32, 32, 115, 101, 116, 85, 115, 101, 114, 40, 39, 39, // setUser('' + 41, 59, 10, 32, 32, 125, 59, 10, 10, 32, 32, 47, // );. };.. / + 47, 32, 87, 97, 116, 99, 104, 32, 102, 111, 114, 32, // / Watch for + 110, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, // notification + 115, 46, 32, 65, 115, 32, 115, 111, 111, 110, 32, 97, // s. As soon a + 115, 32, 97, 32, 110, 111, 116, 105, 102, 105, 99, 97, // s a notifica + 116, 105, 111, 110, 32, 97, 114, 114, 105, 118, 101, 115, // tion arrives + 44, 32, 112, 97, 115, 115, 32, 105, 116, 32, 111, 110, // , pass it on + 10, 32, 32, 47, 47, 32, 116, 111, 32, 97, 108, 108, // . // to all + 32, 115, 117, 98, 115, 99, 114, 105, 98, 101, 100, 32, // subscribed + 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 10, 32, // components. + 32, 99, 111, 110, 115, 116, 32, 119, 97, 116, 99, 104, // const watch + 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, // = function( + 41, 32, 123, 10, 32, 32, 32, 32, 118, 97, 114, 32, // ) {. var + 108, 32, 61, 32, 119, 105, 110, 100, 111, 119, 46, 108, // l = window.l + 111, 99, 97, 116, 105, 111, 110, 44, 32, 112, 114, 111, // ocation, pro + 116, 111, 32, 61, 32, 108, 46, 112, 114, 111, 116, 111, // to = l.proto + 99, 111, 108, 46, 114, 101, 112, 108, 97, 99, 101, 40, // col.replace( + 39, 104, 116, 116, 112, 39, 44, 32, 39, 119, 115, 39, // 'http', 'ws' + 41, 59, 10, 32, 32, 32, 32, 118, 97, 114, 32, 116, // );. var t + 105, 100, 44, 32, 119, 115, 85, 82, 73, 32, 61, 32, // id, wsURI = + 112, 114, 111, 116, 111, 32, 43, 32, 39, 47, 47, 39, // proto + '//' + 32, 43, 32, 108, 46, 104, 111, 115, 116, 32, 43, 32, // + l.host + + 39, 47, 97, 112, 105, 47, 119, 97, 116, 99, 104, 39, // '/api/watch' + 10, 32, 32, 32, 32, 118, 97, 114, 32, 114, 101, 99, // . var rec + 111, 110, 110, 101, 99, 116, 32, 61, 32, 102, 117, 110, // onnect = fun + 99, 116, 105, 111, 110, 40, 41, 32, 123, 10, 32, 32, // ction() {. + 32, 32, 32, 32, 118, 97, 114, 32, 119, 115, 32, 61, // var ws = + 32, 110, 101, 119, 32, 87, 101, 98, 83, 111, 99, 107, // new WebSock + 101, 116, 40, 119, 115, 85, 82, 73, 41, 59, 10, 32, // et(wsURI);. + 32, 32, 32, 32, 32, 119, 115, 46, 111, 110, 109, 101, // ws.onme + 115, 115, 97, 103, 101, 32, 61, 32, 102, 117, 110, 99, // ssage = func + 116, 105, 111, 110, 40, 101, 118, 41, 32, 123, 10, 32, // tion(ev) {. + 32, 32, 32, 32, 32, 32, 32, 116, 114, 121, 32, 123, // try { + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 118, // . v + 97, 114, 32, 109, 115, 103, 32, 61, 32, 74, 83, 79, // ar msg = JSO + 78, 46, 112, 97, 114, 115, 101, 40, 101, 118, 46, 100, // N.parse(ev.d + 97, 116, 97, 41, 59, 10, 32, 32, 32, 32, 32, 32, // ata);. + 32, 32, 32, 32, 80, 117, 98, 83, 117, 98, 46, 112, // PubSub.p + 117, 98, 108, 105, 115, 104, 40, 109, 115, 103, 41, 59, // ublish(msg); + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 105, // . i + 102, 32, 40, 109, 115, 103, 46, 110, 97, 109, 101, 32, // f (msg.name + 33, 61, 32, 39, 109, 101, 116, 114, 105, 99, 115, 39, // != 'metrics' + 41, 32, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, // ) console.lo + 103, 40, 39, 119, 115, 45, 62, 39, 44, 32, 109, 115, // g('ws->', ms + 103, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, // g);. + 125, 32, 99, 97, 116, 99, 104, 32, 40, 101, 41, 32, // } catch (e) 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // {. - 115, 101, 116, 77, 101, 115, 115, 97, 103, 101, 115, 40, // setMessages( - 109, 32, 61, 62, 32, 109, 46, 99, 111, 110, 99, 97, // m => m.conca - 116, 40, 91, 109, 115, 103, 46, 100, 97, 116, 97, 93, // t([msg.data] - 41, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, 32, // ));. - 125, 32, 101, 108, 115, 101, 32, 105, 102, 32, 40, 109, // } else if (m - 115, 103, 46, 110, 97, 109, 101, 32, 61, 61, 32, 39, // sg.name == ' - 109, 101, 116, 114, 105, 99, 115, 39, 41, 32, 123, 10, // metrics') {. - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 115, 101, // se - 116, 77, 101, 116, 114, 105, 99, 115, 40, 109, 32, 61, // tMetrics(m = - 62, 32, 109, 46, 99, 111, 110, 99, 97, 116, 40, 91, // > m.concat([ - 109, 115, 103, 46, 100, 97, 116, 97, 93, 41, 46, 115, // msg.data]).s - 112, 108, 105, 99, 101, 40, 45, 77, 97, 120, 77, 101, // plice(-MaxMe - 116, 114, 105, 99, 115, 68, 97, 116, 97, 80, 111, 105, // tricsDataPoi - 110, 116, 115, 41, 41, 59, 10, 32, 32, 32, 32, 32, // nts));. - 32, 32, 32, 125, 10, 32, 32, 32, 32, 32, 32, 32, // }. - 32, 47, 47, 32, 99, 111, 110, 115, 111, 108, 101, 46, // // console. - 108, 111, 103, 40, 109, 115, 103, 41, 59, 10, 32, 32, // log(msg);. - 32, 32, 32, 32, 32, 32, 105, 102, 32, 40, 33, 114, // if (!r - 101, 115, 117, 108, 116, 46, 100, 111, 110, 101, 41, 32, // esult.done) - 114, 101, 116, 117, 114, 110, 32, 102, 40, 114, 101, 97, // return f(rea - 100, 101, 114, 41, 59, 10, 32, 32, 32, 32, 32, 32, // der);. - 125, 41, 59, 10, 32, 32, 32, 32, 125, 59, 10, 32, // });. };. - 32, 32, 32, 102, 101, 116, 99, 104, 40, 39, 47, 97, // fetch('/a - 112, 105, 47, 119, 97, 116, 99, 104, 39, 44, 32, 123, // pi/watch', { - 104, 101, 97, 100, 101, 114, 115, 58, 32, 123, 65, 117, // headers: {Au - 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 58, // thorization: - 32, 39, 39, 125, 125, 41, 10, 32, 32, 32, 32, 32, // ''}}). - 32, 32, 32, 46, 116, 104, 101, 110, 40, 114, 32, 61, // .then(r = - 62, 32, 114, 46, 98, 111, 100, 121, 46, 103, 101, 116, // > r.body.get - 82, 101, 97, 100, 101, 114, 40, 41, 41, 10, 32, 32, // Reader()). - 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, // .then( - 102, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 46, // f). . - 99, 97, 116, 99, 104, 40, 101, 32, 61, 62, 32, 115, // catch(e => s - 101, 116, 84, 105, 109, 101, 111, 117, 116, 40, 119, 97, // etTimeout(wa - 116, 99, 104, 44, 32, 49, 48, 48, 48, 41, 41, 59, // tch, 1000)); - 10, 32, 32, 125, 59, 10, 10, 32, 32, 117, 115, 101, // . };.. use - 69, 102, 102, 101, 99, 116, 40, 40, 41, 32, 61, 62, // Effect(() => - 32, 123, 10, 32, 32, 32, 32, 102, 101, 116, 99, 104, // {. fetch + 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 40, // console.log( + 39, 73, 110, 118, 97, 108, 105, 100, 32, 119, 115, 32, // 'Invalid ws + 102, 114, 97, 109, 101, 58, 39, 44, 32, 101, 118, 46, // frame:', ev. + 100, 97, 116, 97, 41, 59, 32, 32, 47, 47, 32, 101, // data); // e + 115, 108, 105, 110, 116, 45, 100, 105, 115, 97, 98, 108, // slint-disabl + 101, 45, 108, 105, 110, 101, 10, 32, 32, 32, 32, 32, // e-line. + 32, 32, 32, 125, 10, 32, 32, 32, 32, 32, 32, 125, // }. } + 59, 10, 32, 32, 32, 32, 32, 32, 119, 115, 46, 111, // ;. ws.o + 110, 99, 108, 111, 115, 101, 32, 61, 32, 102, 117, 110, // nclose = fun + 99, 116, 105, 111, 110, 40, 41, 32, 123, 10, 32, 32, // ction() {. + 32, 32, 32, 32, 32, 32, 99, 108, 101, 97, 114, 84, // clearT + 105, 109, 101, 111, 117, 116, 40, 116, 105, 100, 41, 59, // imeout(tid); + 10, 32, 32, 32, 32, 32, 32, 32, 32, 116, 105, 100, // . tid + 32, 61, 32, 115, 101, 116, 84, 105, 109, 101, 111, 117, // = setTimeou + 116, 40, 114, 101, 99, 111, 110, 110, 101, 99, 116, 44, // t(reconnect, + 32, 49, 48, 48, 48, 41, 59, 10, 32, 32, 32, 32, // 1000);. + 32, 32, 125, 59, 10, 32, 32, 32, 32, 125, 59, 10, // };. };. + 32, 32, 32, 32, 114, 101, 99, 111, 110, 110, 101, 99, // reconnec + 116, 40, 41, 59, 10, 32, 32, 125, 59, 10, 10, 32, // t();. };.. + 32, 117, 115, 101, 69, 102, 102, 101, 99, 116, 40, 40, // useEffect(( + 41, 32, 61, 62, 32, 123, 10, 32, 32, 32, 32, 47, // ) => {. / + 47, 32, 67, 97, 108, 108, 101, 100, 32, 111, 110, 99, // / Called onc + 101, 32, 97, 116, 32, 105, 110, 105, 116, 32, 116, 105, // e at init ti + 109, 101, 10, 32, 32, 32, 32, 102, 101, 116, 99, 104, // me. fetch 40, 39, 47, 97, 112, 105, 47, 108, 111, 103, 105, 110, // ('/api/login 39, 44, 32, 123, 104, 101, 97, 100, 101, 114, 115, 58, // ', {headers: 32, 123, 65, 117, 116, 104, 111, 114, 105, 122, 97, 116, // {Authorizat @@ -1043,54 +1138,52 @@ static const unsigned char v2[] = { 32, 32, 32, 32, 32, 46, 99, 97, 116, 99, 104, 40, // .catch( 101, 114, 114, 32, 61, 62, 32, 115, 101, 116, 85, 115, // err => setUs 101, 114, 40, 39, 39, 41, 41, 59, 10, 32, 32, 32, // er(''));. - 32, 114, 101, 102, 114, 101, 115, 104, 40, 41, 59, 10, // refresh();. - 32, 32, 32, 32, 119, 97, 116, 99, 104, 40, 41, 59, // watch(); - 10, 32, 32, 125, 44, 32, 91, 93, 41, 59, 10, 10, // . }, []);.. - 32, 32, 105, 102, 32, 40, 33, 117, 115, 101, 114, 41, // if (!user) + 32, 119, 97, 116, 99, 104, 40, 41, 59, 10, 32, 32, // watch();. + 32, 32, 80, 117, 98, 83, 117, 98, 46, 115, 117, 98, // PubSub.sub + 115, 99, 114, 105, 98, 101, 40, 109, 115, 103, 32, 61, // scribe(msg = + 62, 32, 109, 115, 103, 46, 110, 97, 109, 101, 32, 61, // > msg.name = + 61, 32, 39, 99, 111, 110, 102, 105, 103, 39, 32, 38, // = 'config' & + 38, 32, 103, 101, 116, 99, 111, 110, 102, 105, 103, 40, // & getconfig( + 41, 41, 59, 10, 32, 32, 125, 44, 32, 91, 93, 41, // ));. }, []) + 59, 10, 10, 32, 32, 105, 102, 32, 40, 33, 117, 115, // ;.. if (!us + 101, 114, 41, 32, 114, 101, 116, 117, 114, 110, 32, 104, // er) return h + 116, 109, 108, 96, 60, 36, 123, 76, 111, 103, 105, 110, // tml`<${Login + 125, 32, 108, 111, 103, 105, 110, 61, 36, 123, 108, 111, // } login=${lo + 103, 105, 110, 125, 32, 47, 62, 96, 59, 10, 10, 32, // gin} />`;.. 32, 114, 101, 116, 117, 114, 110, 32, 104, 116, 109, 108, // return html - 96, 60, 36, 123, 76, 111, 103, 105, 110, 125, 32, 108, // `<${Login} l - 111, 103, 105, 110, 61, 36, 123, 108, 111, 103, 105, 110, // ogin=${login - 125, 32, 47, 62, 96, 59, 10, 32, 32, 99, 111, 110, // } />`;. con - 115, 116, 32, 97, 100, 109, 105, 110, 32, 61, 32, 117, // st admin = u - 115, 101, 114, 32, 61, 61, 32, 39, 97, 100, 109, 105, // ser == 'admi - 110, 39, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, // n';. const - 99, 115, 32, 61, 32, 97, 100, 109, 105, 110, 32, 63, // cs = admin ? - 32, 104, 116, 109, 108, 96, 60, 36, 123, 67, 111, 110, // html`<${Con - 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 125, 32, // figuration} - 99, 111, 110, 102, 105, 103, 61, 36, 123, 99, 111, 110, // config=${con - 102, 105, 103, 125, 32, 47, 62, 96, 32, 58, 32, 39, // fig} />` : ' - 39, 59, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, // ';. return - 104, 116, 109, 108, 96, 10, 60, 36, 123, 78, 97, 118, // html`.<${Nav - 125, 32, 117, 115, 101, 114, 61, 36, 123, 117, 115, 101, // } user=${use - 114, 125, 32, 108, 111, 103, 111, 117, 116, 61, 36, 123, // r} logout=${ - 108, 111, 103, 111, 117, 116, 125, 32, 47, 62, 10, 60, // logout} />.< - 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, 99, // div class="c - 111, 110, 116, 97, 105, 110, 101, 114, 34, 62, 10, 32, // ontainer">. - 32, 60, 36, 123, 72, 101, 114, 111, 125, 32, 47, 62, // <${Hero} /> - 10, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, // .
. - 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, //
<${ - 67, 104, 97, 114, 116, 125, 32, 109, 101, 116, 114, 105, // Chart} metri - 99, 115, 61, 36, 123, 109, 101, 116, 114, 105, 99, 115, // cs=${metrics + 96, 10, 60, 36, 123, 78, 97, 118, 125, 32, 117, 115, // `.<${Nav} us + 101, 114, 61, 36, 123, 117, 115, 101, 114, 125, 32, 108, // er=${user} l + 111, 103, 111, 117, 116, 61, 36, 123, 108, 111, 103, 111, // ogout=${logo + 117, 116, 125, 32, 47, 62, 10, 60, 100, 105, 118, 32, // ut} />.
. .
<${Her + 111, 125, 32, 47, 62, 60, 47, 100, 105, 118, 62, 10, // o} />
. + 32, 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, //
<${Chart} + 32, 47, 62, 60, 47, 100, 105, 118, 62, 10, 32, 32, // />
. + 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, //
${user == ' + 97, 100, 109, 105, 110, 39, 32, 38, 38, 32, 104, 40, // admin' && h( + 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, // Configuratio + 110, 41, 125, 60, 47, 100, 105, 118, 62, 10, 32, 32, // n)}
. + 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, //
<${Messages 125, 32, 47, 62, 60, 47, 100, 105, 118, 62, 10, 32, // } />
. - 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, //
$ - 123, 99, 115, 125, 60, 47, 100, 105, 118, 62, 10, 32, // {cs}
. - 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, //
< - 36, 123, 77, 101, 115, 115, 97, 103, 101, 115, 125, 32, // ${Messages} - 109, 101, 115, 115, 97, 103, 101, 115, 61, 36, 123, 109, // messages=${m - 101, 115, 115, 97, 103, 101, 115, 125, 32, 47, 62, 60, // essages} />< - 47, 100, 105, 118, 62, 10, 32, 32, 60, 47, 100, 105, // /div>. . <${Foot - 101, 114, 125, 32, 47, 62, 10, 60, 47, 100, 105, 118, // er} />.
`;.};..wind - 111, 119, 46, 111, 110, 108, 111, 97, 100, 32, 61, 32, // ow.onload = - 40, 41, 32, 61, 62, 32, 114, 101, 110, 100, 101, 114, // () => render - 40, 104, 40, 65, 112, 112, 41, 44, 32, 100, 111, 99, // (h(App), doc - 117, 109, 101, 110, 116, 46, 98, 111, 100, 121, 41, 59, // ument.body); - 10, 0 // . + 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 36, //
. <$ + 123, 70, 111, 111, 116, 101, 114, 125, 32, 47, 62, 10, // {Footer} />. + 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, 10, //
`;.};. + 10, 119, 105, 110, 100, 111, 119, 46, 111, 110, 108, 111, // .window.onlo + 97, 100, 32, 61, 32, 40, 41, 32, 61, 62, 32, 114, // ad = () => r + 101, 110, 100, 101, 114, 40, 104, 40, 65, 112, 112, 41, // ender(h(App) + 44, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 98, // , document.b + 111, 100, 121, 41, 59, 10, 0 // ody);. }; static const unsigned char v3[] = { 118, 97, 114, 32, 101, 44, 110, 44, 95, 44, 116, 44, // var e,n,_,t, @@ -2282,37 +2375,55 @@ static const unsigned char v4[] = { 35, 100, 101, 102, 59, 32, 98, 111, 114, 100, 101, 114, // #def; border 45, 108, 101, 102, 116, 58, 32, 53, 112, 120, 32, 115, // -left: 5px s 111, 108, 105, 100, 32, 35, 53, 57, 100, 59, 32, 112, // olid #59d; p - 97, 100, 100, 105, 110, 103, 58, 32, 49, 101, 109, 59, // adding: 1em; - 32, 109, 97, 114, 103, 105, 110, 58, 32, 49, 101, 109, // margin: 1em - 32, 48, 59, 32, 125, 10, 46, 114, 111, 119, 32, 123, // 0; }..row { - 32, 109, 97, 114, 103, 105, 110, 58, 32, 49, 37, 32, // margin: 1% - 48, 59, 32, 111, 118, 101, 114, 102, 108, 111, 119, 58, // 0; overflow: - 32, 97, 117, 116, 111, 59, 32, 125, 10, 46, 99, 111, // auto; }..co - 108, 32, 123, 32, 102, 108, 111, 97, 116, 58, 32, 108, // l { float: l - 101, 102, 116, 59, 32, 125, 10, 46, 116, 97, 98, 108, // eft; }..tabl - 101, 44, 32, 46, 99, 49, 50, 32, 123, 32, 119, 105, // e, .c12 { wi - 100, 116, 104, 58, 32, 49, 48, 48, 37, 59, 32, 125, // dth: 100%; } - 10, 46, 99, 49, 49, 32, 123, 32, 119, 105, 100, 116, // ..c11 { widt - 104, 58, 32, 57, 49, 46, 54, 54, 37, 59, 32, 125, // h: 91.66%; } - 10, 46, 99, 49, 48, 32, 123, 32, 119, 105, 100, 116, // ..c10 { widt - 104, 58, 32, 56, 51, 46, 51, 51, 37, 59, 32, 125, // h: 83.33%; } - 10, 46, 99, 57, 32, 123, 32, 119, 105, 100, 116, 104, // ..c9 { width - 58, 32, 55, 53, 37, 59, 32, 125, 10, 46, 99, 56, // : 75%; }..c8 - 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 54, 54, // { width: 66 - 46, 54, 54, 37, 59, 32, 125, 10, 46, 99, 55, 32, // .66%; }..c7 - 123, 32, 119, 105, 100, 116, 104, 58, 32, 53, 56, 46, // { width: 58. - 51, 51, 37, 59, 32, 125, 10, 46, 99, 54, 32, 123, // 33%; }..c6 { - 32, 119, 105, 100, 116, 104, 58, 32, 53, 48, 37, 59, // width: 50%; - 32, 125, 10, 46, 99, 53, 32, 123, 32, 119, 105, 100, // }..c5 { wid - 116, 104, 58, 32, 52, 49, 46, 54, 54, 37, 59, 32, // th: 41.66%; - 125, 10, 46, 99, 52, 32, 123, 32, 119, 105, 100, 116, // }..c4 { widt - 104, 58, 32, 51, 51, 46, 51, 51, 37, 59, 32, 125, // h: 33.33%; } - 10, 46, 99, 51, 32, 123, 32, 119, 105, 100, 116, 104, // ..c3 { width - 58, 32, 50, 53, 37, 59, 32, 125, 10, 46, 99, 50, // : 25%; }..c2 - 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, 54, // { width: 16 - 46, 54, 54, 37, 59, 32, 125, 10, 46, 99, 49, 32, // .66%; }..c1 - 123, 32, 119, 105, 100, 116, 104, 58, 32, 56, 46, 51, // { width: 8.3 - 51, 37, 59, 32, 125, 10, 10, 64, 109, 101, 100, 105, // 3%; }..@medi + 97, 100, 100, 105, 110, 103, 58, 32, 48, 46, 53, 101, // adding: 0.5e + 109, 59, 32, 102, 111, 110, 116, 45, 115, 105, 122, 101, // m; font-size + 58, 32, 57, 48, 37, 59, 32, 109, 97, 114, 103, 105, // : 90%; margi + 110, 58, 32, 49, 101, 109, 32, 48, 59, 32, 125, 10, // n: 1em 0; }. + 46, 114, 111, 119, 32, 123, 32, 100, 105, 115, 112, 108, // .row { displ + 97, 121, 58, 32, 102, 108, 101, 120, 59, 32, 102, 108, // ay: flex; fl + 101, 120, 45, 119, 114, 97, 112, 58, 32, 119, 114, 97, // ex-wrap: wra + 112, 59, 32, 125, 10, 46, 99, 111, 108, 32, 123, 32, // p; }..col { + 109, 97, 114, 103, 105, 110, 58, 32, 48, 59, 32, 112, // margin: 0; p + 97, 100, 100, 105, 110, 103, 58, 32, 48, 59, 32, 111, // adding: 0; o + 118, 101, 114, 102, 108, 111, 119, 58, 32, 97, 117, 116, // verflow: aut + 111, 59, 32, 125, 10, 46, 99, 111, 108, 45, 49, 50, // o; }..col-12 + 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, 48, // { width: 10 + 48, 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 49, // 0%; }..col-1 + 49, 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 57, // 1 { width: 9 + 49, 46, 54, 54, 37, 59, 32, 125, 10, 46, 99, 111, // 1.66%; }..co + 108, 45, 49, 48, 32, 123, 32, 119, 105, 100, 116, 104, // l-10 { width + 58, 32, 56, 51, 46, 51, 51, 37, 59, 32, 125, 10, // : 83.33%; }. + 46, 99, 111, 108, 45, 57, 32, 123, 32, 119, 105, 100, // .col-9 { wid + 116, 104, 58, 32, 55, 53, 37, 59, 32, 125, 10, 46, // th: 75%; }.. + 99, 111, 108, 45, 56, 32, 123, 32, 119, 105, 100, 116, // col-8 { widt + 104, 58, 32, 54, 54, 46, 54, 54, 37, 59, 32, 125, // h: 66.66%; } + 10, 46, 99, 111, 108, 45, 55, 32, 123, 32, 119, 105, // ..col-7 { wi + 100, 116, 104, 58, 32, 53, 56, 46, 51, 51, 37, 59, // dth: 58.33%; + 32, 125, 10, 46, 99, 111, 108, 45, 54, 32, 123, 32, // }..col-6 { + 119, 105, 100, 116, 104, 58, 32, 53, 48, 37, 59, 32, // width: 50%; + 125, 10, 46, 99, 111, 108, 45, 53, 32, 123, 32, 119, // }..col-5 { w + 105, 100, 116, 104, 58, 32, 52, 49, 46, 54, 54, 37, // idth: 41.66% + 59, 32, 125, 10, 46, 99, 111, 108, 45, 52, 32, 123, // ; }..col-4 { + 32, 119, 105, 100, 116, 104, 58, 32, 51, 51, 46, 51, // width: 33.3 + 51, 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 51, // 3%; }..col-3 + 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 50, 53, // { width: 25 + 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 50, 32, // %; }..col-2 + 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, 54, 46, // { width: 16. + 54, 54, 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, // 66%; }..col- + 49, 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 56, // 1 { width: 8 + 46, 51, 51, 37, 59, 32, 125, 10, 10, 46, 116, 111, // .33%; }...to + 112, 105, 99, 32, 123, 32, 98, 97, 99, 107, 103, 114, // pic { backgr + 111, 117, 110, 100, 58, 32, 35, 102, 101, 97, 59, 32, // ound: #fea; + 112, 97, 100, 100, 105, 110, 103, 58, 32, 48, 46, 50, // padding: 0.2 + 101, 109, 32, 49, 101, 109, 59, 32, 98, 111, 114, 100, // em 1em; bord + 101, 114, 45, 114, 97, 100, 105, 117, 115, 58, 32, 48, // er-radius: 0 + 46, 52, 101, 109, 59, 32, 125, 10, 46, 100, 97, 116, // .4em; }..dat + 97, 32, 123, 32, 98, 97, 99, 107, 103, 114, 111, 117, // a { backgrou + 110, 100, 58, 32, 35, 97, 101, 102, 59, 32, 112, 97, // nd: #aef; pa + 100, 100, 105, 110, 103, 58, 32, 48, 46, 50, 101, 109, // dding: 0.2em + 32, 49, 101, 109, 59, 32, 98, 111, 114, 100, 101, 114, // 1em; border + 45, 114, 97, 100, 105, 117, 115, 58, 32, 48, 46, 52, // -radius: 0.4 + 101, 109, 59, 32, 125, 10, 10, 64, 109, 101, 100, 105, // em; }..@medi 97, 32, 40, 109, 105, 110, 45, 119, 105, 100, 116, 104, // a (min-width 58, 32, 49, 51, 49, 48, 112, 120, 41, 32, 123, 32, // : 1310px) { 46, 99, 111, 110, 116, 97, 105, 110, 101, 114, 32, 123, // .container { @@ -2320,7 +2431,7 @@ static const unsigned char v4[] = { 111, 59, 32, 119, 105, 100, 116, 104, 58, 32, 49, 50, // o; width: 12 55, 48, 112, 120, 59, 32, 125, 32, 125, 10, 64, 109, // 70px; } }.@m 101, 100, 105, 97, 32, 40, 109, 97, 120, 45, 119, 105, // edia (max-wi - 100, 116, 104, 58, 32, 56, 55, 48, 112, 120, 41, 32, // dth: 870px) + 100, 116, 104, 58, 32, 57, 50, 48, 112, 120, 41, 32, // dth: 920px) 123, 32, 46, 114, 111, 119, 32, 46, 99, 111, 108, 32, // { .row .col 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, 48, 48, // { width: 100 37, 59, 32, 125, 32, 125, 10, 0 // %; } }. @@ -2657,9 +2768,9 @@ static const struct packed_file { time_t mtime; } packed_files[] = { {"/web_root/index.html", v1, sizeof(v1), 1654357482}, - {"/web_root/main.js", v2, sizeof(v2), 1654374271}, + {"/web_root/main.js", v2, sizeof(v2), 1654437405}, {"/web_root/preact.min.js", v3, sizeof(v3), 1652374364}, - {"/web_root/style.css", v4, sizeof(v4), 1654373337}, + {"/web_root/style.css", v4, sizeof(v4), 1654436558}, {"/web_root/user.png", v5, sizeof(v5), 1626172939}, {NULL, NULL, 0, 0} }; diff --git a/examples/device-dashboard/screenshots/dashboard.png b/examples/device-dashboard/screenshots/dashboard.png index 33aed153..4085d074 100644 Binary files a/examples/device-dashboard/screenshots/dashboard.png and b/examples/device-dashboard/screenshots/dashboard.png differ diff --git a/examples/device-dashboard/web_root/main.js b/examples/device-dashboard/web_root/main.js index e0d980cd..c1f2deb7 100644 --- a/examples/device-dashboard/web_root/main.js +++ b/examples/device-dashboard/web_root/main.js @@ -3,6 +3,23 @@ import {Component, h, html, render, useEffect, useState, useRef} from './preact. const MaxMetricsDataPoints = 50; +// This simple publish/subscribe is used to pass notifications that were +// received from the server, to all child components of the app. +var PubSub = (function() { + var handlers = {}, id = 0; + return { + subscribe: function(fn) { + handlers[id++] = fn; + }, + unsubscribe: function(id) { + delete handlers[id]; + }, + publish: function(data) { + for (var k in handlers) handlers[k](data); + } + }; +})(); + const Nav = props => html`
@@ -41,23 +58,69 @@ const Hero = props => html` using curl command-line utility:

-
curl localhost:8000/api/config/get - get current device configuration
-
curl localhost:8000/api/config/set -d 'value1=7&value2=hello' - set device configuration
-
curl localhost:8000/api/message/send -d 'msg=hello' - send MQTT message
-
curl localhost:8000/api/watch - get notifications: MQTT messages, configuration, sensor data
+
curl localhost:8000/api/config/get
+
curl localhost:8000/api/config/set -d 'value1=7&value2=hello'
+
curl localhost:8000/api/message/send -d 'msg=hello'
+ +

+ A device can send notifications to this dashboard at anytime. Notifications + are sent over Websocket at URI curl localhost:8000/api/watch + as JSON strings {"name": "..", "data": ...} +

`; +const Login = function(props) { + const [user, setUser] = useState(''); + const [pass, setPass] = useState(''); + const login = ev => + fetch( + '/api/login', + {headers: {Authorization: 'Basic ' + btoa(user + ':' + pass)}}) + .then(r => r.json()) + .then(r => r && props.login(r)) + .catch(err => err); + return html` +
+
+

Device Dashboard Login

+
+ setUser(ev.target.value)} value=${user} /> +
+
+ setPass(ev.target.value)} value=${pass} + onchange=${login} /> +
+
+ +
+
+ Valid logins: admin:pass0, user1:pass1, user2:pass2 +
+
+
`; +}; + const Configuration = function(props) { const [url, setUrl] = useState(''); const [pub, setPub] = useState(''); const [sub, setSub] = useState(''); + useEffect(() => { - setUrl(props.config.url); - setPub(props.config.pub); - setSub(props.config.sub); - }, [props.config.url, props.config.pub, props.config.sub]) + const id = PubSub.subscribe(function(msg) { + if (msg.name == 'newconfig') { + setUrl(msg.data.url); + setPub(msg.data.pub); + setSub(msg.data.sub); + } + }); + return PubSub.unsubscribe(id); + }, []); + const update = (name, val) => fetch('/api/config/set', { method: 'post', body: `${name}=${encodeURIComponent(val)}` @@ -65,6 +128,7 @@ const Configuration = function(props) { const updateurl = ev => update('url', url); const updatepub = ev => update('pub', pub); const updatesub = ev => update('sub', sub); + return html`

@@ -105,62 +169,44 @@ const Configuration = function(props) {

`; }; -const Login = function(props) { - const [user, setUser] = useState(''); - const [pass, setPass] = useState(''); - const login = ev => - fetch( - '/api/login', - {headers: {Authorization: 'Basic ' + btoa(user + ':' + pass)}}) - .then(r => r.json()) - .then(r => r && props.login(r)) - .catch(err => err); - return html` -
-
-

Device Dashboard Login

-
- setUser(ev.target.value)} value=${user} /> -
-
- setPass(ev.target.value)} value=${pass} - onchange=${login} /> -
-
- -
-
- Valid logins: admin:pass0, user1:pass1, user2:pass2 -
-
-
`; -}; -const Message = text => html`
${text}
`; +const Message = m => html`
+ topic: ${m.message.topic} + data: ${m.message.data} +
`; const Messages = function(props) { - const [message, setMessage] = useState(''); + const [messages, setMessages] = useState([]); + const [cfg, setCfg] = useState({}); + const [txt, setTxt] = useState(''); + + useEffect(() => { + const id = PubSub.subscribe(function(msg) { + if (msg.name == 'newconfig') setCfg(x => msg.data); + if (msg.name == 'message') setMessages(x => x.concat([msg.data])); + }); + return PubSub.unsubscribe(id); + }, []); + const sendmessage = ev => fetch('/api/message/send', { method: 'post', - body: `message=${encodeURIComponent(message)}` - }).then(r => setMessage('')); + body: `message=${encodeURIComponent(txt)}` + }).then(r => setTxt('')); - const messages = props.messages.map( - text => html`
${text}
`); return html`

MQTT messages

+
+ MQTT server status: ${cfg.connected ? 'connected' : 'diconnected'} +
- ${messages} + ${messages.map(message => h(Message, {message}))}
Publish message: setMessage(ev.target.value)} /> + value=${txt} onchange=${sendmessage} + oninput=${ev => setTxt(ev.target.value)} />
Message gets passed to the device via REST. Then a device sends it to @@ -240,14 +286,22 @@ const SVG = function(props) { const Chart = function(props) { - let xmax = 0, missing = MaxMetricsDataPoints - props.metrics.length; + const [data, setData] = useState([]); + useEffect(() => { + const id = PubSub.subscribe(function(msg) { + if (msg.name != 'metrics') return; + setData(x => x.concat([msg.data]).splice(-MaxMetricsDataPoints)); + }); + return PubSub.unsubscribe(id); + }, []); + + let xmax = 0, missing = MaxMetricsDataPoints - data.length; if (missing > 0) xmax = Math.round(Date.now() / 1000) + missing; return html`

Data Chart

- <${SVG} height=240 width=600 ymin=0 ymax=20 - xmax=${xmax} data=${props.metrics} /> + <${SVG} height=240 width=600 ymin=0 ymax=20 xmax=${xmax} data=${data} />
This chart plots live sensor data, sent by a device via /api/watch. @@ -256,19 +310,17 @@ const Chart = function(props) { }; const App = function(props) { - const [messages, setMessages] = useState([]); - const [metrics, setMetrics] = useState([]); const [user, setUser] = useState(''); - const [config, setConfig] = useState({}); - const refresh = () => fetch('/api/config/get', {headers: {Authorization: ''}}) - .then(r => r.json()) - .then(r => setConfig(r)); + const getconfig = () => + fetch('/api/config/get', {headers: {Authorization: ''}}) + .then(r => r.json()) + .then(r => PubSub.publish({name: 'newconfig', data: r})); const login = function(u) { document.cookie = `access_token=${u.token};path=/;max-age=3600`; setUser(u.user); - refresh(); + return getconfig(); }; const logout = ev => { @@ -276,48 +328,50 @@ const App = function(props) { setUser(''); }; + // Watch for notifications. As soon as a notification arrives, pass it on + // to all subscribed components const watch = function() { - var f = function(reader) { - return reader.read().then(function(result) { - var data = String.fromCharCode.apply(null, result.value); - var msg = JSON.parse(data); - if (msg.name == 'config') { - refresh(); - } else if (msg.name == 'message') { - setMessages(m => m.concat([msg.data])); - } else if (msg.name == 'metrics') { - setMetrics(m => m.concat([msg.data]).splice(-MaxMetricsDataPoints)); + var l = window.location, proto = l.protocol.replace('http', 'ws'); + var tid, wsURI = proto + '//' + l.host + '/api/watch' + var reconnect = function() { + var ws = new WebSocket(wsURI); + ws.onmessage = function(ev) { + try { + var msg = JSON.parse(ev.data); + PubSub.publish(msg); + if (msg.name != 'metrics') console.log('ws->', msg); + } catch (e) { + console.log('Invalid ws frame:', ev.data); // eslint-disable-line } - // console.log(msg); - if (!result.done) return f(reader); - }); + }; + ws.onclose = function() { + clearTimeout(tid); + tid = setTimeout(reconnect, 1000); + }; }; - fetch('/api/watch', {headers: {Authorization: ''}}) - .then(r => r.body.getReader()) - .then(f) - .catch(e => setTimeout(watch, 1000)); + reconnect(); }; useEffect(() => { + // Called once at init time fetch('/api/login', {headers: {Authorization: ''}}) .then(r => r.json()) .then(r => login(r)) .catch(err => setUser('')); - refresh(); watch(); + PubSub.subscribe(msg => msg.name == 'config' && getconfig()); }, []); if (!user) return html`<${Login} login=${login} />`; - const admin = user == 'admin'; - const cs = admin ? html`<${Configuration} config=${config} />` : ''; + return html` <${Nav} user=${user} logout=${logout} />
- <${Hero} />
-
<${Chart} metrics=${metrics} />
-
${cs}
-
<${Messages} messages=${messages} />
+
<${Hero} />
+
<${Chart} />
+
${user == 'admin' && h(Configuration)}
+
<${Messages} />
<${Footer} />
`; diff --git a/examples/device-dashboard/web_root/style.css b/examples/device-dashboard/web_root/style.css index f06a5012..215ddf50 100644 --- a/examples/device-dashboard/web_root/style.css +++ b/examples/device-dashboard/web_root/style.css @@ -17,21 +17,24 @@ a, a:visited, a:active { color: #55f; } .border { border: 1px solid #ddd; } .rounded { border-radius: 0.5em; } .nowrap { white-space: nowrap; } -.msg { background: #def; border-left: 5px solid #59d; padding: 1em; margin: 1em 0; } -.row { margin: 1% 0; overflow: auto; } -.col { float: left; } -.table, .c12 { width: 100%; } -.c11 { width: 91.66%; } -.c10 { width: 83.33%; } -.c9 { width: 75%; } -.c8 { width: 66.66%; } -.c7 { width: 58.33%; } -.c6 { width: 50%; } -.c5 { width: 41.66%; } -.c4 { width: 33.33%; } -.c3 { width: 25%; } -.c2 { width: 16.66%; } -.c1 { width: 8.33%; } +.msg { background: #def; border-left: 5px solid #59d; padding: 0.5em; font-size: 90%; margin: 1em 0; } +.row { display: flex; flex-wrap: wrap; } +.col { margin: 0; padding: 0; overflow: auto; } +.col-12 { width: 100%; } +.col-11 { width: 91.66%; } +.col-10 { width: 83.33%; } +.col-9 { width: 75%; } +.col-8 { width: 66.66%; } +.col-7 { width: 58.33%; } +.col-6 { width: 50%; } +.col-5 { width: 41.66%; } +.col-4 { width: 33.33%; } +.col-3 { width: 25%; } +.col-2 { width: 16.66%; } +.col-1 { width: 8.33%; } + +.topic { background: #fea; padding: 0.2em 1em; border-radius: 0.4em; } +.data { background: #aef; padding: 0.2em 1em; border-radius: 0.4em; } @media (min-width: 1310px) { .container { margin: auto; width: 1270px; } } -@media (max-width: 870px) { .row .col { width: 100%; } } +@media (max-width: 920px) { .row .col { width: 100%; } }