diff --git a/examples/device-dashboard/Makefile b/examples/device-dashboard/Makefile index 423bd428..eaea59bb 100644 --- a/examples/device-dashboard/Makefile +++ b/examples/device-dashboard/Makefile @@ -1,5 +1,5 @@ PROG ?= example -SOURCES ?= ../../mongoose.c main.c net.c packed_fs.c +SOURCES ?= ../../mongoose.c main.c net.c mjson.c packed_fs.c CFLAGS ?= -I../.. -DMG_ENABLE_PACKED_FS=1 -DMG_ENABLE_LINES=1 $(EXTRA) FILES_TO_EMBED ?= $(wildcard web_root/*) ROOT ?= $(realpath $(CURDIR)/../../..) diff --git a/examples/device-dashboard/mjson.c b/examples/device-dashboard/mjson.c new file mode 100644 index 00000000..ced0d89d --- /dev/null +++ b/examples/device-dashboard/mjson.c @@ -0,0 +1,1066 @@ +// Copyright (c) 2018-2020 Cesanta Software Limited +// All rights reserved +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include + +#include "mjson.h" + +#if defined(_MSC_VER) +#define alloca(x) _alloca(x) +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1700 +#define va_copy(x, y) (x) = (y) +#define isinf(x) !_finite(x) +#define isnan(x) _isnan(x) +#endif + +static double mystrtod(const char *str, char **end); + +static int mjson_esc(int c, int esc) { + const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\""; + for (p = esc ? esc1 : esc2; *p != '\0'; p++) { + if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2]; + } + return 0; +} + +static int mjson_escape(int c) { + return mjson_esc(c, 1); +} + +static int mjson_pass_string(const char *s, int len) { + int i; + for (i = 0; i < len; i++) { + if (s[i] == '\\' && i + 1 < len && mjson_escape(s[i + 1])) { + i++; + } else if (s[i] == '\0') { + return MJSON_ERROR_INVALID_INPUT; + } else if (s[i] == '"') { + return i; + } + } + return MJSON_ERROR_INVALID_INPUT; +} + +int mjson(const char *s, int len, mjson_cb_t cb, void *ud) { + enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE; + unsigned char nesting[MJSON_MAX_DEPTH]; + int i, depth = 0; +#define MJSONCALL(ev) \ + if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1; + +// In the ascii table, the distance between `[` and `]` is 2. +// Ditto for `{` and `}`. Hence +2 in the code below. +#define MJSONEOO() \ + do { \ + if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \ + depth--; \ + if (depth == 0) { \ + MJSONCALL(tok); \ + return i + 1; \ + } \ + } while (0) + + for (i = 0; i < len; i++) { + int start = i; + unsigned char c = ((unsigned char *) s)[i]; + int tok = c; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue; + // printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting); + switch (expecting) { + case S_VALUE: + if (c == '{') { + if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP; + nesting[depth++] = c; + expecting = S_KEY; + break; + } else if (c == '[') { + if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP; + nesting[depth++] = c; + break; + } else if (c == ']' && depth > 0) { // Empty array + MJSONEOO(); + } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) { + i += 3; + tok = MJSON_TOK_TRUE; + } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) { + i += 3; + tok = MJSON_TOK_NULL; + } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) { + i += 4; + tok = MJSON_TOK_FALSE; + } else if (c == '-' || ((c >= '0' && c <= '9'))) { + char *end = NULL; + mystrtod(&s[i], &end); + if (end != NULL) i += (int) (end - &s[i] - 1); + tok = MJSON_TOK_NUMBER; + } else if (c == '"') { + int n = mjson_pass_string(&s[i + 1], len - i - 1); + if (n < 0) return n; + i += n + 1; + tok = MJSON_TOK_STRING; + } else { + return MJSON_ERROR_INVALID_INPUT; + } + if (depth == 0) { + MJSONCALL(tok); + return i + 1; + } + expecting = S_COMMA_OR_EOO; + break; + + case S_KEY: + if (c == '"') { + int n = mjson_pass_string(&s[i + 1], len - i - 1); + if (n < 0) return n; + i += n + 1; + tok = MJSON_TOK_KEY; + expecting = S_COLON; + } else if (c == '}') { // Empty object + MJSONEOO(); + expecting = S_COMMA_OR_EOO; + } else { + return MJSON_ERROR_INVALID_INPUT; + } + break; + + case S_COLON: + if (c == ':') { + expecting = S_VALUE; + } else { + return MJSON_ERROR_INVALID_INPUT; + } + break; + + case S_COMMA_OR_EOO: + if (depth <= 0) return MJSON_ERROR_INVALID_INPUT; + if (c == ',') { + expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE; + } else if (c == ']' || c == '}') { + MJSONEOO(); + } else { + return MJSON_ERROR_INVALID_INPUT; + } + break; + } + MJSONCALL(tok); + } + return MJSON_ERROR_INVALID_INPUT; +} + +struct msjon_get_data { + const char *path; // Lookup json path + int pos; // Current path position + int d1; // Current depth of traversal + int d2; // Expected depth of traversal + int i1; // Index in an array + int i2; // Expected index in an array + int obj; // If the value is array/object, offset where it starts + const char **tokptr; // Destination + int *toklen; // Destination length + int tok; // Returned token +}; + +#include + +static int plen1(const char *s) { + int i = 0, n = 0; + while (s[i] != '\0' && s[i] != '.' && s[i] != '[') + n++, i += s[i] == '\\' ? 2 : 1; + // printf("PLEN: s: [%s], [%.*s] => %d\n", s, i, s, n); + return n; +} + +static int plen2(const char *s) { + int i = 0, n = 0; + while (s[i] != '\0' && s[i] != '.' && s[i] != '[') + n++, i += s[i] == '\\' ? 2 : 1; + // printf("PLEN: s: [%s], [%.*s] => %d\n", s, i, s, n); + return i; +} + +static int kcmp(const char *a, const char *b, int n) { + int i = 0, j = 0, r = 0; + for (i = 0, j = 0; j < n; i++, j++) { + if (b[i] == '\\') i++; + if ((r = a[j] - b[i]) != 0) return r; + } + // printf("KCMP: a: [%.*s], b:[%.*s] ==> %d\n", n, a, i, b, r); + return r; +} + +static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) { + struct msjon_get_data *d = (struct msjon_get_data *) ud; +#if 0 + printf("--> %2x %2d %2d %2d %2d\t %2d %2d\t'%s' '%s' '%s' '%s'\n", tok, d->d1, + d->d2, d->i1, d->i2, (int) off, (int) d->pos, s, d->path, s + off, + d->path + d->pos); +#endif + if (d->tok != MJSON_TOK_INVALID) return 1; // Found + if (tok == '{' || tok == '[') { + if (d->d1 < d->d2) d->obj = -1; + if (d->d1 == d->d2) d->obj = off; + if (d->d1 == d->d2 && tok == '[' && d->path[d->pos] == '[') { + d->i1 = 0; + d->i2 = (int) mystrtod(&d->path[d->pos + 1], NULL); + if (d->i1 == d->i2) { + while (d->path[d->pos] && d->path[d->pos] != ']') d->pos++; + if (d->path[d->pos] == ']') d->pos++; + d->d2++; + } + } + d->d1++; + } else if (tok == '}' || tok == ']') { + if (tok == ']' && d->d1 == d->d2) d->i1 = 0; + d->d1--; + // printf("X %s %d %d %d %d %d\n", d->path + d->pos, d->d1, d->d2, d->i1, + // d->i2, d->obj); + if (!d->path[d->pos] && d->d1 == d->d2 && d->obj != -1) { + d->tok = tok - 2; + if (d->tokptr) *d->tokptr = s + d->obj; + if (d->toklen) *d->toklen = off - d->obj + 1; + return 1; + } + } else if (tok == ',' && d->d1 == d->d2 && d->pos && + d->path[d->pos - 1] == ']') { + return 1; // Not found in the current elem array + } else if (tok == ',' && d->d1 == d->d2 + 1 && d->path[d->pos] == '[') { + // printf("GG '%s' '%s'\n", d->path, &d->path[d->pos]); + d->i1++; + if (d->i1 == d->i2) { + while (d->path[d->pos] && d->path[d->pos] != ']') d->pos++; + if (d->path[d->pos] == ']') d->pos++; + d->d2++; + } + } else if (tok == MJSON_TOK_KEY && d->d1 == d->d2 + 1 && + d->path[d->pos] == '.' && s[off] == '"' && + s[off + len - 1] == '"' && + plen1(&d->path[d->pos + 1]) == len - 2 && + kcmp(s + off + 1, &d->path[d->pos + 1], len - 2) == 0) { + d->d2++; + d->pos += plen2(&d->path[d->pos + 1]) + 1; + } else if (tok == MJSON_TOK_KEY && d->d1 == d->d2) { + return 1; // Exhausted path, not found + } else if (MJSON_TOK_IS_VALUE(tok)) { + // printf("T %d %d %d %d %d\n", tok, d->d1, d->d2, d->i1, d->i2); + if (d->d1 == d->d2 && d->i1 == d->i2 && !d->path[d->pos]) { + d->tok = tok; + if (d->tokptr) *d->tokptr = s + off; + if (d->toklen) *d->toklen = len; + return 1; + } + } + return 0; +} + +int mjson_find(const char *s, int n, const char *jp, const char **tp, int *tl) { + struct msjon_get_data data = {jp, 1, 0, 0, 0, + 0, -1, tp, tl, MJSON_TOK_INVALID}; + if (jp[0] != '$') return MJSON_TOK_INVALID; + if (mjson(s, n, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID; + return data.tok; +} + +int mjson_get_number(const char *s, int len, const char *path, double *v) { + const char *p; + int tok, n; + if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) { + if (v != NULL) *v = mystrtod(p, NULL); + } + return tok == MJSON_TOK_NUMBER ? 1 : 0; +} + +int mjson_get_bool(const char *s, int len, const char *path, int *v) { + int tok = mjson_find(s, len, path, NULL, NULL); + if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1; + if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0; + return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0; +} + +static unsigned char unhex(unsigned char c) { + return (c >= '0' && c <= '9') ? (unsigned char) (c - '0') + : (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7') + : (unsigned char) (c - 'W'); +} + +static unsigned char mjson_unhex_nimble(const char *s) { + unsigned char *u = (unsigned char *) s; + return (unsigned char) (((unsigned char) (unhex(u[0]) << 4)) | unhex(u[1])); +} + +static int mjson_unescape(const char *s, int len, char *to, int n) { + int i, j; + for (i = 0, j = 0; i < len && j < n; i++, j++) { + if (s[i] == '\\' && i + 5 < len && s[i + 1] == 'u') { + // \uXXXX escape. We could process a simple one-byte chars + // \u00xx from the ASCII range. More complex chars would require + // dragging in a UTF8 library, which is too much for us + if (s[i + 2] != '0' || s[i + 3] != '0') return -1; // Too much, give up + ((unsigned char *) to)[j] = mjson_unhex_nimble(s + i + 4); + i += 5; + } else if (s[i] == '\\' && i + 1 < len) { + int c = mjson_esc(s[i + 1], 0); + if (c == 0) return -1; + to[j] = (char) (unsigned char) c; + i++; + } else { + to[j] = s[i]; + } + } + if (j >= n) return -1; + if (n > 0) to[j] = '\0'; + return j; +} + +int mjson_get_string(const char *s, int len, const char *path, char *to, + int n) { + const char *p; + int sz; + if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1; + return mjson_unescape(p + 1, sz - 2, to, n); +} + +int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) { + const char *p; + int i, j, sz; + if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1; + for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) { + ((unsigned char *) to)[j] = mjson_unhex_nimble(p + i + 1); + } + if (j < n) to[j] = '\0'; + return j; +} + +#if MJSON_ENABLE_BASE64 +static unsigned char mjson_base64rev(int c) { + if (c >= 'A' && c <= 'Z') { + return (unsigned char) (c - 'A'); + } else if (c >= 'a' && c <= 'z') { + return (unsigned char) (c + 26 - 'a'); + } else if (c >= '0' && c <= '9') { + return (unsigned char) (c + 52 - '0'); + } else if (c == '+') { + return 62; + } else if (c == '/') { + return 63; + } else { + return 64; + } +} + +int mjson_base64_dec(const char *src, int n, char *dst, int dlen) { + const char *end = src + n; + int len = 0; + while (src + 3 < end && len < dlen) { + unsigned char a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]), + c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]); + dst[len++] = (char) (unsigned char) ((a << 2) | (b >> 4)); + if (src[2] != '=' && len < dlen) { + dst[len++] = (char) (unsigned char) ((b << 4) | (c >> 2)); + if (src[3] != '=' && len < dlen) { + dst[len++] = (char) (unsigned char) ((c << 6) | d); + } + } + src += 4; + } + if (len < dlen) dst[len] = '\0'; + return len; +} + +int mjson_get_base64(const char *s, int len, const char *path, char *to, + int n) { + const char *p; + int sz; + if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0; + return mjson_base64_dec(p + 1, sz - 2, to, n); +} +#endif // MJSON_ENABLE_BASE64 + +#if MJSON_ENABLE_NEXT +struct nextdata { + int off, len, depth, t, vo, arrayindex; + int *koff, *klen, *voff, *vlen, *vtype; +}; + +static int next_cb(int tok, const char *s, int off, int len, void *ud) { + struct nextdata *d = (struct nextdata *) ud; + // int i; + switch (tok) { + case '{': + case '[': + if (d->depth == 0 && tok == '[') d->arrayindex = 0; + if (d->depth == 1 && off > d->off) { + d->vo = off; + d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY; + if (d->voff) *d->voff = off; + if (d->vtype) *d->vtype = d->t; + } + d->depth++; + break; + case '}': + case ']': + d->depth--; + if (d->depth == 1 && d->vo) { + d->len = off + len; + if (d->vlen) *d->vlen = d->len - d->vo; + if (d->arrayindex >= 0) { + if (d->koff) *d->koff = d->arrayindex; // koff holds array index + if (d->klen) *d->klen = 0; // klen holds 0 + } + return 1; + } + if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++; + break; + case ',': + case ':': + break; + case MJSON_TOK_KEY: + if (d->depth == 1 && d->off < off) { + if (d->koff) *d->koff = off; // And report back to the user + if (d->klen) *d->klen = len; // If we have to + } + break; + default: + if (d->depth != 1) break; + // If we're iterating over the array + if (off > d->off) { + d->len = off + len; + if (d->vlen) *d->vlen = len; // value length + if (d->voff) *d->voff = off; // value offset + if (d->vtype) *d->vtype = tok; // value type + if (d->arrayindex >= 0) { + if (d->koff) *d->koff = d->arrayindex; // koff holds array index + if (d->klen) *d->klen = 0; // klen holds 0 + } + return 1; + } + if (d->arrayindex >= 0) d->arrayindex++; + break; + } + (void) s; + return 0; +} + +int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff, + int *vlen, int *vtype) { + struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype}; + mjson(s, n, next_cb, &d); + return d.len; +} +#endif + +#if MJSON_ENABLE_PRINT +int mjson_print_fixed_buf(const char *ptr, int len, void *fndata) { + struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fndata; + int i, left = fb->size - 1 - fb->len; + if (left < len) len = left; + for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i]; + fb->len += len; + fb->ptr[fb->len] = '\0'; + return len; +} + +// This function allocates memory in chunks of size MJSON_DYNBUF_CHUNK +// to decrease memory fragmentation, when many calls are executed to +// print e.g. a base64 string or a hex string. +int mjson_print_dynamic_buf(const char *ptr, int len, void *fndata) { + char *s, *buf = *(char **) fndata; + size_t curlen = buf == NULL ? 0 : strlen(buf); + size_t new_size = curlen + (size_t) len + 1 + MJSON_DYNBUF_CHUNK; + new_size -= new_size % MJSON_DYNBUF_CHUNK; + + if ((s = (char *) MJSON_REALLOC(buf, new_size)) == NULL) { + return 0; + } else { + memcpy(s + curlen, ptr, (size_t) len); + s[curlen + (size_t) len] = '\0'; + *(char **) fndata = s; + return len; + } +} + +int mjson_snprintf(char *buf, size_t len, const char *fmt, ...) { + va_list ap; + struct mjson_fixedbuf fb = {buf, (int) len, 0}; + va_start(ap, fmt); + mjson_vprintf(mjson_print_fixed_buf, &fb, fmt, &ap); + va_end(ap); + return fb.len; +} + +char *mjson_aprintf(const char *fmt, ...) { + va_list ap; + char *result = NULL; + va_start(ap, fmt); + mjson_vprintf(mjson_print_dynamic_buf, &result, fmt, &ap); + va_end(ap); + return result; +} + +int mjson_print_null(const char *ptr, int len, void *userdata) { + (void) ptr; + (void) userdata; + return len; +} + +int mjson_print_buf(mjson_print_fn_t fn, void *fnd, const char *buf, int len) { + return fn(buf, len, fnd); +} + +int mjson_print_long(mjson_print_fn_t fn, void *fnd, long val, int is_signed) { + unsigned long v = (unsigned long) val, s = 0, n, i; + char buf[20], t; + if (is_signed && val < 0) buf[s++] = '-', v = (unsigned long) (-val); + // This loop prints a number in reverse order. I guess this is because we + // write numbers from right to left: least significant digit comes last. + // Maybe because we use Arabic numbers, and Arabs write RTL? + for (n = 0; v > 0; v /= 10) buf[s + n++] = "0123456789"[v % 10]; + // Reverse a string + for (i = 0; i < n / 2; i++) + t = buf[s + i], buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t; + if (val == 0) buf[n++] = '0'; // Handle special case + return fn(buf, (int) (s + n), fnd); +} + +int mjson_print_int(mjson_print_fn_t fn, void *fnd, int v, int s) { + return mjson_print_long(fn, fnd, s ? (long) v : (long) (unsigned) v, s); +} + +static int addexp(char *buf, int e, int sign) { + int n = 0; + buf[n++] = 'e'; + buf[n++] = (char) sign; + if (e > 400) return 0; + if (e < 10) buf[n++] = '0'; + if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100); + if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10); + buf[n++] = (char) (e + '0'); + return n; +} + +int mjson_print_dbl(mjson_print_fn_t fn, void *fnd, double d, int width) { + char buf[40]; + int i, s = 0, n = 0, e = 0; + double t, mul, saved; + if (d == 0.0) return fn("0", 1, fnd); + if (isinf(d)) return fn(d > 0 ? "inf" : "-inf", d > 0 ? 3 : 4, fnd); + if (isnan(d)) return fn("nan", 3, fnd); + if (d < 0.0) d = -d, buf[s++] = '-'; + + // Round + saved = d; + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0; + while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0; + for (i = 0, t = mul * 5; i < width; i++) t /= 10.0; + d += t; + // Calculate exponent, and 'mul' for scientific representation + mul = 1.0; + while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++; + while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--; + // printf(" --> %g %d %g %g\n", saved, e, t, mul); + + if (e >= width) { + struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0}; + n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width); + // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, fb.len, fb.ptr); + n += addexp(buf + s + n, e, '+'); + return fn(buf, s + n, fnd); + } else if (e <= -width) { + struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0}; + n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width); + // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, fb.len, fb.ptr); + n += addexp(buf + s + n, -e, '-'); + return fn(buf, s + n, fnd); + } else { + for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) { + int ch = (int) (d / t); + if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + t /= 10.0; + } + // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf); + if (n == 0) buf[s++] = '0'; + while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0; + if (s + n < (int) sizeof(buf)) buf[n + s++] = '.'; + // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf); + for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) { + int ch = (int) (d / t); + buf[s + n++] = (char) (ch + '0'); + d -= ch * t; + t /= 10.0; + } + } + while (n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeros + if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot + buf[s + n] = '\0'; + return fn(buf, s + n, fnd); +} + +int mjson_print_str(mjson_print_fn_t fn, void *fnd, const char *s, int len) { + int i, n = fn("\"", 1, fnd); + for (i = 0; i < len; i++) { + char c = (char) (unsigned char) mjson_escape(s[i]); + if (c) { + n += fn("\\", 1, fnd); + n += fn(&c, 1, fnd); + } else { + n += fn(&s[i], 1, fnd); + } + } + return n + fn("\"", 1, fnd); +} + +#if MJSON_ENABLE_BASE64 +int mjson_print_b64(mjson_print_fn_t fn, void *fnd, const unsigned char *s, + int n) { + const char *t = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int i, len = fn("\"", 1, fnd); + for (i = 0; i < n; i += 3) { + int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0; + char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='}; + if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)]; + if (i + 2 < n) buf[3] = t[c & 63]; + len += fn(buf, sizeof(buf), fnd); + } + return len + fn("\"", 1, fnd); +} +#endif /* MJSON_ENABLE_BASE64 */ + +int mjson_vprintf(mjson_print_fn_t fn, void *fnd, const char *fmt, + va_list *ap) { + int i = 0, n = 0; + while (fmt[i] != '\0') { + if (fmt[i] == '%') { + char fc = fmt[++i]; + int is_long = 0; + if (fc == 'l') { + is_long = 1; + fc = fmt[i + 1]; + } + if (fc == 'Q') { + char *buf = va_arg(*ap, char *); + n += mjson_print_str(fn, fnd, buf ? buf : "", + buf ? (int) strlen(buf) : 0); + } else if (strncmp(&fmt[i], ".*Q", 3) == 0) { + int len = va_arg(*ap, int); + char *buf = va_arg(*ap, char *); + n += mjson_print_str(fn, fnd, buf, len); + i += 2; + } else if (fc == 'd' || fc == 'u') { + int is_signed = (fc == 'd'); + if (is_long) { + long val = va_arg(*ap, long); + n += mjson_print_long(fn, fnd, val, is_signed); + i++; + } else { + int val = va_arg(*ap, int); + n += mjson_print_int(fn, fnd, val, is_signed); + } + } else if (fc == 'B') { + const char *s = va_arg(*ap, int) ? "true" : "false"; + n += mjson_print_buf(fn, fnd, s, (int) strlen(s)); + } else if (fc == 's') { + char *buf = va_arg(*ap, char *); + n += mjson_print_buf(fn, fnd, buf, (int) strlen(buf)); + } else if (strncmp(&fmt[i], ".*s", 3) == 0) { + int len = va_arg(*ap, int); + char *buf = va_arg(*ap, char *); + n += mjson_print_buf(fn, fnd, buf, len); + i += 2; + } else if (fc == 'g') { + n += mjson_print_dbl(fn, fnd, va_arg(*ap, double), 6); + } else if (strncmp(&fmt[i], ".*g", 3) == 0) { + int width = va_arg(*ap, int); + n += mjson_print_dbl(fn, fnd, va_arg(*ap, double), width); + i += 2; +#if MJSON_ENABLE_BASE64 + } else if (fc == 'V') { + int len = va_arg(*ap, int); + const char *buf = va_arg(*ap, const char *); + n += mjson_print_b64(fn, fnd, (unsigned char *) buf, len); +#endif + } else if (fc == 'H') { + const char *hex = "0123456789abcdef"; + int j, len = va_arg(*ap, int); + const unsigned char *p = va_arg(*ap, const unsigned char *); + n += fn("\"", 1, fnd); + for (j = 0; j < len; j++) { + n += fn(&hex[(p[j] >> 4) & 15], 1, fnd); + n += fn(&hex[p[j] & 15], 1, fnd); + } + n += fn("\"", 1, fnd); + } else if (fc == 'M') { + mjson_vprint_fn_t vfn = va_arg(*ap, mjson_vprint_fn_t); + n += vfn(fn, fnd, ap); + } + i++; + } else { + n += mjson_print_buf(fn, fnd, &fmt[i++], 1); + } + } + return n; +} + +int mjson_printf(mjson_print_fn_t fn, void *fnd, const char *fmt, ...) { + va_list ap; + int len; + va_start(ap, fmt); + len = mjson_vprintf(fn, fnd, fmt, &ap); + va_end(ap); + return len; +} +#endif /* MJSON_ENABLE_PRINT */ + +static int is_digit(int c) { + return c >= '0' && c <= '9'; +} + +/* NOTE: strtod() implementation by Yasuhiro Matsumoto. */ +static double mystrtod(const char *str, char **end) { + double d = 0.0; + int sign = 1, n = 0; + const char *p = str, *a = str; + + /* decimal part */ + if (*p == '-') { + sign = -1; + ++p; + } else if (*p == '+') { + ++p; + } + if (is_digit(*p)) { + d = (double) (*p++ - '0'); + while (*p && is_digit(*p)) { + d = d * 10.0 + (double) (*p - '0'); + ++p; + ++n; + } + a = p; + } else if (*p != '.') { + goto done; + } + d *= sign; + + /* fraction part */ + if (*p == '.') { + double f = 0.0; + double base = 0.1; + ++p; + + if (is_digit(*p)) { + while (*p && is_digit(*p)) { + f += base * (*p - '0'); + base /= 10.0; + ++p; + ++n; + } + } + d += f * sign; + a = p; + } + + /* exponential part */ + if ((*p == 'E') || (*p == 'e')) { + int i, e = 0, neg = 0; + p++; + if (*p == '-') p++, neg++; + if (*p == '+') p++; + while (is_digit(*p)) e = e * 10 + *p++ - '0'; + if (neg) e = -e; +#if 0 + if (d == 2.2250738585072011 && e == -308) { + d = 0.0; + a = p; + goto done; + } + if (d == 2.2250738585072012 && e <= -308) { + d *= 1.0e-308; + a = p; + goto done; + } +#endif + for (i = 0; i < e; i++) d *= 10; + for (i = 0; i < -e; i++) d /= 10; + a = p; + } else if (p > str && !is_digit(*(p - 1))) { + a = str; + goto done; + } + +done: + if (end) *end = (char *) a; + return d; +} + +#if MJSON_ENABLE_MERGE +int mjson_merge(const char *s, int n, const char *s2, int n2, + mjson_print_fn_t fn, void *userdata) { + int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0; + if (n < 2) return len; + len += fn("{", 1, userdata); + while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) { + char *path = (char *) alloca((size_t) klen + 1); + const char *val; + memcpy(path, "$.", 2); + memcpy(path + 2, s + koff + 1, (size_t) (klen - 2)); + path[klen] = '\0'; + if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) { + if (t2 == MJSON_TOK_NULL) continue; // null deletes the key + } else { + val = s + voff; // Key is not found in the update. Copy the old value. + } + if (comma) len += fn(",", 1, userdata); + len += fn(s + koff, klen, userdata); + len += fn(":", 1, userdata); + if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) { + len += mjson_merge(s + voff, vlen, val, k, fn, userdata); + } else { + if (t2 != MJSON_TOK_INVALID) vlen = k; + len += fn(val, vlen, userdata); + } + comma = 1; + } + // Add missing keys + off = 0; + while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) { + char *path = (char *) alloca((size_t) klen + 1); + const char *val; + if (t == MJSON_TOK_NULL) continue; + memcpy(path, "$.", 2); + memcpy(path + 2, s2 + koff + 1, (size_t) (klen - 2)); + path[klen] = '\0'; + if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue; + if (comma) len += fn(",", 1, userdata); + len += fn(s2 + koff, klen, userdata); + len += fn(":", 1, userdata); + len += fn(s2 + voff, vlen, userdata); + comma = 1; + } + len += fn("}", 1, userdata); + return len; +} +#endif // MJSON_ENABLE_MERGE + +#if MJSON_ENABLE_PRETTY +struct prettydata { + int level; + int len; + int prev; + const char *pad; + int padlen; + mjson_print_fn_t fn; + void *userdata; +}; + +static int pretty_cb(int ev, const char *s, int off, int len, void *ud) { + struct prettydata *d = (struct prettydata *) ud; + int i; + switch (ev) { + case '{': + case '[': + d->level++; + d->len += d->fn(s + off, len, d->userdata); + break; + case '}': + case ']': + d->level--; + if (d->prev != '[' && d->prev != '{' && d->padlen > 0) { + d->len += d->fn("\n", 1, d->userdata); + for (i = 0; i < d->level; i++) + d->len += d->fn(d->pad, d->padlen, d->userdata); + } + d->len += d->fn(s + off, len, d->userdata); + break; + case ',': + d->len += d->fn(s + off, len, d->userdata); + if (d->padlen > 0) { + d->len += d->fn("\n", 1, d->userdata); + for (i = 0; i < d->level; i++) + d->len += d->fn(d->pad, d->padlen, d->userdata); + } + break; + case ':': + d->len += d->fn(s + off, len, d->userdata); + if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata); + break; + case MJSON_TOK_KEY: + if (d->prev == '{' && d->padlen > 0) { + d->len += d->fn("\n", 1, d->userdata); + for (i = 0; i < d->level; i++) + d->len += d->fn(d->pad, d->padlen, d->userdata); + } + d->len += d->fn(s + off, len, d->userdata); + break; + default: + if (d->prev == '[' && d->padlen > 0) { + d->len += d->fn("\n", 1, d->userdata); + for (i = 0; i < d->level; i++) + d->len += d->fn(d->pad, d->padlen, d->userdata); + } + d->len += d->fn(s + off, len, d->userdata); + break; + } + d->prev = ev; + return 0; +} + +int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn, + void *userdata) { + struct prettydata d = {0, 0, 0, pad, (int) strlen(pad), fn, userdata}; + if (mjson(s, n, pretty_cb, &d) < 0) return -1; + return d.len; +} +#endif // MJSON_ENABLE_PRETTY + +#if MJSON_ENABLE_RPC +struct jsonrpc_ctx jsonrpc_default_context; + +int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) { + int i = 0, j = 0, ni = 0, nj = 0; + while (i < n1 || j < n2) { + if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) { + i++, j++; + } else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) { + ni = i, nj = j + 1, i++; + } else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) { + i = ni, j = nj; + } else { + return 0; + } + } + return 1; +} + +void jsonrpc_return_errorv(struct jsonrpc_request *r, int code, + const char *message, const char *data_fmt, + va_list *ap) { + if (r->id_len == 0) return; + mjson_printf(r->fn, r->fndata, + "{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len, + r->id, code, message == NULL ? "" : message); + if (data_fmt != NULL) { + mjson_printf(r->fn, r->fndata, ",\"data\":"); + mjson_vprintf(r->fn, r->fndata, data_fmt, ap); + } + mjson_printf(r->fn, r->fndata, "}}\n"); +} + +void jsonrpc_return_error(struct jsonrpc_request *r, int code, + const char *message, const char *data_fmt, ...) { + va_list ap; + va_start(ap, data_fmt); + jsonrpc_return_errorv(r, code, message, data_fmt, &ap); + va_end(ap); +} + +void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt, + va_list *ap) { + if (r->id_len == 0) return; + mjson_printf(r->fn, r->fndata, "{\"id\":%.*s,\"result\":", r->id_len, r->id); + if (result_fmt != NULL) { + mjson_vprintf(r->fn, r->fndata, result_fmt, ap); + } else { + mjson_printf(r->fn, r->fndata, "%s", "null"); + } + mjson_printf(r->fn, r->fndata, "}\n"); +} + +void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt, + ...) { + va_list ap; + va_start(ap, result_fmt); + jsonrpc_return_successv(r, result_fmt, &ap); + va_end(ap); +} + +void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *buf, int len, + mjson_print_fn_t fn, void *fndata, void *ud) { + const char *result = NULL, *error = NULL; + int result_sz = 0, error_sz = 0; + struct jsonrpc_method *m = NULL; + struct jsonrpc_request r = {ctx, buf, len, 0, 0, 0, 0, 0, 0, fn, fndata, ud}; + + // Is is a response frame? + mjson_find(buf, len, "$.result", &result, &result_sz); + if (result == NULL) mjson_find(buf, len, "$.error", &error, &error_sz); + if (result_sz > 0 || error_sz > 0) { + if (ctx->response_cb) ctx->response_cb(buf, len, ctx->response_cb_data); + return; + } + + // Method must exist and must be a string + if (mjson_find(buf, len, "$.method", &r.method, &r.method_len) != + MJSON_TOK_STRING) { + mjson_printf(fn, fndata, "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n", + len, buf); + return; + } + + // id and params are optional + mjson_find(buf, len, "$.id", &r.id, &r.id_len); + mjson_find(buf, len, "$.params", &r.params, &r.params_len); + + for (m = ctx->methods; m != NULL; m = m->next) { + if (mjson_globmatch(m->method, m->method_sz, r.method + 1, + r.method_len - 2) > 0) { + if (r.params == NULL) r.params = ""; + m->cb(&r); + break; + } + } + if (m == NULL) { + jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL); + } +} + +static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fndata, + va_list *ap) { + struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *); + struct jsonrpc_method *m; + int len = 0; + for (m = ctx->methods; m != NULL; m = m->next) { + if (m != ctx->methods) len += mjson_print_buf(fn, fndata, ",", 1); + len += mjson_print_str(fn, fndata, m->method, (int) strlen(m->method)); + } + return len; +} + +void jsonrpc_list(struct jsonrpc_request *r) { + jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->ctx); +} + +void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb, + void *response_cb_data) { + ctx->methods = NULL; + ctx->response_cb = response_cb; + ctx->response_cb_data = response_cb_data; +} + +void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) { + struct jsonrpc_ctx *ctx = &jsonrpc_default_context; + jsonrpc_ctx_init(ctx, response_cb, userdata); + jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, jsonrpc_list); +} +#endif // MJSON_ENABLE_RPC diff --git a/examples/device-dashboard/mjson.h b/examples/device-dashboard/mjson.h new file mode 100644 index 00000000..084b320a --- /dev/null +++ b/examples/device-dashboard/mjson.h @@ -0,0 +1,208 @@ +// Copyright (c) 2018-2020 Cesanta Software Limited +// All rights reserved +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef MJSON_H +#define MJSON_H + +#include +#include +#include + +#ifndef MJSON_ENABLE_PRINT +#define MJSON_ENABLE_PRINT 1 +#endif + +#ifndef MJSON_ENABLE_RPC +#define MJSON_ENABLE_RPC 1 +#endif + +#ifndef MJSON_ENABLE_BASE64 +#define MJSON_ENABLE_BASE64 1 +#endif + +#ifndef MJSON_ENABLE_MERGE +#define MJSON_ENABLE_MERGE 1 +#endif + +#ifndef MJSON_ENABLE_PRETTY +#define MJSON_ENABLE_PRETTY 1 +#endif + +#ifndef MJSON_ENABLE_NEXT +#define MJSON_ENABLE_NEXT 1 +#endif + +#ifndef MJSON_RPC_LIST_NAME +#define MJSON_RPC_LIST_NAME "rpc.list" +#endif + +#ifndef MJSON_DYNBUF_CHUNK +#define MJSON_DYNBUF_CHUNK 256 // Allocation granularity for print_dynamic_buf +#endif + +#ifndef MJSON_REALLOC +#define MJSON_REALLOC realloc +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define MJSON_ERROR_INVALID_INPUT (-1) +#define MJSON_ERROR_TOO_DEEP (-2) +#define MJSON_TOK_INVALID 0 +#define MJSON_TOK_KEY 1 +#define MJSON_TOK_STRING 11 +#define MJSON_TOK_NUMBER 12 +#define MJSON_TOK_TRUE 13 +#define MJSON_TOK_FALSE 14 +#define MJSON_TOK_NULL 15 +#define MJSON_TOK_ARRAY 91 +#define MJSON_TOK_OBJECT 123 +#define MJSON_TOK_IS_VALUE(t) ((t) > 10 && (t) < 20) + +typedef int (*mjson_cb_t)(int ev, const char *s, int off, int len, void *ud); + +#ifndef MJSON_MAX_DEPTH +#define MJSON_MAX_DEPTH 20 +#endif + +int mjson(const char *s, int len, mjson_cb_t cb, void *ud); +int mjson_find(const char *s, int len, const char *jp, const char **, int *); +int mjson_get_number(const char *s, int len, const char *path, double *v); +int mjson_get_bool(const char *s, int len, const char *path, int *v); +int mjson_get_string(const char *s, int len, const char *path, char *to, int n); +int mjson_get_hex(const char *s, int len, const char *path, char *to, int n); + +#if MJSON_ENABLE_NEXT +int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff, + int *vlen, int *vtype); +#endif + +#if MJSON_ENABLE_BASE64 +int mjson_get_base64(const char *s, int len, const char *path, char *to, int n); +int mjson_base64_dec(const char *src, int n, char *dst, int dlen); +#endif + +#if MJSON_ENABLE_PRINT +typedef int (*mjson_print_fn_t)(const char *buf, int len, void *userdata); +typedef int (*mjson_vprint_fn_t)(mjson_print_fn_t, void *, va_list *); + +struct mjson_fixedbuf { + char *ptr; + int size, len; +}; + +int mjson_printf(mjson_print_fn_t, void *, const char *fmt, ...); +int mjson_vprintf(mjson_print_fn_t, void *, const char *fmt, va_list *ap); +int mjson_print_str(mjson_print_fn_t, void *, const char *s, int len); +int mjson_print_int(mjson_print_fn_t, void *, int value, int is_signed); +int mjson_print_long(mjson_print_fn_t, void *, long value, int is_signed); +int mjson_print_buf(mjson_print_fn_t fn, void *, const char *buf, int len); +int mjson_print_dbl(mjson_print_fn_t fn, void *, double, int width); + +int mjson_print_null(const char *ptr, int len, void *userdata); +int mjson_print_fixed_buf(const char *ptr, int len, void *userdata); +int mjson_print_dynamic_buf(const char *ptr, int len, void *userdata); + +int mjson_snprintf(char *buf, size_t len, const char *fmt, ...); +char *mjson_aprintf(const char *fmt, ...); + +#if MJSON_ENABLE_PRETTY +int mjson_pretty(const char *, int, const char *, mjson_print_fn_t, void *); +#endif + +#if MJSON_ENABLE_MERGE +int mjson_merge(const char *, int, const char *, int, mjson_print_fn_t, void *); +#endif + +#endif // MJSON_ENABLE_PRINT + +#if MJSON_ENABLE_RPC + +void jsonrpc_init(mjson_print_fn_t, void *userdata); +int mjson_globmatch(const char *s1, int n1, const char *s2, int n2); + +struct jsonrpc_request { + struct jsonrpc_ctx *ctx; + const char *frame; // Points to the whole frame + int frame_len; // Frame length + const char *params; // Points to the "params" in the request frame + int params_len; // Length of the "params" + const char *id; // Points to the "id" in the request frame + int id_len; // Length of the "id" + const char *method; // Points to the "method" in the request frame + int method_len; // Length of the "method" + mjson_print_fn_t fn; // Printer function + void *fndata; // Printer function data + void *userdata; // Callback's user data as specified at export time +}; + +struct jsonrpc_method { + const char *method; + int method_sz; + void (*cb)(struct jsonrpc_request *); + struct jsonrpc_method *next; +}; + +// Main RPC context, stores current request information and a list of +// exported RPC methods. +struct jsonrpc_ctx { + struct jsonrpc_method *methods; + mjson_print_fn_t response_cb; + void *response_cb_data; +}; + +// Registers function fn under the given name within the given RPC context +#define jsonrpc_ctx_export(ctx, name, fn) \ + do { \ + static struct jsonrpc_method m = {(name), sizeof(name) - 1, (fn), 0}; \ + m.next = (ctx)->methods; \ + (ctx)->methods = &m; \ + } while (0) + +void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t, void *); +void jsonrpc_return_error(struct jsonrpc_request *r, int code, + const char *message, const char *data_fmt, ...); +void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt, + ...); +void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *req, int req_sz, + mjson_print_fn_t fn, void *fndata, void *userdata); + +extern struct jsonrpc_ctx jsonrpc_default_context; +extern void jsonrpc_list(struct jsonrpc_request *r); + +#define jsonrpc_export(name, fn) \ + jsonrpc_ctx_export(&jsonrpc_default_context, (name), (fn)) + +#define jsonrpc_process(buf, len, fn, fnd, ud) \ + jsonrpc_ctx_process(&jsonrpc_default_context, (buf), (len), (fn), (fnd), (ud)) + +#define JSONRPC_ERROR_INVALID -32700 /* Invalid JSON was received */ +#define JSONRPC_ERROR_NOT_FOUND -32601 /* The method does not exist */ +#define JSONRPC_ERROR_BAD_PARAMS -32602 /* Invalid params passed */ +#define JSONRPC_ERROR_INTERNAL -32603 /* Internal JSON-RPC error */ + +#endif // MJSON_ENABLE_RPC +#ifdef __cplusplus +} +#endif +#endif // MJSON_H diff --git a/examples/device-dashboard/net.c b/examples/device-dashboard/net.c index a0d05335..e3fefa06 100644 --- a/examples/device-dashboard/net.c +++ b/examples/device-dashboard/net.c @@ -1,6 +1,7 @@ // Copyright (c) 2020-2022 Cesanta Software Limited // All rights reserved +#include "mjson.h" #include "mongoose.h" #define MQTT_SERVER "mqtt://broker.hivemq.com:1883" @@ -66,12 +67,14 @@ static struct user *getuser(struct mg_http_message *hm) { static void send_notification(struct mg_mgr *mgr, const char *name, const char *data) { struct mg_connection *c; + char *msg = mjson_aprintf("{%Q:%Q,%Q:%s}", "name", name, "data", data); for (c = mgr->conns; c != NULL; c = c->next) { if (c->label[0] != 'W') continue; // c->is_hexdumping = 1; - mg_ws_printf(c, WEBSOCKET_OP_TEXT, "{\"name\": \"%s\", \"data\": %s}", name, - data); + mg_ws_send(c, msg, strlen(msg), WEBSOCKET_OP_TEXT); + if (strcmp(name, "metrics") != 0) MG_INFO(("%lu -> %s", c->id, msg)); } + free(msg); } // Send simulated metrics data to the dashboard, for chart rendering @@ -80,23 +83,25 @@ static void timer_metrics_fn(void *param) { mg_snprintf(buf, sizeof(buf), "[ %lu, %d ]", (unsigned long) time(NULL), 10 + (int) ((double) rand() * 10 / RAND_MAX)); 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) { +static void mqtt_fn(struct mg_connection *c, int ev, void *ev_data, void *fnd) { if (ev == MG_EV_MQTT_OPEN) { s_connected = true; - // c->is_hexdumping = 1; - mg_mqtt_sub(s_mqtt, mg_str(s_config.sub), 1); + c->is_hexdumping = 1; + mg_mqtt_sub(s_mqtt, mg_str(s_config.sub), 2); 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(c->mgr, "message", buf); + struct mg_mqtt_message *mm = ev_data; + char *message = mjson_aprintf( + "{%Q: %.*Q,%Q:%.*Q,%Q:%d}", "topic", (int) mm->topic.len, mm->topic.ptr, + "data", (int) mm->data.len, mm->data.ptr, "qos", mm->qos); + send_notification(c->mgr, "message", message); + free(message); + } else if (ev == MG_EV_MQTT_CMD) { + struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data; + MG_DEBUG(("cmd %d qos %d", mm->cmd, mm->qos)); } else if (ev == MG_EV_CLOSE) { s_mqtt = NULL; if (s_connected) { @@ -136,12 +141,11 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data, // All URIs starting with /api/ must be authenticated 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\",\"connected\":%s}", - s_config.url, s_config.pub, s_config.sub, - s_connected ? "true" : "false"); - mg_http_printf_chunk(c, ""); + char *response = mjson_aprintf("{%Q:%Q,%Q:%Q,%Q:%Q,%Q:%B}", "url", + s_config.url, "pub", s_config.pub, "sub", + s_config.sub, "connected", s_connected); + mg_http_reply(c, 200, NULL, "%s\n", response); + free(response); } else if (mg_http_match_uri(hm, "/api/config/set")) { // Admins only if (strcmp(u->name, "admin") == 0) { @@ -166,13 +170,13 @@ void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data, 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, - u->token); - mg_http_printf_chunk(c, ""); + char *response = + mjson_aprintf("{%Q:%Q,%Q:%Q}", "user", u->name, "token", u->token); + mg_http_reply(c, 200, NULL, "%s\n", response); + free(response); } else { struct mg_http_serve_opts opts = {0}; -#if 1 +#if 0 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 b46422bd..3a2cb04d 100644 --- a/examples/device-dashboard/packed_fs.c +++ b/examples/device-dashboard/packed_fs.c @@ -134,235 +134,455 @@ static const unsigned char v2[] = { 34, 62, 108, 111, 103, 111, 117, 116, 60, 47, 97, 62, // ">logout 10, 32, 32, 32, 32, 60, 47, 100, 105, 118, 62, 10, // . . 32, 32, 60, 47, 100, 105, 118, 62, 10, 60, 47, 100, // .`;..const - 32, 70, 111, 111, 116, 101, 114, 32, 61, 32, 112, 114, // Footer = pr - 111, 112, 115, 32, 61, 62, 32, 104, 116, 109, 108, 96, // ops => html` - 10, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, // .
. - 32, 32, 67, 111, 112, 121, 114, 105, 103, 104, 116, 32, // Copyright - 40, 99, 41, 32, 89, 111, 117, 114, 32, 67, 111, 109, // (c) Your Com - 112, 97, 110, 121, 10, 60, 47, 100, 105, 118, 62, 10, // pany.
. - 96, 59, 10, 10, 10, 99, 111, 110, 115, 116, 32, 72, // `;...const H - 101, 114, 111, 32, 61, 32, 112, 114, 111, 112, 115, 32, // ero = props - 61, 62, 32, 104, 116, 109, 108, 96, 10, 60, 100, 105, // => html`..
. - 60, 104, 49, 32, 115, 116, 121, 108, 101, 61, 34, 109, //

Interac - 116, 105, 118, 101, 32, 68, 101, 118, 105, 99, 101, 32, // tive Device - 68, 97, 115, 104, 98, 111, 97, 114, 100, 60, 47, 104, // Dashboard..

. - 84, 104, 105, 115, 32, 100, 101, 118, 105, 99, 101, 32, // This device - 100, 97, 115, 104, 98, 111, 97, 114, 100, 32, 105, 115, // dashboard is - 32, 100, 101, 118, 101, 108, 111, 112, 101, 100, 32, 119, // developed w - 105, 116, 104, 32, 109, 111, 100, 101, 114, 110, 32, 97, // ith modern a - 110, 100, 32, 99, 111, 109, 112, 97, 99, 116, 32, 80, // nd compact P - 114, 101, 97, 99, 116, 32, 102, 114, 97, 109, 101, 119, // react framew - 111, 114, 107, 44, 10, 32, 32, 105, 110, 32, 111, 114, // ork,. in or - 100, 101, 114, 32, 116, 111, 32, 102, 105, 116, 32, 111, // der to fit o - 110, 32, 97, 32, 118, 101, 114, 121, 32, 115, 109, 97, // n a very sma - 108, 108, 32, 100, 101, 118, 105, 99, 101, 115, 46, 32, // ll devices. - 84, 104, 105, 115, 32, 105, 115, 10, 32, 32, 97, 32, // This is. a - 60, 97, 32, 104, 114, 101, 102, 61, 34, 104, 116, 116, // hybrid - 115, 101, 114, 118, 101, 114, 60, 47, 97, 62, 32, 119, // server w - 104, 105, 99, 104, 10, 32, 32, 112, 114, 111, 118, 105, // hich. provi - 100, 101, 115, 32, 98, 111, 116, 104, 32, 115, 116, 97, // des both sta - 116, 105, 99, 32, 97, 110, 100, 32, 100, 121, 110, 97, // tic and dyna - 109, 105, 99, 32, 99, 111, 110, 116, 101, 110, 116, 46, // mic content. - 32, 32, 83, 116, 97, 116, 105, 99, 32, 102, 105, 108, // Static fil - 101, 115, 44, 32, 108, 105, 107, 101, 32, 67, 83, 83, // es, like CSS - 47, 74, 83, 47, 72, 84, 77, 76, 10, 32, 32, 111, // /JS/HTML. o - 114, 32, 105, 109, 97, 103, 101, 115, 44, 32, 97, 114, // r images, ar - 101, 32, 99, 111, 109, 112, 105, 108, 101, 100, 32, 105, // e compiled i - 110, 116, 111, 32, 116, 104, 101, 32, 115, 101, 114, 118, // nto the serv - 101, 114, 32, 98, 105, 110, 97, 114, 121, 46, 10, 10, // er binary... - 32, 32, 84, 104, 105, 115, 32, 85, 73, 32, 117, 115, // This UI us - 101, 115, 32, 116, 104, 101, 32, 82, 69, 83, 84, 32, // es the REST - 65, 80, 73, 32, 105, 109, 112, 108, 101, 109, 101, 110, // API implemen - 116, 101, 100, 32, 98, 121, 32, 116, 104, 101, 32, 100, // ted by the d - 101, 118, 105, 99, 101, 44, 32, 119, 104, 105, 99, 104, // evice, which - 32, 121, 111, 117, 32, 99, 97, 110, 32, 101, 120, 97, // you can exa - 109, 105, 110, 101, 10, 32, 32, 117, 115, 105, 110, 103, // mine. using - 32, 32, 60, 99, 111, 100, 101, 62, 99, 117, 114, 108, // curl - 60, 47, 99, 111, 100, 101, 62, 32, 99, 111, 109, 109, // comm - 97, 110, 100, 45, 108, 105, 110, 101, 32, 117, 116, 105, // and-line uti - 108, 105, 116, 121, 58, 10, 32, 32, 60, 47, 112, 62, // lity:.

- 10, 10, 32, 32, 60, 100, 105, 118, 62, 60, 99, 111, // ..
curl loca - 108, 104, 111, 115, 116, 58, 56, 48, 48, 48, 47, 97, // lhost:8000/a - 112, 105, 47, 99, 111, 110, 102, 105, 103, 47, 103, 101, // pi/config/ge - 116, 60, 47, 99, 111, 100, 101, 62, 32, 60, 47, 100, // t .
< - 99, 111, 100, 101, 62, 99, 117, 114, 108, 32, 108, 111, // code>curl lo - 99, 97, 108, 104, 111, 115, 116, 58, 56, 48, 48, 48, // calhost:8000 - 47, 97, 112, 105, 47, 99, 111, 110, 102, 105, 103, 47, // /api/config/ - 115, 101, 116, 32, 45, 100, 32, 39, 118, 97, 108, 117, // set -d 'valu - 101, 49, 61, 55, 38, 118, 97, 108, 117, 101, 50, 61, // e1=7&value2= - 104, 101, 108, 108, 111, 39, 60, 47, 99, 111, 100, 101, // hello'
. < - 100, 105, 118, 62, 60, 99, 111, 100, 101, 62, 99, 117, // div>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, 109, 101, // :8000/api/me - 115, 115, 97, 103, 101, 47, 115, 101, 110, 100, 32, 45, // ssage/send - - 100, 32, 39, 109, 115, 103, 61, 104, 101, 108, 108, 111, // d 'msg=hello - 39, 60, 47, 99, 111, 100, 101, 62, 32, 60, 47, 100, // ' ..

. - 32, 65, 32, 100, 101, 118, 105, 99, 101, 32, 99, 97, // A device ca - 110, 32, 115, 101, 110, 100, 32, 110, 111, 116, 105, 102, // n send notif - 105, 99, 97, 116, 105, 111, 110, 115, 32, 116, 111, 32, // ications to - 116, 104, 105, 115, 32, 100, 97, 115, 104, 98, 111, 97, // this dashboa - 114, 100, 32, 97, 116, 32, 97, 110, 121, 116, 105, 109, // rd at anytim - 101, 46, 32, 78, 111, 116, 105, 102, 105, 99, 97, 116, // e. Notificat - 105, 111, 110, 115, 10, 32, 32, 97, 114, 101, 32, 115, // ions. are s - 101, 110, 116, 32, 111, 118, 101, 114, 32, 87, 101, 98, // ent over Web - 115, 111, 99, 107, 101, 116, 32, 97, 116, 32, 85, 82, // socket at UR - 73, 32, 60, 99, 111, 100, 101, 62, 99, 117, 114, 108, // I curl + 105, 118, 62, 96, 59, 10, 10, 10, 99, 111, 110, 115, // iv>`;...cons + 116, 32, 72, 101, 114, 111, 32, 61, 32, 112, 114, 111, // t Hero = pro + 112, 115, 32, 61, 62, 32, 104, 116, 109, 108, 96, 10, // ps => html`. + 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, //

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

Inte + 114, 97, 99, 116, 105, 118, 101, 32, 68, 101, 118, 105, // ractive Devi + 99, 101, 32, 68, 97, 115, 104, 98, 111, 97, 114, 100, // ce Dashboard + 60, 47, 104, 49, 62, 10, 10, 32, 32, 60, 112, 62, //

..

+ 10, 32, 32, 84, 104, 105, 115, 32, 100, 101, 118, 105, // . This devi + 99, 101, 32, 100, 97, 115, 104, 98, 111, 97, 114, 100, // ce dashboard + 32, 105, 115, 32, 100, 101, 118, 101, 108, 111, 112, 101, // is develope + 100, 32, 119, 105, 116, 104, 32, 109, 111, 100, 101, 114, // d with moder + 110, 32, 97, 110, 100, 32, 99, 111, 109, 112, 97, 99, // n and compac + 116, 32, 80, 114, 101, 97, 99, 116, 32, 102, 114, 97, // t Preact fra + 109, 101, 119, 111, 114, 107, 44, 10, 32, 32, 105, 110, // mework,. in + 32, 111, 114, 100, 101, 114, 32, 116, 111, 32, 102, 105, // order to fi + 116, 32, 111, 110, 32, 97, 32, 118, 101, 114, 121, 32, // t on a very + 115, 109, 97, 108, 108, 32, 100, 101, 118, 105, 99, 101, // small device + 115, 46, 32, 84, 104, 105, 115, 32, 105, 115, 10, 32, // s. This is. + 32, 97, 32, 60, 97, 32, 104, 114, 101, 102, 61, 34, // a hybr + 105, 100, 32, 115, 101, 114, 118, 101, 114, 60, 47, 97, // id server which. pr + 111, 118, 105, 100, 101, 115, 32, 98, 111, 116, 104, 32, // ovides both + 115, 116, 97, 116, 105, 99, 32, 97, 110, 100, 32, 100, // static and d + 121, 110, 97, 109, 105, 99, 32, 99, 111, 110, 116, 101, // ynamic conte + 110, 116, 46, 32, 32, 83, 116, 97, 116, 105, 99, 32, // nt. Static + 102, 105, 108, 101, 115, 44, 32, 108, 105, 107, 101, 32, // files, like + 67, 83, 83, 47, 74, 83, 47, 72, 84, 77, 76, 10, // CSS/JS/HTML. + 32, 32, 111, 114, 32, 105, 109, 97, 103, 101, 115, 44, // or images, + 32, 97, 114, 101, 32, 99, 111, 109, 112, 105, 108, 101, // are compile + 100, 32, 105, 110, 116, 111, 32, 116, 104, 101, 32, 115, // d into the s + 101, 114, 118, 101, 114, 32, 98, 105, 110, 97, 114, 121, // erver binary + 46, 10, 10, 32, 32, 84, 104, 105, 115, 32, 85, 73, // ... This UI + 32, 117, 115, 101, 115, 32, 116, 104, 101, 32, 82, 69, // uses the RE + 83, 84, 32, 65, 80, 73, 32, 105, 109, 112, 108, 101, // ST API imple + 109, 101, 110, 116, 101, 100, 32, 98, 121, 32, 116, 104, // mented by th + 101, 32, 100, 101, 118, 105, 99, 101, 44, 32, 119, 104, // e device, wh + 105, 99, 104, 32, 121, 111, 117, 32, 99, 97, 110, 32, // ich you can + 101, 120, 97, 109, 105, 110, 101, 10, 32, 32, 117, 115, // examine. us + 105, 110, 103, 32, 32, 60, 99, 111, 100, 101, 62, 99, // ing c + 117, 114, 108, 60, 47, 99, 111, 100, 101, 62, 32, 99, // url c + 111, 109, 109, 97, 110, 100, 45, 108, 105, 110, 101, 32, // ommand-line + 117, 116, 105, 108, 105, 116, 121, 58, 10, 32, 32, 60, // utility:. < + 47, 112, 62, 10, 10, 32, 32, 60, 100, 105, 118, 62, // /p>..

+ 60, 99, 111, 100, 101, 62, 99, 117, 114, 108, 32, 108, // curl l + 111, 99, 97, 108, 104, 111, 115, 116, 58, 56, 48, 48, // ocalhost:800 + 48, 47, 97, 112, 105, 47, 99, 111, 110, 102, 105, 103, // 0/api/config + 47, 103, 101, 116, 60, 47, 99, 111, 100, 101, 62, 32, // /get + 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, //
. curl 32, 108, 111, 99, 97, 108, 104, 111, 115, 116, 58, 56, // localhost:8 - 48, 48, 48, 47, 97, 112, 105, 47, 119, 97, 116, 99, // 000/api/watc - 104, 60, 47, 99, 111, 100, 101, 62, 10, 32, 32, 97, // h. a - 115, 32, 74, 83, 79, 78, 32, 115, 116, 114, 105, 110, // s JSON strin - 103, 115, 32, 60, 99, 111, 100, 101, 62, 123, 34, 110, // gs {"n - 97, 109, 101, 34, 58, 32, 34, 46, 46, 34, 44, 32, // ame": "..", - 34, 100, 97, 116, 97, 34, 58, 32, 46, 46, 46, 125, // "data": ...} - 60, 47, 99, 111, 100, 101, 62, 10, 32, 32, 60, 47, // . .
.`;..cons - 116, 32, 76, 111, 103, 105, 110, 32, 61, 32, 102, 117, // t Login = fu - 110, 99, 116, 105, 111, 110, 40, 112, 114, 111, 112, 115, // nction(props - 41, 32, 123, 10, 32, 32, 99, 111, 110, 115, 116, 32, // ) {. const - 91, 117, 115, 101, 114, 44, 32, 115, 101, 116, 85, 115, // [user, setUs - 101, 114, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, // er] = useSta - 116, 101, 40, 39, 39, 41, 59, 10, 32, 32, 99, 111, // te('');. co - 110, 115, 116, 32, 91, 112, 97, 115, 115, 44, 32, 115, // nst [pass, s - 101, 116, 80, 97, 115, 115, 93, 32, 61, 32, 117, 115, // etPass] = us - 101, 83, 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, // eState('');. - 32, 32, 99, 111, 110, 115, 116, 32, 108, 111, 103, 105, // const logi - 110, 32, 61, 32, 101, 118, 32, 61, 62, 10, 32, 32, // n = ev =>. - 32, 32, 32, 32, 102, 101, 116, 99, 104, 40, 10, 32, // fetch(. - 32, 32, 32, 32, 32, 32, 32, 32, 32, 39, 47, 97, // '/a - 112, 105, 47, 108, 111, 103, 105, 110, 39, 44, 10, 32, // pi/login',. - 32, 32, 32, 32, 32, 32, 32, 32, 32, 123, 104, 101, // {he - 97, 100, 101, 114, 115, 58, 32, 123, 65, 117, 116, 104, // aders: {Auth - 111, 114, 105, 122, 97, 116, 105, 111, 110, 58, 32, 39, // orization: ' - 66, 97, 115, 105, 99, 32, 39, 32, 43, 32, 98, 116, // Basic ' + bt - 111, 97, 40, 117, 115, 101, 114, 32, 43, 32, 39, 58, // oa(user + ': - 39, 32, 43, 32, 112, 97, 115, 115, 41, 125, 125, 41, // ' + pass)}}) - 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, // . . - 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 114, 46, // then(r => r. - 106, 115, 111, 110, 40, 41, 41, 10, 32, 32, 32, 32, // json()). - 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, // .then( - 114, 32, 61, 62, 32, 114, 32, 38, 38, 32, 112, 114, // r => r && pr - 111, 112, 115, 46, 108, 111, 103, 105, 110, 40, 114, 41, // ops.login(r) - 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // ). - 46, 99, 97, 116, 99, 104, 40, 101, 114, 114, 32, 61, // .catch(err = - 62, 32, 101, 114, 114, 41, 59, 10, 32, 32, 114, 101, // > err);. re - 116, 117, 114, 110, 32, 104, 116, 109, 108, 96, 10, 60, // turn html`.< - 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, 114, // div class="r - 111, 117, 110, 100, 101, 100, 32, 98, 111, 114, 100, 101, // ounded borde - 114, 34, 32, 115, 116, 121, 108, 101, 61, 34, 109, 97, // r" style="ma - 120, 45, 119, 105, 100, 116, 104, 58, 32, 52, 56, 48, // x-width: 480 - 112, 120, 59, 32, 109, 97, 114, 103, 105, 110, 58, 32, // px; margin: - 48, 32, 97, 117, 116, 111, 59, 32, 109, 97, 114, 103, // 0 auto; marg - 105, 110, 45, 116, 111, 112, 58, 32, 53, 101, 109, 59, // in-top: 5em; - 32, 98, 97, 99, 107, 103, 114, 111, 117, 110, 100, 58, // background: - 32, 35, 101, 101, 101, 59, 32, 34, 62, 10, 32, 32, // #eee; ">. - 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, //
.

De - 118, 105, 99, 101, 32, 68, 97, 115, 104, 98, 111, 97, // vice Dashboa - 114, 100, 32, 76, 111, 103, 105, 110, 32, 60, 47, 104, // rd Login .
. setUs - 101, 114, 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, // er(ev.target - 46, 118, 97, 108, 117, 101, 41, 125, 32, 118, 97, 108, // .value)} val - 117, 101, 61, 36, 123, 117, 115, 101, 114, 125, 32, 47, // ue=${user} / - 62, 10, 32, 32, 32, 32, 60, 47, 100, 105, 118, 62, // >.
- 10, 32, 32, 32, 32, 60, 100, 105, 118, 32, 115, 116, // .
. - 32, 32, 32, 32, 32, 32, 60, 105, 110, 112, 117, 116, // - 32, 115, 101, 116, 80, 97, 115, 115, 40, 101, 118, 46, // setPass(ev. - 116, 97, 114, 103, 101, 116, 46, 118, 97, 108, 117, 101, // target.value - 41, 125, 32, 118, 97, 108, 117, 101, 61, 36, 123, 112, // )} value=${p - 97, 115, 115, 125, 10, 32, 32, 32, 32, 32, 32, 32, // ass}. - 32, 111, 110, 99, 104, 97, 110, 103, 101, 61, 36, 123, // onchange=${ - 108, 111, 103, 105, 110, 125, 32, 47, 62, 10, 32, 32, // login} />. - 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 32, //
. - 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, //
. - 60, 98, 117, 116, 116, 111, 110, 32, 99, 108, 97, 115, //
. < - 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, 99, // div style="c - 111, 108, 111, 114, 58, 32, 35, 55, 55, 55, 59, 32, // olor: #777; - 109, 97, 114, 103, 105, 110, 45, 116, 111, 112, 58, 32, // margin-top: - 50, 101, 109, 59, 34, 62, 10, 32, 32, 32, 32, 32, // 2em;">. - 32, 86, 97, 108, 105, 100, 32, 108, 111, 103, 105, 110, // Valid login - 115, 58, 32, 97, 100, 109, 105, 110, 58, 112, 97, 115, // s: admin:pas - 115, 48, 44, 32, 117, 115, 101, 114, 49, 58, 112, 97, // s0, user1:pa - 115, 115, 49, 44, 32, 117, 115, 101, 114, 50, 58, 112, // ss1, user2:p - 97, 115, 115, 50, 10, 32, 32, 32, 32, 60, 47, 100, // ass2. .

- 10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, // .
`;.}; - 10, 10, 10, 99, 111, 110, 115, 116, 32, 67, 111, 110, // ...const Con - 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 32, 61, // figuration = + 48, 48, 48, 47, 97, 112, 105, 47, 99, 111, 110, 102, // 000/api/conf + 105, 103, 47, 115, 101, 116, 32, 45, 100, 32, 39, 118, // ig/set -d 'v + 97, 108, 117, 101, 49, 61, 55, 38, 118, 97, 108, 117, // alue1=7&valu + 101, 50, 61, 104, 101, 108, 108, 111, 39, 60, 47, 99, // e2=hello'

. + 32, 32, 60, 100, 105, 118, 62, 60, 99, 111, 100, 101, //
curl localh + 111, 115, 116, 58, 56, 48, 48, 48, 47, 97, 112, 105, // ost:8000/api + 47, 109, 101, 115, 115, 97, 103, 101, 47, 115, 101, 110, // /message/sen + 100, 32, 45, 100, 32, 39, 109, 115, 103, 61, 104, 101, // d -d 'msg=he + 108, 108, 111, 39, 60, 47, 99, 111, 100, 101, 62, 32, // llo' + 60, 47, 100, 105, 118, 62, 10, 10, 32, 32, 60, 112, //
..

. A device + 32, 99, 97, 110, 32, 115, 101, 110, 100, 32, 110, 111, // can send no + 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 32, // tifications + 116, 111, 32, 116, 104, 105, 115, 32, 100, 97, 115, 104, // to this dash + 98, 111, 97, 114, 100, 32, 97, 116, 32, 97, 110, 121, // board at any + 116, 105, 109, 101, 46, 32, 78, 111, 116, 105, 102, 105, // time. Notifi + 99, 97, 116, 105, 111, 110, 115, 10, 32, 32, 97, 114, // cations. ar + 101, 32, 115, 101, 110, 116, 32, 111, 118, 101, 114, 32, // e sent over + 87, 101, 98, 115, 111, 99, 107, 101, 116, 32, 97, 116, // Websocket at + 32, 85, 82, 73, 32, 60, 99, 111, 100, 101, 62, 99, // URI c + 117, 114, 108, 32, 108, 111, 99, 97, 108, 104, 111, 115, // url localhos + 116, 58, 56, 48, 48, 48, 47, 97, 112, 105, 47, 119, // t:8000/api/w + 97, 116, 99, 104, 60, 47, 99, 111, 100, 101, 62, 10, // atch. + 32, 32, 97, 115, 32, 74, 83, 79, 78, 32, 115, 116, // as JSON st + 114, 105, 110, 103, 115, 32, 60, 99, 111, 100, 101, 62, // rings + 123, 34, 110, 97, 109, 101, 34, 58, 32, 34, 46, 46, // {"name": ".. + 34, 44, 32, 34, 100, 97, 116, 97, 34, 58, 32, 46, // ", "data": . + 46, 46, 125, 60, 47, 99, 111, 100, 101, 62, 10, 32, // ..}. + 32, 60, 47, 112, 62, 10, 60, 47, 100, 105, 118, 62, //

. + 10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 10, 99, // .`;..c + 111, 110, 115, 116, 32, 76, 111, 103, 105, 110, 32, 61, // onst Login = 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, 117, 114, 108, 44, 32, 115, 101, 116, // st [url, set - 85, 114, 108, 93, 32, 61, 32, 117, 115, 101, 83, 116, // Url] = useSt - 97, 116, 101, 40, 39, 39, 41, 59, 10, 32, 32, 99, // ate('');. c - 111, 110, 115, 116, 32, 91, 112, 117, 98, 44, 32, 115, // onst [pub, s - 101, 116, 80, 117, 98, 93, 32, 61, 32, 117, 115, 101, // etPub] = use + 115, 116, 32, 91, 117, 115, 101, 114, 44, 32, 115, 101, // st [user, se + 116, 85, 115, 101, 114, 93, 32, 61, 32, 117, 115, 101, // tUser] = use 83, 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, 32, // State('');. - 32, 99, 111, 110, 115, 116, 32, 91, 115, 117, 98, 44, // const [sub, - 32, 115, 101, 116, 83, 117, 98, 93, 32, 61, 32, 117, // setSub] = u + 32, 99, 111, 110, 115, 116, 32, 91, 112, 97, 115, 115, // const [pass + 44, 32, 115, 101, 116, 80, 97, 115, 115, 93, 32, 61, // , setPass] = + 32, 117, 115, 101, 83, 116, 97, 116, 101, 40, 39, 39, // useState('' + 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, 108, // );. const l + 111, 103, 105, 110, 32, 61, 32, 101, 118, 32, 61, 62, // ogin = ev => + 10, 32, 32, 32, 32, 32, 32, 102, 101, 116, 99, 104, // . fetch + 40, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // (. + 39, 47, 97, 112, 105, 47, 108, 111, 103, 105, 110, 39, // '/api/login' + 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // ,. + 123, 104, 101, 97, 100, 101, 114, 115, 58, 32, 123, 65, // {headers: {A + 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, // uthorization + 58, 32, 39, 66, 97, 115, 105, 99, 32, 39, 32, 43, // : 'Basic ' + + 32, 98, 116, 111, 97, 40, 117, 115, 101, 114, 32, 43, // btoa(user + + 32, 39, 58, 39, 32, 43, 32, 112, 97, 115, 115, 41, // ':' + pass) + 125, 125, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, // }}). + 32, 32, 46, 116, 104, 101, 110, 40, 114, 32, 61, 62, // .then(r => + 32, 114, 46, 106, 115, 111, 110, 40, 41, 41, 10, 32, // r.json()). + 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, // .th + 101, 110, 40, 114, 32, 61, 62, 32, 114, 32, 38, 38, // en(r => r && + 32, 112, 114, 111, 112, 115, 46, 108, 111, 103, 105, 110, // props.login + 40, 114, 41, 41, 10, 32, 32, 32, 32, 32, 32, 32, // (r)). + 32, 32, 32, 46, 99, 97, 116, 99, 104, 40, 101, 114, // .catch(er + 114, 32, 61, 62, 32, 101, 114, 114, 41, 59, 10, 32, // r => err);. + 32, 114, 101, 116, 117, 114, 110, 32, 104, 116, 109, 108, // return html + 96, 10, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, // `.
+ 10, 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, // .
. + 60, 104, 49, 32, 115, 116, 121, 108, 101, 61, 34, 99, //

Device Dash + 98, 111, 97, 114, 100, 32, 76, 111, 103, 105, 110, 32, // board Login + 60, 47, 104, 49, 62, 10, 32, 32, 32, 32, 60, 100, //

. . < + 105, 110, 112, 117, 116, 32, 116, 121, 112, 101, 61, 39, // input type=' + 116, 101, 120, 116, 39, 32, 112, 108, 97, 99, 101, 104, // text' placeh + 111, 108, 100, 101, 114, 61, 39, 78, 97, 109, 101, 39, // older='Name' + 32, 115, 116, 121, 108, 101, 61, 34, 119, 105, 100, 116, // style="widt + 104, 58, 32, 49, 48, 48, 37, 59, 34, 10, 32, 32, // h: 100%;". + 32, 32, 32, 32, 32, 32, 111, 110, 105, 110, 112, 117, // oninpu + 116, 61, 36, 123, 101, 118, 32, 61, 62, 32, 115, 101, // t=${ev => se + 116, 85, 115, 101, 114, 40, 101, 118, 46, 116, 97, 114, // tUser(ev.tar + 103, 101, 116, 46, 118, 97, 108, 117, 101, 41, 125, 32, // get.value)} + 118, 97, 108, 117, 101, 61, 36, 123, 117, 115, 101, 114, // value=${user + 125, 32, 47, 62, 10, 32, 32, 32, 32, 60, 47, 100, // } />. .
. setPass( + 101, 118, 46, 116, 97, 114, 103, 101, 116, 46, 118, 97, // ev.target.va + 108, 117, 101, 41, 125, 32, 118, 97, 108, 117, 101, 61, // lue)} value= + 36, 123, 112, 97, 115, 115, 125, 10, 32, 32, 32, 32, // ${pass}. + 32, 32, 32, 32, 111, 110, 99, 104, 97, 110, 103, 101, // onchange + 61, 36, 123, 108, 111, 103, 105, 110, 125, 32, 47, 62, // =${login} /> + 10, 32, 32, 32, 32, 60, 47, 100, 105, 118, 62, 10, // .
. + 32, 32, 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, //
. + 32, 32, 32, 60, 98, 117, 116, 116, 111, 110, 32, 99, // . + 32, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, //
. + 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, //
. + 32, 32, 32, 32, 86, 97, 108, 105, 100, 32, 108, 111, // Valid lo + 103, 105, 110, 115, 58, 32, 97, 100, 109, 105, 110, 58, // gins: admin: + 112, 97, 115, 115, 48, 44, 32, 117, 115, 101, 114, 49, // pass0, user1 + 58, 112, 97, 115, 115, 49, 44, 32, 117, 115, 101, 114, // :pass1, user + 50, 58, 112, 97, 115, 115, 50, 10, 32, 32, 32, 32, // 2:pass2. + 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 47, 100, //
. .
`; + 10, 125, 59, 10, 10, 10, 99, 111, 110, 115, 116, 32, // .};...const + 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, // Configuratio + 110, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, // n = function + 40, 112, 114, 111, 112, 115, 41, 32, 123, 10, 32, 32, // (props) {. + 99, 111, 110, 115, 116, 32, 91, 117, 114, 108, 44, 32, // const [url, + 115, 101, 116, 85, 114, 108, 93, 32, 61, 32, 117, 115, // setUrl] = us + 101, 83, 116, 97, 116, 101, 40, 112, 114, 111, 112, 115, // eState(props + 46, 99, 111, 110, 102, 105, 103, 46, 117, 114, 108, 32, // .config.url + 124, 124, 32, 39, 39, 41, 59, 10, 32, 32, 99, 111, // || '');. co + 110, 115, 116, 32, 91, 112, 117, 98, 44, 32, 115, 101, // nst [pub, se + 116, 80, 117, 98, 93, 32, 61, 32, 117, 115, 101, 83, // tPub] = useS + 116, 97, 116, 101, 40, 112, 114, 111, 112, 115, 46, 99, // tate(props.c + 111, 110, 102, 105, 103, 46, 112, 117, 98, 32, 124, 124, // onfig.pub || + 32, 39, 39, 41, 59, 10, 32, 32, 99, 111, 110, 115, // '');. cons + 116, 32, 91, 115, 117, 98, 44, 32, 115, 101, 116, 83, // t [sub, setS + 117, 98, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, // ub] = useSta + 116, 101, 40, 112, 114, 111, 112, 115, 46, 99, 111, 110, // te(props.con + 102, 105, 103, 46, 115, 117, 98, 32, 124, 124, 32, 39, // fig.sub || ' + 39, 41, 59, 10, 10, 32, 32, 117, 115, 101, 69, 102, // ');.. useEf + 102, 101, 99, 116, 40, 40, 41, 32, 61, 62, 32, 123, // fect(() => { + 10, 32, 32, 32, 32, 115, 101, 116, 85, 114, 108, 40, // . setUrl( + 112, 114, 111, 112, 115, 46, 99, 111, 110, 102, 105, 103, // props.config + 46, 117, 114, 108, 41, 59, 10, 32, 32, 32, 32, 115, // .url);. s + 101, 116, 80, 117, 98, 40, 112, 114, 111, 112, 115, 46, // etPub(props. + 99, 111, 110, 102, 105, 103, 46, 112, 117, 98, 41, 59, // config.pub); + 10, 32, 32, 32, 32, 115, 101, 116, 83, 117, 98, 40, // . setSub( + 112, 114, 111, 112, 115, 46, 99, 111, 110, 102, 105, 103, // props.config + 46, 115, 117, 98, 41, 59, 10, 32, 32, 125, 44, 32, // .sub);. }, + 91, 112, 114, 111, 112, 115, 46, 99, 111, 110, 102, 105, // [props.confi + 103, 93, 41, 59, 10, 10, 32, 32, 99, 111, 110, 115, // g]);.. cons + 116, 32, 117, 112, 100, 97, 116, 101, 32, 61, 32, 40, // t update = ( + 110, 97, 109, 101, 44, 32, 118, 97, 108, 41, 32, 61, // name, val) = + 62, 32, 102, 101, 116, 99, 104, 40, 39, 47, 97, 112, // > fetch('/ap + 105, 47, 99, 111, 110, 102, 105, 103, 47, 115, 101, 116, // i/config/set + 39, 44, 32, 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, 109, 101, 116, 104, 111, 100, 58, 32, 39, // method: ' + 112, 111, 115, 116, 39, 44, 10, 32, 32, 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, 32, 32, 98, 111, 100, 121, 58, 32, 96, // body: ` + 36, 123, 110, 97, 109, 101, 125, 61, 36, 123, 101, 110, // ${name}=${en + 99, 111, 100, 101, 85, 82, 73, 67, 111, 109, 112, 111, // codeURICompo + 110, 101, 110, 116, 40, 118, 97, 108, 41, 125, 96, 10, // nent(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, 32, 32, 32, 32, 32, 125, 41, 46, 99, // }).c + 97, 116, 99, 104, 40, 101, 114, 114, 32, 61, 62, 32, // atch(err => + 101, 114, 114, 41, 59, 10, 32, 32, 99, 111, 110, 115, // err);. cons + 116, 32, 117, 112, 100, 97, 116, 101, 117, 114, 108, 32, // t updateurl + 61, 32, 101, 118, 32, 61, 62, 32, 117, 112, 100, 97, // = ev => upda + 116, 101, 40, 39, 117, 114, 108, 39, 44, 32, 117, 114, // te('url', ur + 108, 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, // l);. const + 117, 112, 100, 97, 116, 101, 112, 117, 98, 32, 61, 32, // updatepub = + 101, 118, 32, 61, 62, 32, 117, 112, 100, 97, 116, 101, // ev => update + 40, 39, 112, 117, 98, 39, 44, 32, 112, 117, 98, 41, // ('pub', pub) + 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, 117, 112, // ;. const up + 100, 97, 116, 101, 115, 117, 98, 32, 61, 32, 101, 118, // datesub = ev + 32, 61, 62, 32, 117, 112, 100, 97, 116, 101, 40, 39, // => update(' + 115, 117, 98, 39, 44, 32, 115, 117, 98, 41, 59, 10, // sub', sub);. + 10, 32, 32, 99, 111, 110, 115, 111, 108, 101, 46, 108, // . console.l + 111, 103, 40, 112, 114, 111, 112, 115, 44, 32, 91, 117, // og(props, [u + 114, 108, 44, 32, 112, 117, 98, 44, 32, 115, 117, 98, // rl, pub, sub + 93, 41, 59, 10, 32, 32, 114, 101, 116, 117, 114, 110, // ]);. return + 32, 104, 116, 109, 108, 96, 10, 60, 100, 105, 118, 32, // 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, //
+ 10, 32, 32, 32, 32, 60, 115, 112, 97, 110, 32, 99, // . Subs + 99, 114, 105, 98, 101, 32, 116, 111, 112, 105, 99, 58, // cribe topic: + 60, 47, 115, 112, 97, 110, 62, 10, 32, 32, 32, 32, // . + 60, 105, 110, 112, 117, 116, 32, 116, 121, 112, 101, 61, // + 115, 101, 116, 83, 117, 98, 40, 101, 118, 46, 116, 97, // setSub(ev.ta + 114, 103, 101, 116, 46, 118, 97, 108, 117, 101, 41, 125, // rget.value)} + 32, 47, 62, 10, 32, 32, 32, 32, 60, 98, 117, 116, // />. Upda + 116, 101, 60, 47, 98, 117, 116, 116, 111, 110, 62, 10, // te. + 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, //
. < + 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, 109, // div style="m + 97, 114, 103, 105, 110, 58, 32, 48, 46, 53, 101, 109, // argin: 0.5em + 32, 48, 59, 32, 100, 105, 115, 112, 108, 97, 121, 58, // 0; display: + 32, 102, 108, 101, 120, 59, 34, 62, 10, 32, 32, 32, // flex;">. + 32, 60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, // Publish + 116, 111, 112, 105, 99, 58, 60, 47, 115, 112, 97, 110, // topic:. se + 116, 80, 117, 98, 40, 101, 118, 46, 116, 97, 114, 103, // tPub(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, // >. Update + 60, 47, 98, 117, 116, 116, 111, 110, 62, 10, 32, 32, // . + 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, //

. . You c + 97, 110, 32, 117, 115, 101, 32, 60, 97, 32, 104, 114, // an use . Hive + 77, 81, 32, 87, 101, 98, 115, 111, 99, 107, 101, 116, // MQ Websocket + 32, 119, 101, 98, 32, 99, 108, 105, 101, 110, 116, 60, // web client< + 47, 97, 62, 32, 116, 111, 32, 115, 101, 110, 100, 32, // /a> to send + 109, 101, 115, 115, 97, 103, 101, 115, 32, 116, 111, 32, // messages to + 116, 104, 105, 115, 32, 99, 111, 110, 115, 111, 108, 101, // this console + 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, // ..
. + 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, //
. D + 101, 118, 105, 99, 101, 32, 107, 101, 101, 112, 115, 32, // evice keeps + 97, 32, 112, 101, 114, 115, 105, 115, 116, 101, 110, 116, // a persistent + 32, 99, 111, 110, 110, 101, 99, 116, 105, 111, 110, 32, // connection + 116, 111, 32, 116, 104, 101, 32, 99, 111, 110, 102, 105, // to the confi + 103, 117, 114, 101, 100, 32, 77, 81, 84, 84, 32, 115, // gured MQTT s + 101, 114, 118, 101, 114, 46, 10, 32, 32, 32, 32, 67, // erver.. C + 104, 97, 110, 103, 101, 115, 32, 116, 111, 32, 116, 104, // hanges to th + 105, 115, 32, 99, 111, 110, 102, 105, 103, 117, 114, 97, // is configura + 116, 105, 111, 110, 32, 97, 114, 101, 32, 112, 114, 111, // tion are pro + 112, 97, 103, 97, 116, 101, 100, 32, 116, 111, 32, 97, // pagated to a + 108, 108, 32, 100, 97, 115, 104, 98, 111, 97, 114, 100, // ll dashboard + 115, 58, 32, 116, 114, 121, 10, 32, 32, 32, 32, 99, // s: try. c + 104, 97, 110, 103, 105, 110, 103, 32, 116, 104, 101, 109, // hanging them + 32, 105, 110, 32, 116, 104, 105, 115, 32, 100, 97, 115, // in this das + 104, 98, 111, 97, 114, 100, 32, 97, 110, 100, 32, 111, // hboard and o + 98, 115, 101, 114, 118, 101, 32, 99, 104, 97, 110, 103, // bserve chang + 101, 115, 32, 105, 110, 32, 116, 104, 101, 32, 111, 116, // es in the ot + 104, 101, 114, 32, 111, 112, 101, 110, 101, 100, 10, 32, // her opened. + 32, 32, 32, 100, 97, 115, 104, 98, 111, 97, 114, 100, // dashboard + 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, 60, 100, // ..
. Note + 58, 32, 97, 100, 109, 105, 110, 105, 115, 116, 114, 97, // : administra + 116, 111, 114, 115, 32, 99, 97, 110, 32, 115, 101, 101, // tors can see + 32, 116, 104, 105, 115, 32, 115, 101, 99, 116, 105, 111, // this sectio + 110, 32, 97, 110, 100, 32, 99, 97, 110, 32, 99, 104, // n and can ch + 97, 110, 103, 101, 32, 100, 101, 118, 105, 99, 101, 10, // ange device. + 32, 32, 32, 32, 99, 111, 110, 102, 105, 103, 117, 114, // configur + 97, 116, 105, 111, 110, 44, 32, 119, 104, 105, 108, 115, // ation, whils + 116, 32, 117, 115, 101, 114, 115, 32, 99, 97, 110, 110, // t users cann + 111, 116, 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, // ot.. + 10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, // .`;.}; + 10, 10, 10, 99, 111, 110, 115, 116, 32, 77, 101, 115, // ...const Mes + 115, 97, 103, 101, 32, 61, 32, 109, 32, 61, 62, 32, // sage = m => + 104, 116, 109, 108, 96, 60, 100, 105, 118, 32, 115, 116, // html`
. + 32, 32, 60, 115, 112, 97, 110, 32, 99, 108, 97, 115, // qos: + 32, 36, 123, 109, 46, 109, 101, 115, 115, 97, 103, 101, // ${m.message + 46, 113, 111, 115, 125, 32, 60, 47, 115, 112, 97, 110, // .qos} . + 116, 111, 112, 105, 99, 58, 32, 36, 123, 109, 46, 109, // topic: ${m.m + 101, 115, 115, 97, 103, 101, 46, 116, 111, 112, 105, 99, // essage.topic + 125, 32, 60, 47, 115, 112, 97, 110, 62, 10, 32, 32, // } . + 60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, // data: + 32, 36, 123, 109, 46, 109, 101, 115, 115, 97, 103, 101, // ${m.message + 46, 100, 97, 116, 97, 125, 60, 47, 115, 112, 97, 110, // .data}.
`;.. + 99, 111, 110, 115, 116, 32, 77, 101, 115, 115, 97, 103, // const Messag + 101, 115, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, // es = functio + 110, 40, 112, 114, 111, 112, 115, 41, 32, 123, 10, 32, // n(props) {. + 32, 99, 111, 110, 115, 116, 32, 91, 109, 101, 115, 115, // const [mess + 97, 103, 101, 115, 44, 32, 115, 101, 116, 77, 101, 115, // ages, setMes + 115, 97, 103, 101, 115, 93, 32, 61, 32, 117, 115, 101, // sages] = use + 83, 116, 97, 116, 101, 40, 91, 93, 41, 59, 10, 32, // State([]);. + 32, 99, 111, 110, 115, 116, 32, 91, 116, 120, 116, 44, // const [txt, + 32, 115, 101, 116, 84, 120, 116, 93, 32, 61, 32, 117, // setTxt] = u 115, 101, 83, 116, 97, 116, 101, 40, 39, 39, 41, 59, // seState(''); 10, 10, 32, 32, 117, 115, 101, 69, 102, 102, 101, 99, // .. useEffec 116, 40, 40, 41, 32, 61, 62, 32, 123, 10, 32, 32, // t(() => {. @@ -371,719 +591,505 @@ static const unsigned char v2[] = { 99, 114, 105, 98, 101, 40, 102, 117, 110, 99, 116, 105, // cribe(functi 111, 110, 40, 109, 115, 103, 41, 32, 123, 10, 32, 32, // on(msg) {. 32, 32, 32, 32, 105, 102, 32, 40, 109, 115, 103, 46, // if (msg. - 110, 97, 109, 101, 32, 61, 61, 32, 39, 110, 101, 119, // name == 'new - 99, 111, 110, 102, 105, 103, 39, 41, 32, 123, 10, 32, // config') {. - 32, 32, 32, 32, 32, 32, 32, 115, 101, 116, 85, 114, // setUr - 108, 40, 109, 115, 103, 46, 100, 97, 116, 97, 46, 117, // l(msg.data.u - 114, 108, 41, 59, 10, 32, 32, 32, 32, 32, 32, 32, // rl);. - 32, 115, 101, 116, 80, 117, 98, 40, 109, 115, 103, 46, // setPub(msg. - 100, 97, 116, 97, 46, 112, 117, 98, 41, 59, 10, 32, // data.pub);. - 32, 32, 32, 32, 32, 32, 32, 115, 101, 116, 83, 117, // setSu - 98, 40, 109, 115, 103, 46, 100, 97, 116, 97, 46, 115, // b(msg.data.s - 117, 98, 41, 59, 10, 32, 32, 32, 32, 32, 32, 125, // ub);. } - 10, 32, 32, 32, 32, 125, 41, 59, 10, 32, 32, 32, // . });. - 32, 114, 101, 116, 117, 114, 110, 32, 80, 117, 98, 83, // return PubS - 117, 98, 46, 117, 110, 115, 117, 98, 115, 99, 114, 105, // ub.unsubscri - 98, 101, 40, 105, 100, 41, 59, 10, 32, 32, 125, 44, // be(id);. }, - 32, 91, 93, 41, 59, 10, 10, 32, 32, 99, 111, 110, // []);.. con - 115, 116, 32, 117, 112, 100, 97, 116, 101, 32, 61, 32, // st update = - 40, 110, 97, 109, 101, 44, 32, 118, 97, 108, 41, 32, // (name, val) - 61, 62, 32, 102, 101, 116, 99, 104, 40, 39, 47, 97, // => fetch('/a - 112, 105, 47, 99, 111, 110, 102, 105, 103, 47, 115, 101, // pi/config/se - 116, 39, 44, 32, 123, 10, 32, 32, 32, 32, 32, 32, // t', {. + 110, 97, 109, 101, 32, 61, 61, 32, 39, 109, 101, 115, // name == 'mes + 115, 97, 103, 101, 39, 41, 32, 115, 101, 116, 77, 101, // sage') setMe + 115, 115, 97, 103, 101, 115, 40, 120, 32, 61, 62, 32, // ssages(x => + 120, 46, 99, 111, 110, 99, 97, 116, 40, 91, 109, 115, // x.concat([ms + 103, 46, 100, 97, 116, 97, 93, 41, 41, 59, 10, 32, // g.data]));. + 32, 32, 32, 125, 41, 59, 10, 32, 32, 32, 32, 114, // });. r + 101, 116, 117, 114, 110, 32, 80, 117, 98, 83, 117, 98, // eturn PubSub + 46, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, // .unsubscribe + 40, 105, 100, 41, 59, 10, 32, 32, 125, 44, 32, 91, // (id);. }, [ + 93, 41, 59, 10, 10, 32, 32, 99, 111, 110, 115, 116, // ]);.. const + 32, 115, 101, 110, 100, 109, 101, 115, 115, 97, 103, 101, // sendmessage + 32, 61, 32, 101, 118, 32, 61, 62, 32, 102, 101, 116, // = ev => fet + 99, 104, 40, 39, 47, 97, 112, 105, 47, 109, 101, 115, // ch('/api/mes + 115, 97, 103, 101, 47, 115, 101, 110, 100, 39, 44, 32, // sage/send', + 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, 32, 32, 109, 101, 116, 104, 111, 100, 58, 32, // method: - 39, 112, 111, 115, 116, 39, 44, 10, 32, 32, 32, 32, // 'post',. + 32, 32, 32, 32, 32, 32, 32, 32, 109, 101, 116, 104, // meth + 111, 100, 58, 32, 39, 112, 111, 115, 116, 39, 44, 10, // od: '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, 32, 32, 32, 98, 111, 100, 121, 58, 32, // body: - 96, 36, 123, 110, 97, 109, 101, 125, 61, 36, 123, 101, // `${name}=${e + 96, 109, 101, 115, 115, 97, 103, 101, 61, 36, 123, 101, // `message=${e 110, 99, 111, 100, 101, 85, 82, 73, 67, 111, 109, 112, // ncodeURIComp - 111, 110, 101, 110, 116, 40, 118, 97, 108, 41, 125, 96, // onent(val)}` + 111, 110, 101, 110, 116, 40, 116, 120, 116, 41, 125, 96, // onent(txt)}` 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, 125, 41, 46, // }). - 99, 97, 116, 99, 104, 40, 101, 114, 114, 32, 61, 62, // catch(err => - 32, 101, 114, 114, 41, 59, 10, 32, 32, 99, 111, 110, // err);. con - 115, 116, 32, 117, 112, 100, 97, 116, 101, 117, 114, 108, // st updateurl - 32, 61, 32, 101, 118, 32, 61, 62, 32, 117, 112, 100, // = ev => upd - 97, 116, 101, 40, 39, 117, 114, 108, 39, 44, 32, 117, // ate('url', u - 114, 108, 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, // rl);. const - 32, 117, 112, 100, 97, 116, 101, 112, 117, 98, 32, 61, // updatepub = - 32, 101, 118, 32, 61, 62, 32, 117, 112, 100, 97, 116, // ev => updat - 101, 40, 39, 112, 117, 98, 39, 44, 32, 112, 117, 98, // e('pub', pub - 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, 117, // );. const u - 112, 100, 97, 116, 101, 115, 117, 98, 32, 61, 32, 101, // pdatesub = e - 118, 32, 61, 62, 32, 117, 112, 100, 97, 116, 101, 40, // v => update( - 39, 115, 117, 98, 39, 44, 32, 115, 117, 98, 41, 59, // 'sub', sub); - 10, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 104, // .. return h + 32, 32, 32, 32, 32, 125, 41, 46, 116, 104, 101, 110, // }).then + 40, 114, 32, 61, 62, 32, 115, 101, 116, 84, 120, 116, // (r => setTxt + 40, 39, 39, 41, 41, 59, 10, 32, 32, 99, 111, 110, // (''));. con + 115, 116, 32, 99, 111, 110, 110, 115, 116, 97, 116, 117, // st connstatu + 115, 32, 61, 32, 112, 114, 111, 112, 115, 46, 99, 111, // s = props.co + 110, 102, 105, 103, 46, 99, 111, 110, 110, 101, 99, 116, // nfig.connect + 101, 100, 32, 63, 32, 39, 99, 111, 110, 110, 101, 99, // ed ? 'connec + 116, 101, 100, 39, 32, 58, 32, 39, 100, 105, 99, 111, // ted' : 'dico + 110, 110, 101, 99, 116, 101, 100, 39, 59, 10, 32, 32, // nnected';. + 114, 101, 116, 117, 114, 110, 32, 104, 116, 109, 108, 96, // return html` + 10, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, // .
. + 32, 60, 104, 51, 32, 115, 116, 121, 108, 101, 61, 34, //

MQTT mess + 97, 103, 101, 115, 60, 47, 104, 51, 62, 10, 32, 32, // ages

. + 60, 100, 105, 118, 62, 10, 32, 32, 32, 32, 77, 81, //
. MQ + 84, 84, 32, 115, 101, 114, 118, 101, 114, 32, 115, 116, // TT server st + 97, 116, 117, 115, 58, 32, 60, 98, 62, 36, 123, 99, // atus: ${c + 111, 110, 110, 115, 116, 97, 116, 117, 115, 125, 60, 47, // onnstatus}.
. + 32, 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, //
. ${ + 109, 101, 115, 115, 97, 103, 101, 115, 46, 109, 97, 112, // messages.map + 40, 109, 101, 115, 115, 97, 103, 101, 32, 61, 62, 32, // (message => + 104, 40, 77, 101, 115, 115, 97, 103, 101, 44, 32, 123, // h(Message, { + 109, 101, 115, 115, 97, 103, 101, 125, 41, 41, 125, 10, // message}))}. + 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, //
. < + 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, 34, 109, // div style="m + 97, 114, 103, 105, 110, 58, 32, 48, 46, 53, 101, 109, // argin: 0.5em + 32, 48, 59, 32, 100, 105, 115, 112, 108, 97, 121, 58, // 0; display: + 32, 102, 108, 101, 120, 34, 62, 10, 32, 32, 32, 32, // flex">. + 60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, // Publish m + 101, 115, 115, 97, 103, 101, 58, 60, 47, 115, 112, 97, // essage:. setTx + 116, 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, 46, // t(ev.target. + 118, 97, 108, 117, 101, 41, 125, 32, 47, 62, 10, 32, // value)} />. + 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, //
. . Mess + 97, 103, 101, 32, 103, 101, 116, 115, 32, 112, 97, 115, // age gets pas + 115, 101, 100, 32, 116, 111, 32, 116, 104, 101, 32, 100, // sed to the d + 101, 118, 105, 99, 101, 32, 118, 105, 97, 32, 82, 69, // evice via RE + 83, 84, 46, 32, 84, 104, 101, 110, 32, 97, 32, 100, // ST. Then a d + 101, 118, 105, 99, 101, 32, 115, 101, 110, 100, 115, 32, // evice sends + 105, 116, 32, 116, 111, 10, 32, 32, 32, 32, 116, 104, // it to. th + 101, 32, 77, 81, 84, 84, 32, 115, 101, 114, 118, 101, // e MQTT serve + 114, 32, 111, 118, 101, 114, 32, 77, 81, 84, 84, 46, // r over MQTT. + 32, 65, 108, 108, 32, 77, 81, 84, 84, 32, 109, 101, // All MQTT me + 115, 115, 97, 103, 101, 115, 32, 111, 110, 32, 97, 32, // ssages on a + 115, 117, 98, 115, 99, 114, 105, 98, 101, 100, 32, 116, // subscribed t + 111, 112, 105, 99, 10, 32, 32, 32, 32, 114, 101, 99, // opic. rec + 101, 105, 118, 101, 100, 32, 98, 121, 32, 97, 32, 100, // eived by a d + 101, 118, 105, 99, 101, 44, 32, 97, 114, 101, 32, 112, // evice, are p + 114, 111, 112, 97, 103, 97, 116, 101, 100, 32, 116, 111, // ropagated to + 32, 116, 104, 105, 115, 32, 100, 97, 115, 104, 98, 111, // this dashbo + 97, 114, 100, 32, 118, 105, 97, 32, 116, 104, 101, 10, // ard via the. + 32, 32, 32, 32, 47, 97, 112, 105, 47, 119, 97, 116, // /api/wat + 99, 104, 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, // ch.. + 10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, // .`;.}; + 10, 10, 47, 47, 32, 69, 120, 112, 101, 99, 116, 101, // ..// Expecte + 100, 32, 97, 114, 103, 117, 109, 101, 110, 116, 115, 58, // d arguments: + 10, 47, 47, 32, 100, 97, 116, 97, 58, 32, 116, 105, // .// data: ti + 109, 101, 115, 101, 114, 105, 101, 115, 44, 32, 101, 46, // meseries, e. + 103, 46, 32, 91, 32, 91, 49, 54, 53, 52, 51, 54, // g. [ [165436 + 49, 51, 53, 50, 44, 32, 49, 57, 93, 44, 32, 91, // 1352, 19], [ + 49, 54, 53, 52, 51, 54, 49, 51, 53, 51, 44, 32, // 1654361353, + 49, 56, 93, 44, 32, 46, 46, 46, 32, 93, 10, 47, // 18], ... ]./ + 47, 32, 119, 105, 100, 116, 104, 44, 32, 104, 101, 105, // / width, hei + 103, 104, 116, 44, 32, 121, 116, 105, 99, 107, 115, 44, // ght, yticks, + 32, 120, 116, 105, 99, 107, 115, 44, 32, 121, 109, 105, // xticks, ymi + 110, 44, 32, 121, 109, 97, 120, 44, 32, 120, 109, 105, // n, ymax, xmi + 110, 44, 32, 120, 109, 97, 120, 10, 99, 111, 110, 115, // n, xmax.cons + 116, 32, 83, 86, 71, 32, 61, 32, 102, 117, 110, 99, // t SVG = func + 116, 105, 111, 110, 40, 112, 114, 111, 112, 115, 41, 32, // tion(props) + 123, 10, 32, 32, 47, 47, 32, 32, 32, 32, 32, 32, // {. // + 32, 32, 32, 32, 32, 32, 119, 10, 32, 32, 47, 47, // w. // + 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, 32, // h1 + 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, 32, // h. // | + 119, 49, 32, 124, 32, 32, 32, 32, 32, 32, 32, 32, // w1 | + 32, 32, 32, 124, 32, 119, 50, 32, 124, 10, 32, 32, // | w2 |. + 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, 50, // | h2 + 32, 32, 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, // let w = pr + 111, 112, 115, 46, 119, 105, 100, 116, 104, 44, 32, 104, // ops.width, h + 32, 61, 32, 112, 114, 111, 112, 115, 46, 104, 101, 105, // = props.hei + 103, 104, 116, 44, 32, 119, 49, 32, 61, 32, 51, 48, // ght, w1 = 30 + 44, 32, 119, 50, 32, 61, 32, 48, 44, 32, 104, 49, // , w2 = 0, h1 + 32, 61, 32, 56, 44, 32, 104, 50, 32, 61, 32, 49, // = 8, h2 = 1 + 56, 59, 10, 32, 32, 108, 101, 116, 32, 121, 116, 105, // 8;. let yti + 99, 107, 115, 32, 61, 32, 112, 114, 111, 112, 115, 46, // cks = props. + 121, 116, 105, 99, 107, 115, 32, 124, 124, 32, 52, 44, // yticks || 4, + 32, 120, 116, 105, 99, 107, 115, 32, 61, 32, 112, 114, // xticks = pr + 111, 112, 115, 46, 120, 116, 105, 99, 107, 115, 32, 124, // ops.xticks | + 124, 32, 53, 59, 10, 32, 32, 108, 101, 116, 32, 100, // | 5;. let d + 97, 116, 97, 32, 61, 32, 112, 114, 111, 112, 115, 46, // ata = props. + 100, 97, 116, 97, 32, 124, 124, 32, 91, 93, 59, 10, // data || [];. + 32, 32, 108, 101, 116, 32, 121, 109, 105, 110, 32, 61, // let ymin = + 32, 112, 114, 111, 112, 115, 46, 121, 109, 105, 110, 32, // props.ymin + 124, 124, 32, 48, 59, 10, 32, 32, 108, 101, 116, 32, // || 0;. let + 121, 109, 97, 120, 32, 61, 32, 112, 114, 111, 112, 115, // ymax = props + 46, 121, 109, 97, 120, 32, 124, 124, 32, 77, 97, 116, // .ymax || Mat + 104, 46, 109, 97, 120, 46, 97, 112, 112, 108, 121, 40, // h.max.apply( + 110, 117, 108, 108, 44, 32, 100, 97, 116, 97, 46, 109, // null, data.m + 97, 112, 40, 112, 32, 61, 62, 32, 112, 91, 49, 93, // ap(p => p[1] + 41, 41, 59, 10, 32, 32, 108, 101, 116, 32, 120, 109, // ));. let xm + 105, 110, 32, 61, 32, 112, 114, 111, 112, 115, 46, 120, // in = props.x + 109, 105, 110, 32, 124, 124, 32, 77, 97, 116, 104, 46, // min || Math. + 109, 105, 110, 46, 97, 112, 112, 108, 121, 40, 110, 117, // min.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, 48, 93, 41, 41, // (p => p[0])) + 59, 10, 32, 32, 108, 101, 116, 32, 120, 109, 97, 120, // ;. let xmax + 32, 61, 32, 112, 114, 111, 112, 115, 46, 120, 109, 97, // = props.xma + 120, 32, 124, 124, 32, 77, 97, 116, 104, 46, 109, 97, // x || Math.ma + 120, 46, 97, 112, 112, 108, 121, 40, 110, 117, 108, 108, // x.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]));. + 10, 32, 32, 47, 47, 32, 89, 45, 97, 120, 105, 115, // . // Y-axis + 32, 116, 105, 99, 107, 32, 108, 105, 110, 101, 115, 32, // tick lines + 97, 110, 100, 32, 108, 97, 98, 101, 108, 115, 10, 32, // and labels. + 32, 108, 101, 116, 32, 121, 116, 97, 32, 61, 32, 40, // let yta = ( + 110, 101, 119, 32, 65, 114, 114, 97, 121, 40, 121, 116, // new Array(yt + 105, 99, 107, 115, 32, 43, 32, 49, 41, 41, 46, 102, // icks + 1)).f + 105, 108, 108, 40, 48, 41, 46, 109, 97, 112, 40, 40, // ill(0).map(( + 95, 44, 32, 105, 41, 32, 61, 62, 32, 105, 41, 59, // _, i) => i); + 32, 32, 47, 47, 32, 105, 110, 100, 105, 99, 101, 115, // // indices + 10, 32, 32, 108, 101, 116, 32, 121, 116, 105, 32, 61, // . let yti = + 32, 105, 32, 61, 62, 32, 104, 32, 45, 32, 104, 50, // i => h - h2 + 32, 45, 32, 40, 104, 32, 45, 32, 104, 49, 32, 45, // - (h - h1 - + 32, 104, 50, 41, 32, 42, 32, 105, 32, 47, 32, 121, // h2) * i / y + 116, 105, 99, 107, 115, 59, 32, 32, 32, 32, 32, 32, // ticks; + 32, 32, 32, 32, 47, 47, 32, 105, 110, 100, 101, 120, // // index + 39, 115, 32, 89, 10, 32, 32, 108, 101, 116, 32, 121, // 's Y. let y + 116, 118, 32, 61, 32, 105, 32, 61, 62, 32, 40, 121, // tv = i => (y + 109, 97, 120, 32, 45, 32, 121, 109, 105, 110, 41, 32, // max - ymin) + 42, 32, 105, 32, 47, 32, 121, 116, 105, 99, 107, 115, // * i / yticks + 59, 10, 32, 32, 108, 101, 116, 32, 121, 116, 108, 32, // ;. let ytl + 61, 32, 121, 32, 61, 62, 32, 104, 116, 109, 108, 96, // = y => html` + 60, 108, 105, 110, 101, 32, 120, 49, 61, 36, 123, 119, // `;. le + 116, 32, 121, 116, 116, 32, 61, 32, 40, 121, 44, 32, // t ytt = (y, + 118, 41, 32, 61, 62, 32, 104, 116, 109, 108, 96, 60, // v) => html`< + 116, 101, 120, 116, 32, 120, 61, 48, 32, 121, 61, 36, // text x=0 y=$ + 123, 121, 32, 43, 32, 53, 125, 32, 99, 108, 97, 115, // {y + 5} clas + 115, 61, 34, 108, 97, 98, 101, 108, 34, 62, 36, 123, // s="label">${ + 118, 125, 60, 47, 116, 101, 120, 116, 62, 96, 59, 10, // v}`;. + 10, 32, 32, 47, 47, 32, 88, 45, 97, 120, 105, 115, // . // X-axis + 32, 116, 105, 99, 107, 32, 108, 105, 110, 101, 115, 32, // tick lines + 97, 110, 100, 32, 108, 97, 98, 101, 108, 115, 10, 32, // and labels. + 32, 108, 101, 116, 32, 100, 97, 116, 101, 102, 109, 116, // let datefmt + 32, 61, 32, 117, 110, 105, 120, 32, 61, 62, 32, 40, // = unix => ( + 110, 101, 119, 32, 68, 97, 116, 101, 40, 117, 110, 105, // new Date(uni + 120, 32, 42, 32, 49, 48, 48, 48, 41, 41, 46, 116, // x * 1000)).t + 111, 73, 83, 79, 83, 116, 114, 105, 110, 103, 40, 41, // oISOString() + 46, 115, 117, 98, 115, 116, 114, 40, 49, 52, 44, 32, // .substr(14, + 53, 41, 59, 10, 32, 32, 108, 101, 116, 32, 120, 116, // 5);. let xt + 97, 32, 61, 32, 40, 110, 101, 119, 32, 65, 114, 114, // a = (new Arr + 97, 121, 40, 120, 116, 105, 99, 107, 115, 32, 43, 32, // ay(xticks + + 49, 41, 41, 46, 102, 105, 108, 108, 40, 48, 41, 46, // 1)).fill(0). + 109, 97, 112, 40, 40, 95, 44, 32, 105, 41, 32, 61, // map((_, i) = + 62, 32, 105, 41, 59, 32, 32, 47, 47, 32, 105, 110, // > i); // in + 100, 105, 99, 101, 115, 10, 32, 32, 108, 101, 116, 32, // dices. let + 120, 116, 105, 32, 61, 32, 105, 32, 61, 62, 32, 119, // xti = i => w + 49, 32, 43, 32, 40, 119, 32, 45, 32, 119, 49, 32, // 1 + (w - w1 + 45, 32, 119, 50, 41, 32, 42, 32, 105, 32, 47, 32, // - w2) * i / + 120, 116, 105, 99, 107, 115, 59, 32, 32, 32, 32, 32, // xticks; + 32, 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, // // + 105, 110, 100, 101, 120, 39, 115, 32, 88, 10, 32, 32, // index's X. + 108, 101, 116, 32, 120, 116, 118, 32, 61, 32, 105, 32, // let xtv = i + 61, 62, 32, 100, 97, 116, 101, 102, 109, 116, 40, 120, // => datefmt(x + 109, 105, 110, 32, 43, 32, 40, 120, 109, 97, 120, 32, // min + (xmax + 45, 32, 120, 109, 105, 110, 41, 32, 42, 32, 105, 32, // - xmin) * i + 47, 32, 120, 116, 105, 99, 107, 115, 41, 59, 10, 32, // / xticks);. + 32, 108, 101, 116, 32, 120, 116, 108, 32, 61, 32, 120, // let xtl = x + 32, 61, 62, 32, 104, 116, 109, 108, 96, 60, 112, 97, // => html``;. let + 120, 116, 116, 32, 61, 32, 40, 120, 44, 32, 118, 41, // xtt = (x, v) + 32, 61, 62, 10, 32, 32, 32, 32, 32, 32, 104, 116, // =>. ht + 109, 108, 96, 60, 116, 101, 120, 116, 32, 120, 61, 36, // ml`${ + 118, 125, 60, 47, 116, 101, 120, 116, 62, 96, 59, 10, // v}`;. + 10, 32, 32, 47, 47, 32, 84, 114, 97, 110, 115, 102, // . // Transf + 111, 114, 109, 32, 100, 97, 116, 97, 32, 112, 111, 105, // orm data poi + 110, 116, 115, 32, 97, 114, 114, 97, 121, 32, 105, 110, // nts array in + 116, 111, 32, 99, 111, 111, 114, 100, 105, 110, 97, 116, // to coordinat + 101, 10, 32, 32, 108, 101, 116, 32, 100, 120, 32, 61, // e. let dx = + 32, 118, 32, 61, 62, 32, 119, 49, 32, 43, 32, 40, // v => w1 + ( + 118, 32, 45, 32, 120, 109, 105, 110, 41, 32, 47, 32, // v - xmin) / + 40, 40, 120, 109, 97, 120, 32, 45, 32, 120, 109, 105, // ((xmax - xmi + 110, 41, 32, 124, 124, 32, 49, 41, 32, 42, 32, 40, // n) || 1) * ( + 119, 32, 45, 32, 119, 49, 32, 45, 32, 119, 50, 41, // w - w1 - w2) + 59, 10, 32, 32, 108, 101, 116, 32, 100, 121, 32, 61, // ;. let dy = + 32, 118, 32, 61, 62, 32, 104, 32, 45, 32, 104, 50, // v => h - h2 + 32, 45, 32, 40, 118, 32, 45, 32, 121, 109, 105, 110, // - (v - ymin + 41, 32, 47, 32, 40, 40, 121, 109, 97, 120, 32, 45, // ) / ((ymax - + 32, 121, 109, 105, 110, 41, 32, 124, 124, 32, 49, 41, // ymin) || 1) + 32, 42, 32, 40, 104, 32, 45, 32, 104, 49, 32, 45, // * (h - h1 - + 32, 104, 50, 41, 59, 10, 32, 32, 108, 101, 116, 32, // h2);. let + 100, 100, 32, 61, 32, 100, 97, 116, 97, 46, 109, 97, // dd = data.ma + 112, 40, 112, 32, 61, 62, 32, 91, 77, 97, 116, 104, // p(p => [Math + 46, 114, 111, 117, 110, 100, 40, 100, 120, 40, 112, 91, // .round(dx(p[ + 48, 93, 41, 41, 44, 32, 77, 97, 116, 104, 46, 114, // 0])), Math.r + 111, 117, 110, 100, 40, 100, 121, 40, 112, 91, 49, 93, // ound(dy(p[1] + 41, 41, 93, 41, 59, 10, 32, 32, 108, 101, 116, 32, // ))]);. let + 100, 100, 108, 32, 61, 32, 100, 100, 46, 108, 101, 110, // ddl = dd.len + 103, 116, 104, 59, 10, 32, 32, 47, 47, 32, 65, 110, // gth;. // An + 100, 32, 112, 108, 111, 116, 32, 116, 104, 101, 32, 100, // d plot the d + 97, 116, 97, 32, 97, 115, 32, 60, 112, 97, 116, 104, // ata as element. + 108, 101, 116, 32, 98, 101, 103, 105, 110, 48, 32, 61, // let begin0 = + 32, 100, 100, 108, 32, 63, 32, 96, 77, 32, 36, 123, // ddl ? `M ${ + 100, 100, 91, 48, 93, 91, 48, 93, 125, 44, 36, 123, // dd[0][0]},${ + 100, 100, 91, 48, 93, 91, 49, 93, 125, 96, 32, 58, // dd[0][1]}` : + 32, 96, 77, 32, 48, 44, 48, 96, 59, 10, 32, 32, // `M 0,0`;. + 108, 101, 116, 32, 98, 101, 103, 105, 110, 32, 61, 32, // let begin = + 96, 77, 32, 36, 123, 119, 49, 125, 44, 36, 123, 104, // `M ${w1},${h + 32, 45, 32, 104, 50, 125, 96, 59, 32, 32, 47, 47, // - h2}`; // + 32, 73, 110, 105, 116, 105, 97, 108, 32, 112, 111, 105, // Initial poi + 110, 116, 10, 32, 32, 108, 101, 116, 32, 101, 110, 100, // nt. let end + 32, 61, 32, 100, 100, 108, 32, 63, 32, 96, 76, 32, // = ddl ? `L + 36, 123, 100, 100, 91, 100, 100, 108, 32, 45, 32, 49, // ${dd[ddl - 1 + 93, 91, 48, 93, 125, 44, 36, 123, 104, 32, 45, 32, // ][0]},${h - + 104, 50, 125, 96, 32, 58, 32, 96, 76, 32, 36, 123, // h2}` : `L ${ + 119, 49, 125, 44, 36, 123, 104, 32, 45, 32, 104, 50, // w1},${h - h2 + 125, 96, 59, 10, 32, 32, 108, 101, 116, 32, 115, 101, // }`;. let se + 114, 105, 101, 115, 32, 61, 32, 100, 100, 108, 32, 63, // ries = ddl ? + 32, 100, 100, 46, 109, 97, 112, 40, 112, 32, 61, 62, // dd.map(p => + 32, 96, 76, 32, 36, 123, 112, 91, 48, 93, 125, 32, // `L ${p[0]} + 36, 123, 112, 91, 49, 93, 125, 96, 41, 32, 58, 32, // ${p[1]}`) : + 91, 93, 59, 10, 10, 32, 32, 114, 101, 116, 117, 114, // [];.. retur + 110, 32, 104, 116, 109, 108, 96, 10, 60, 115, 118, 103, // n html`.. . $ + 123, 121, 116, 97, 46, 109, 97, 112, 40, 105, 32, 61, // {yta.map(i = + 62, 32, 121, 116, 108, 40, 121, 116, 105, 40, 105, 41, // > ytl(yti(i) + 41, 41, 125, 10, 32, 32, 36, 123, 121, 116, 97, 46, // ))}. ${yta. + 109, 97, 112, 40, 105, 32, 61, 62, 32, 121, 116, 116, // map(i => ytt + 40, 121, 116, 105, 40, 105, 41, 44, 32, 121, 116, 118, // (yti(i), ytv + 40, 105, 41, 41, 41, 125, 10, 32, 32, 36, 123, 120, // (i)))}. ${x + 116, 97, 46, 109, 97, 112, 40, 105, 32, 61, 62, 32, // ta.map(i => + 120, 116, 108, 40, 120, 116, 105, 40, 105, 41, 41, 41, // xtl(xti(i))) + 125, 10, 32, 32, 36, 123, 100, 97, 116, 97, 46, 108, // }. ${data.l + 101, 110, 103, 116, 104, 32, 63, 32, 120, 116, 97, 46, // ength ? xta. + 109, 97, 112, 40, 105, 32, 61, 62, 32, 120, 116, 116, // map(i => xtt + 40, 120, 116, 105, 40, 105, 41, 44, 32, 120, 116, 118, // (xti(i), xtv + 40, 105, 41, 41, 41, 32, 58, 32, 39, 39, 125, 10, // (i))) : ''}. + 32, 32, 60, 112, 97, 116, 104, 32, 100, 61, 34, 36, // .

.`;.};...co + 110, 115, 116, 32, 67, 104, 97, 114, 116, 32, 61, 32, // nst Chart = + 102, 117, 110, 99, 116, 105, 111, 110, 40, 112, 114, 111, // function(pro + 112, 115, 41, 32, 123, 10, 32, 32, 99, 111, 110, 115, // ps) {. cons + 116, 32, 91, 100, 97, 116, 97, 44, 32, 115, 101, 116, // t [data, set + 68, 97, 116, 97, 93, 32, 61, 32, 117, 115, 101, 83, // Data] = useS + 116, 97, 116, 101, 40, 91, 93, 41, 59, 10, 32, 32, // tate([]);. + 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, 33, 61, 32, 39, 109, 101, 116, 114, 105, 99, 115, // != 'metrics + 39, 41, 32, 114, 101, 116, 117, 114, 110, 59, 10, 32, // ') return;. + 32, 32, 32, 32, 32, 115, 101, 116, 68, 97, 116, 97, // setData + 40, 120, 32, 61, 62, 32, 120, 46, 99, 111, 110, 99, // (x => x.conc + 97, 116, 40, 91, 109, 115, 103, 46, 100, 97, 116, 97, // at([msg.data + 93, 41, 46, 115, 112, 108, 105, 99, 101, 40, 45, 77, // ]).splice(-M + 97, 120, 77, 101, 116, 114, 105, 99, 115, 68, 97, 116, // axMetricsDat + 97, 80, 111, 105, 110, 116, 115, 41, 41, 59, 10, 32, // aPoints));. + 32, 32, 32, 125, 41, 59, 10, 32, 32, 32, 32, 114, // });. r + 101, 116, 117, 114, 110, 32, 80, 117, 98, 83, 117, 98, // eturn PubSub + 46, 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, // .unsubscribe + 40, 105, 100, 41, 59, 10, 32, 32, 125, 44, 32, 91, // (id);. }, [ + 93, 41, 59, 10, 10, 32, 32, 108, 101, 116, 32, 120, // ]);.. let x + 109, 97, 120, 32, 61, 32, 48, 44, 32, 109, 105, 115, // max = 0, mis + 115, 105, 110, 103, 32, 61, 32, 77, 97, 120, 77, 101, // sing = MaxMe + 116, 114, 105, 99, 115, 68, 97, 116, 97, 80, 111, 105, // tricsDataPoi + 110, 116, 115, 32, 45, 32, 100, 97, 116, 97, 46, 108, // nts - data.l + 101, 110, 103, 116, 104, 59, 10, 32, 32, 105, 102, 32, // ength;. if + 40, 109, 105, 115, 115, 105, 110, 103, 32, 62, 32, 48, // (missing > 0 + 41, 32, 120, 109, 97, 120, 32, 61, 32, 77, 97, 116, // ) xmax = Mat + 104, 46, 114, 111, 117, 110, 100, 40, 68, 97, 116, 101, // h.round(Date + 46, 110, 111, 119, 40, 41, 32, 47, 32, 49, 48, 48, // .now() / 100 + 48, 41, 32, 43, 32, 109, 105, 115, 115, 105, 110, 103, // 0) + missing + 59, 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 104, // ;. return h 116, 109, 108, 96, 10, 60, 100, 105, 118, 32, 99, 108, // tml`.

.

Data Cha + 114, 116, 60, 47, 104, 51, 62, 10, 32, 32, 60, 100, // rt

. . - 68, 101, 118, 105, 99, 101, 32, 67, 111, 110, 102, 105, // Device Confi - 103, 117, 114, 97, 116, 105, 111, 110, 60, 47, 104, 51, // guration.
. MQT - 84, 32, 115, 101, 114, 118, 101, 114, 58, 60, 47, 115, // T server:. - 32, 115, 101, 116, 85, 114, 108, 40, 101, 118, 46, 116, // setUrl(ev.t - 97, 114, 103, 101, 116, 46, 118, 97, 108, 117, 101, 41, // arget.value) - 125, 32, 47, 62, 10, 32, 32, 32, 32, 60, 98, 117, // } />. Upd - 97, 116, 101, 60, 47, 98, 117, 116, 116, 111, 110, 62, // ate - 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, 32, 32, 60, 115, 112, 97, 110, 32, 99, 108, 97, // Subscr - 105, 98, 101, 32, 116, 111, 112, 105, 99, 58, 60, 47, // ibe topic:. se - 116, 83, 117, 98, 40, 101, 118, 46, 116, 97, 114, 103, // tSub(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, // >. Update - 60, 47, 98, 117, 116, 116, 111, 110, 62, 10, 32, 32, // . - 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, //
. . < - 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, 80, 117, 98, 108, 105, 115, 104, 32, 116, 111, // ">Publish to - 112, 105, 99, 58, 60, 47, 115, 112, 97, 110, 62, 10, // pic:. - 32, 32, 32, 32, 60, 105, 110, 112, 117, 116, 32, 116, // setP - 117, 98, 40, 101, 118, 46, 116, 97, 114, 103, 101, 116, // ub(ev.target - 46, 118, 97, 108, 117, 101, 41, 125, 32, 47, 62, 10, // .value)} />. - 32, 32, 32, 32, 60, 98, 117, 116, 116, 111, 110, 32, //
- 96, 59, 10, 10, 99, 111, 110, 115, 116, 32, 77, 101, // `;..const Me - 115, 115, 97, 103, 101, 115, 32, 61, 32, 102, 117, 110, // ssages = 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 [ - 109, 101, 115, 115, 97, 103, 101, 115, 44, 32, 115, 101, // messages, se - 116, 77, 101, 115, 115, 97, 103, 101, 115, 93, 32, 61, // tMessages] = - 32, 117, 115, 101, 83, 116, 97, 116, 101, 40, 91, 93, // useState([] - 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, 32, 91, // );. const [ - 99, 102, 103, 44, 32, 115, 101, 116, 67, 102, 103, 93, // cfg, setCfg] - 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, 101, 40, // = useState( - 123, 125, 41, 59, 10, 32, 32, 99, 111, 110, 115, 116, // {});. const - 32, 91, 116, 120, 116, 44, 32, 115, 101, 116, 84, 120, // [txt, setTx - 116, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, // t] = useStat - 101, 40, 39, 39, 41, 59, 10, 10, 32, 32, 117, 115, // e('');.. us - 101, 69, 102, 102, 101, 99, 116, 40, 40, 41, 32, 61, // eEffect(() = - 62, 32, 123, 10, 32, 32, 32, 32, 99, 111, 110, 115, // > {. cons - 116, 32, 105, 100, 32, 61, 32, 80, 117, 98, 83, 117, // t id = PubSu - 98, 46, 115, 117, 98, 115, 99, 114, 105, 98, 101, 40, // b.subscribe( - 102, 117, 110, 99, 116, 105, 111, 110, 40, 109, 115, 103, // function(msg - 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 105, 102, // ) {. if - 32, 40, 109, 115, 103, 46, 110, 97, 109, 101, 32, 61, // (msg.name = - 61, 32, 39, 110, 101, 119, 99, 111, 110, 102, 105, 103, // = 'newconfig - 39, 41, 32, 115, 101, 116, 67, 102, 103, 40, 120, 32, // ') setCfg(x - 61, 62, 32, 109, 115, 103, 46, 100, 97, 116, 97, 41, // => msg.data) - 59, 10, 32, 32, 32, 32, 32, 32, 105, 102, 32, 40, // ;. if ( - 109, 115, 103, 46, 110, 97, 109, 101, 32, 61, 61, 32, // msg.name == - 39, 109, 101, 115, 115, 97, 103, 101, 39, 41, 32, 115, // 'message') s - 101, 116, 77, 101, 115, 115, 97, 103, 101, 115, 40, 120, // etMessages(x - 32, 61, 62, 32, 120, 46, 99, 111, 110, 99, 97, 116, // => x.concat - 40, 91, 109, 115, 103, 46, 100, 97, 116, 97, 93, 41, // ([msg.data]) - 41, 59, 10, 32, 32, 32, 32, 125, 41, 59, 10, 32, // );. });. - 32, 32, 32, 114, 101, 116, 117, 114, 110, 32, 80, 117, // return Pu - 98, 83, 117, 98, 46, 117, 110, 115, 117, 98, 115, 99, // bSub.unsubsc - 114, 105, 98, 101, 40, 105, 100, 41, 59, 10, 32, 32, // ribe(id);. - 125, 44, 32, 91, 93, 41, 59, 10, 10, 32, 32, 99, // }, []);.. c - 111, 110, 115, 116, 32, 115, 101, 110, 100, 109, 101, 115, // onst sendmes - 115, 97, 103, 101, 32, 61, 32, 101, 118, 32, 61, 62, // sage = ev => - 32, 102, 101, 116, 99, 104, 40, 39, 47, 97, 112, 105, // fetch('/api - 47, 109, 101, 115, 115, 97, 103, 101, 47, 115, 101, 110, // /message/sen - 100, 39, 44, 32, 123, 10, 32, 32, 32, 32, 32, 32, // d', {. - 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, 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, 98, 111, // bo - 100, 121, 58, 32, 96, 109, 101, 115, 115, 97, 103, 101, // dy: `message - 61, 36, 123, 101, 110, 99, 111, 100, 101, 85, 82, 73, // =${encodeURI - 67, 111, 109, 112, 111, 110, 101, 110, 116, 40, 116, 120, // Component(tx - 116, 41, 125, 96, 10, 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, 125, 41, 46, // }). - 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 115, 101, // then(r => se - 116, 84, 120, 116, 40, 39, 39, 41, 41, 59, 10, 10, // tTxt(''));.. - 32, 32, 114, 101, 116, 117, 114, 110, 32, 104, 116, 109, // return htm - 108, 96, 10, 60, 100, 105, 118, 32, 99, 108, 97, 115, // l`.
- 10, 32, 32, 60, 104, 51, 32, 115, 116, 121, 108, 101, // .

MQTT me - 115, 115, 97, 103, 101, 115, 60, 47, 104, 51, 62, 10, // ssages

. - 32, 32, 60, 100, 105, 118, 62, 10, 32, 32, 32, 32, //
. - 77, 81, 84, 84, 32, 115, 101, 114, 118, 101, 114, 32, // MQTT server - 115, 116, 97, 116, 117, 115, 58, 32, 60, 98, 62, 36, // status: $ - 123, 99, 102, 103, 46, 99, 111, 110, 110, 101, 99, 116, // {cfg.connect - 101, 100, 32, 63, 32, 39, 99, 111, 110, 110, 101, 99, // ed ? 'connec - 116, 101, 100, 39, 32, 58, 32, 39, 100, 105, 99, 111, // ted' : 'dico - 110, 110, 101, 99, 116, 101, 100, 39, 125, 60, 47, 98, // nnected'}.
. - 32, 60, 100, 105, 118, 32, 115, 116, 121, 108, 101, 61, //
. ${m - 101, 115, 115, 97, 103, 101, 115, 46, 109, 97, 112, 40, // essages.map( - 109, 101, 115, 115, 97, 103, 101, 32, 61, 62, 32, 104, // message => h - 40, 77, 101, 115, 115, 97, 103, 101, 44, 32, 123, 109, // (Message, {m - 101, 115, 115, 97, 103, 101, 125, 41, 41, 125, 10, 32, // essage}))}. - 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, //
. . < - 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, 80, 117, 98, 108, 105, 115, 104, 32, 109, 101, // ">Publish me - 115, 115, 97, 103, 101, 58, 60, 47, 115, 112, 97, 110, // ssage:. setTxt - 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)} />. + 46, 53, 101, 109, 59, 34, 32, 99, 108, 97, 115, 115, // .5em;" class + 61, 34, 34, 62, 10, 32, 32, 32, 32, 60, 36, 123, // ="">. <${ + 83, 86, 71, 125, 32, 104, 101, 105, 103, 104, 116, 61, // SVG} height= + 50, 52, 48, 32, 119, 105, 100, 116, 104, 61, 54, 48, // 240 width=60 + 48, 32, 121, 109, 105, 110, 61, 48, 32, 121, 109, 97, // 0 ymin=0 yma + 120, 61, 50, 48, 32, 120, 109, 97, 120, 61, 36, 123, // x=20 xmax=${ + 120, 109, 97, 120, 125, 32, 100, 97, 116, 97, 61, 36, // xmax} data=$ + 123, 100, 97, 116, 97, 125, 32, 47, 62, 10, 32, 32, // {data} />. 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, //
. . Messa - 103, 101, 32, 103, 101, 116, 115, 32, 112, 97, 115, 115, // ge gets pass - 101, 100, 32, 116, 111, 32, 116, 104, 101, 32, 100, 101, // ed to the de - 118, 105, 99, 101, 32, 118, 105, 97, 32, 82, 69, 83, // vice via RES - 84, 46, 32, 84, 104, 101, 110, 32, 97, 32, 100, 101, // T. Then a de - 118, 105, 99, 101, 32, 115, 101, 110, 100, 115, 32, 105, // vice sends i - 116, 32, 116, 111, 10, 32, 32, 32, 32, 116, 104, 101, // t to. the - 32, 77, 81, 84, 84, 32, 115, 101, 114, 118, 101, 114, // MQTT server - 32, 111, 118, 101, 114, 32, 77, 81, 84, 84, 46, 32, // over MQTT. - 65, 108, 108, 32, 77, 81, 84, 84, 32, 109, 101, 115, // All MQTT mes - 115, 97, 103, 101, 115, 32, 111, 110, 32, 97, 32, 115, // sages on a s - 117, 98, 115, 99, 114, 105, 98, 101, 100, 32, 116, 111, // ubscribed to - 112, 105, 99, 10, 32, 32, 32, 32, 114, 101, 99, 101, // pic. rece - 105, 118, 101, 100, 32, 98, 121, 32, 97, 32, 100, 101, // ived by a de - 118, 105, 99, 101, 44, 32, 97, 114, 101, 32, 112, 114, // vice, are pr - 111, 112, 97, 103, 97, 116, 101, 100, 32, 116, 111, 32, // opagated to - 116, 104, 105, 115, 32, 100, 97, 115, 104, 98, 111, 97, // this dashboa - 114, 100, 32, 118, 105, 97, 32, 116, 104, 101, 10, 32, // rd via the. - 32, 32, 32, 47, 97, 112, 105, 47, 119, 97, 116, 99, // /api/watc + 34, 62, 10, 32, 32, 32, 32, 84, 104, 105, 115, 32, // ">. This + 99, 104, 97, 114, 116, 32, 112, 108, 111, 116, 115, 32, // chart plots + 108, 105, 118, 101, 32, 115, 101, 110, 115, 111, 114, 32, // live sensor + 100, 97, 116, 97, 44, 32, 115, 101, 110, 116, 32, 98, // data, sent b + 121, 32, 97, 32, 100, 101, 118, 105, 99, 101, 32, 118, // y a device v + 105, 97, 32, 47, 97, 112, 105, 47, 119, 97, 116, 99, // ia /api/watc 104, 46, 10, 32, 32, 60, 47, 100, 105, 118, 62, 10, // h.. . 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, 10, // `;.};. - 10, 47, 47, 32, 69, 120, 112, 101, 99, 116, 101, 100, // .// Expected - 32, 97, 114, 103, 117, 109, 101, 110, 116, 115, 58, 10, // arguments:. - 47, 47, 32, 100, 97, 116, 97, 58, 32, 116, 105, 109, // // data: tim - 101, 115, 101, 114, 105, 101, 115, 44, 32, 101, 46, 103, // eseries, e.g - 46, 32, 91, 32, 91, 49, 54, 53, 52, 51, 54, 49, // . [ [1654361 - 51, 53, 50, 44, 32, 49, 57, 93, 44, 32, 91, 49, // 352, 19], [1 - 54, 53, 52, 51, 54, 49, 51, 53, 51, 44, 32, 49, // 654361353, 1 - 56, 93, 44, 32, 46, 46, 46, 32, 93, 10, 47, 47, // 8], ... ].// - 32, 119, 105, 100, 116, 104, 44, 32, 104, 101, 105, 103, // width, heig - 104, 116, 44, 32, 121, 116, 105, 99, 107, 115, 44, 32, // ht, yticks, - 120, 116, 105, 99, 107, 115, 44, 32, 121, 109, 105, 110, // xticks, ymin - 44, 32, 121, 109, 97, 120, 44, 32, 120, 109, 105, 110, // , ymax, xmin - 44, 32, 120, 109, 97, 120, 10, 99, 111, 110, 115, 116, // , xmax.const - 32, 83, 86, 71, 32, 61, 32, 102, 117, 110, 99, 116, // SVG = funct - 105, 111, 110, 40, 112, 114, 111, 112, 115, 41, 32, 123, // ion(props) { - 10, 32, 32, 47, 47, 32, 32, 32, 32, 32, 32, 32, // . // - 32, 32, 32, 32, 32, 119, 10, 32, 32, 47, 47, 32, // w. // - 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, 32, 32, // h1 - 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, 32, 119, // h. // | w - 49, 32, 124, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 1 | - 32, 32, 124, 32, 119, 50, 32, 124, 10, 32, 32, 47, // | w2 |. / - 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, 50, 32, // h2 - 32, 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, // let w = pro - 112, 115, 46, 119, 105, 100, 116, 104, 44, 32, 104, 32, // ps.width, h - 61, 32, 112, 114, 111, 112, 115, 46, 104, 101, 105, 103, // = props.heig - 104, 116, 44, 32, 119, 49, 32, 61, 32, 51, 48, 44, // ht, w1 = 30, - 32, 119, 50, 32, 61, 32, 48, 44, 32, 104, 49, 32, // w2 = 0, h1 - 61, 32, 56, 44, 32, 104, 50, 32, 61, 32, 49, 56, // = 8, h2 = 18 - 59, 10, 32, 32, 108, 101, 116, 32, 121, 116, 105, 99, // ;. let ytic - 107, 115, 32, 61, 32, 112, 114, 111, 112, 115, 46, 121, // ks = props.y - 116, 105, 99, 107, 115, 32, 124, 124, 32, 52, 44, 32, // ticks || 4, - 120, 116, 105, 99, 107, 115, 32, 61, 32, 112, 114, 111, // xticks = pro - 112, 115, 46, 120, 116, 105, 99, 107, 115, 32, 124, 124, // ps.xticks || - 32, 53, 59, 10, 32, 32, 108, 101, 116, 32, 100, 97, // 5;. let da - 116, 97, 32, 61, 32, 112, 114, 111, 112, 115, 46, 100, // ta = props.d - 97, 116, 97, 32, 124, 124, 32, 91, 93, 59, 10, 32, // ata || [];. - 32, 108, 101, 116, 32, 121, 109, 105, 110, 32, 61, 32, // let ymin = - 112, 114, 111, 112, 115, 46, 121, 109, 105, 110, 32, 124, // props.ymin | - 124, 32, 48, 59, 10, 32, 32, 108, 101, 116, 32, 121, // | 0;. let y - 109, 97, 120, 32, 61, 32, 112, 114, 111, 112, 115, 46, // max = props. - 121, 109, 97, 120, 32, 124, 124, 32, 77, 97, 116, 104, // ymax || Math - 46, 109, 97, 120, 46, 97, 112, 112, 108, 121, 40, 110, // .max.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, 49, 93, 41, // p(p => p[1]) - 41, 59, 10, 32, 32, 108, 101, 116, 32, 120, 109, 105, // );. let xmi - 110, 32, 61, 32, 112, 114, 111, 112, 115, 46, 120, 109, // n = props.xm - 105, 110, 32, 124, 124, 32, 77, 97, 116, 104, 46, 109, // in || Math.m - 105, 110, 46, 97, 112, 112, 108, 121, 40, 110, 117, 108, // in.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, 32, 32, 108, 101, 116, 32, 120, 109, 97, 120, 32, // . let xmax - 61, 32, 112, 114, 111, 112, 115, 46, 120, 109, 97, 120, // = props.xmax - 32, 124, 124, 32, 77, 97, 116, 104, 46, 109, 97, 120, // || Math.max - 46, 97, 112, 112, 108, 121, 40, 110, 117, 108, 108, 44, // .apply(null, - 32, 100, 97, 116, 97, 46, 109, 97, 112, 40, 112, 32, // data.map(p - 61, 62, 32, 112, 91, 48, 93, 41, 41, 59, 10, 10, // => p[0]));.. - 32, 32, 47, 47, 32, 89, 45, 97, 120, 105, 115, 32, // // Y-axis - 116, 105, 99, 107, 32, 108, 105, 110, 101, 115, 32, 97, // tick lines a - 110, 100, 32, 108, 97, 98, 101, 108, 115, 10, 32, 32, // nd labels. - 108, 101, 116, 32, 121, 116, 97, 32, 61, 32, 40, 110, // let yta = (n - 101, 119, 32, 65, 114, 114, 97, 121, 40, 121, 116, 105, // ew Array(yti - 99, 107, 115, 32, 43, 32, 49, 41, 41, 46, 102, 105, // cks + 1)).fi - 108, 108, 40, 48, 41, 46, 109, 97, 112, 40, 40, 95, // ll(0).map((_ - 44, 32, 105, 41, 32, 61, 62, 32, 105, 41, 59, 32, // , i) => i); - 32, 47, 47, 32, 105, 110, 100, 105, 99, 101, 115, 10, // // indices. - 32, 32, 108, 101, 116, 32, 121, 116, 105, 32, 61, 32, // let yti = - 105, 32, 61, 62, 32, 104, 32, 45, 32, 104, 50, 32, // i => h - h2 - 45, 32, 40, 104, 32, 45, 32, 104, 49, 32, 45, 32, // - (h - h1 - - 104, 50, 41, 32, 42, 32, 105, 32, 47, 32, 121, 116, // h2) * i / yt - 105, 99, 107, 115, 59, 32, 32, 32, 32, 32, 32, 32, // icks; - 32, 32, 32, 47, 47, 32, 105, 110, 100, 101, 120, 39, // // index' - 115, 32, 89, 10, 32, 32, 108, 101, 116, 32, 121, 116, // s Y. let yt - 118, 32, 61, 32, 105, 32, 61, 62, 32, 40, 121, 109, // v = i => (ym - 97, 120, 32, 45, 32, 121, 109, 105, 110, 41, 32, 42, // ax - ymin) * - 32, 105, 32, 47, 32, 121, 116, 105, 99, 107, 115, 59, // i / yticks; - 10, 32, 32, 108, 101, 116, 32, 121, 116, 108, 32, 61, // . let ytl = - 32, 121, 32, 61, 62, 32, 104, 116, 109, 108, 96, 60, // y => html`< - 108, 105, 110, 101, 32, 120, 49, 61, 36, 123, 119, 49, // line x1=${w1 - 125, 32, 121, 49, 61, 36, 123, 121, 125, 32, 120, 50, // } y1=${y} x2 - 61, 36, 123, 119, 125, 32, 121, 50, 61, 36, 123, 121, // =${w} y2=${y - 125, 32, 99, 108, 97, 115, 115, 61, 34, 116, 105, 99, // } class="tic - 107, 34, 47, 62, 96, 59, 10, 32, 32, 108, 101, 116, // k"/>`;. let - 32, 121, 116, 116, 32, 61, 32, 40, 121, 44, 32, 118, // ytt = (y, v - 41, 32, 61, 62, 32, 104, 116, 109, 108, 96, 60, 116, // ) => html`${v - 125, 60, 47, 116, 101, 120, 116, 62, 96, 59, 10, 10, // }`;.. - 32, 32, 47, 47, 32, 88, 45, 97, 120, 105, 115, 32, // // X-axis - 116, 105, 99, 107, 32, 108, 105, 110, 101, 115, 32, 97, // tick lines a - 110, 100, 32, 108, 97, 98, 101, 108, 115, 10, 32, 32, // nd labels. - 108, 101, 116, 32, 100, 97, 116, 101, 102, 109, 116, 32, // let datefmt - 61, 32, 117, 110, 105, 120, 32, 61, 62, 32, 40, 110, // = unix => (n - 101, 119, 32, 68, 97, 116, 101, 40, 117, 110, 105, 120, // ew Date(unix - 32, 42, 32, 49, 48, 48, 48, 41, 41, 46, 116, 111, // * 1000)).to - 73, 83, 79, 83, 116, 114, 105, 110, 103, 40, 41, 46, // ISOString(). - 115, 117, 98, 115, 116, 114, 40, 49, 52, 44, 32, 53, // substr(14, 5 - 41, 59, 10, 32, 32, 108, 101, 116, 32, 120, 116, 97, // );. let xta - 32, 61, 32, 40, 110, 101, 119, 32, 65, 114, 114, 97, // = (new Arra - 121, 40, 120, 116, 105, 99, 107, 115, 32, 43, 32, 49, // y(xticks + 1 - 41, 41, 46, 102, 105, 108, 108, 40, 48, 41, 46, 109, // )).fill(0).m - 97, 112, 40, 40, 95, 44, 32, 105, 41, 32, 61, 62, // ap((_, i) => - 32, 105, 41, 59, 32, 32, 47, 47, 32, 105, 110, 100, // i); // ind - 105, 99, 101, 115, 10, 32, 32, 108, 101, 116, 32, 120, // ices. let x - 116, 105, 32, 61, 32, 105, 32, 61, 62, 32, 119, 49, // ti = i => w1 - 32, 43, 32, 40, 119, 32, 45, 32, 119, 49, 32, 45, // + (w - w1 - - 32, 119, 50, 41, 32, 42, 32, 105, 32, 47, 32, 120, // w2) * i / x - 116, 105, 99, 107, 115, 59, 32, 32, 32, 32, 32, 32, // ticks; - 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 32, 105, // // i - 110, 100, 101, 120, 39, 115, 32, 88, 10, 32, 32, 108, // ndex's X. l - 101, 116, 32, 120, 116, 118, 32, 61, 32, 105, 32, 61, // et xtv = i = - 62, 32, 100, 97, 116, 101, 102, 109, 116, 40, 120, 109, // > datefmt(xm - 105, 110, 32, 43, 32, 40, 120, 109, 97, 120, 32, 45, // in + (xmax - - 32, 120, 109, 105, 110, 41, 32, 42, 32, 105, 32, 47, // xmin) * i / - 32, 120, 116, 105, 99, 107, 115, 41, 59, 10, 32, 32, // xticks);. - 108, 101, 116, 32, 120, 116, 108, 32, 61, 32, 120, 32, // let xtl = x - 61, 62, 32, 104, 116, 109, 108, 96, 60, 112, 97, 116, // => html``;. let x - 116, 116, 32, 61, 32, 40, 120, 44, 32, 118, 41, 32, // tt = (x, v) - 61, 62, 10, 32, 32, 32, 32, 32, 32, 104, 116, 109, // =>. htm - 108, 96, 60, 116, 101, 120, 116, 32, 120, 61, 36, 123, // l`${v - 125, 60, 47, 116, 101, 120, 116, 62, 96, 59, 10, 10, // }`;.. - 32, 32, 47, 47, 32, 84, 114, 97, 110, 115, 102, 111, // // Transfo - 114, 109, 32, 100, 97, 116, 97, 32, 112, 111, 105, 110, // rm data poin - 116, 115, 32, 97, 114, 114, 97, 121, 32, 105, 110, 116, // ts array int - 111, 32, 99, 111, 111, 114, 100, 105, 110, 97, 116, 101, // o coordinate - 10, 32, 32, 108, 101, 116, 32, 100, 120, 32, 61, 32, // . let dx = - 118, 32, 61, 62, 32, 119, 49, 32, 43, 32, 40, 118, // v => w1 + (v - 32, 45, 32, 120, 109, 105, 110, 41, 32, 47, 32, 40, // - xmin) / ( - 40, 120, 109, 97, 120, 32, 45, 32, 120, 109, 105, 110, // (xmax - xmin - 41, 32, 124, 124, 32, 49, 41, 32, 42, 32, 40, 119, // ) || 1) * (w - 32, 45, 32, 119, 49, 32, 45, 32, 119, 50, 41, 59, // - w1 - w2); - 10, 32, 32, 108, 101, 116, 32, 100, 121, 32, 61, 32, // . let dy = - 118, 32, 61, 62, 32, 104, 32, 45, 32, 104, 50, 32, // v => h - h2 - 45, 32, 40, 118, 32, 45, 32, 121, 109, 105, 110, 41, // - (v - ymin) - 32, 47, 32, 40, 40, 121, 109, 97, 120, 32, 45, 32, // / ((ymax - - 121, 109, 105, 110, 41, 32, 124, 124, 32, 49, 41, 32, // ymin) || 1) - 42, 32, 40, 104, 32, 45, 32, 104, 49, 32, 45, 32, // * (h - h1 - - 104, 50, 41, 59, 10, 32, 32, 108, 101, 116, 32, 100, // h2);. let d - 100, 32, 61, 32, 100, 97, 116, 97, 46, 109, 97, 112, // d = data.map - 40, 112, 32, 61, 62, 32, 91, 77, 97, 116, 104, 46, // (p => [Math. - 114, 111, 117, 110, 100, 40, 100, 120, 40, 112, 91, 48, // round(dx(p[0 - 93, 41, 41, 44, 32, 77, 97, 116, 104, 46, 114, 111, // ])), Math.ro - 117, 110, 100, 40, 100, 121, 40, 112, 91, 49, 93, 41, // und(dy(p[1]) - 41, 93, 41, 59, 10, 32, 32, 108, 101, 116, 32, 100, // )]);. let d - 100, 108, 32, 61, 32, 100, 100, 46, 108, 101, 110, 103, // dl = dd.leng - 116, 104, 59, 10, 32, 32, 47, 47, 32, 65, 110, 100, // th;. // And - 32, 112, 108, 111, 116, 32, 116, 104, 101, 32, 100, 97, // plot the da - 116, 97, 32, 97, 115, 32, 60, 112, 97, 116, 104, 62, // ta as - 32, 101, 108, 101, 109, 101, 110, 116, 10, 32, 32, 108, // element. l - 101, 116, 32, 98, 101, 103, 105, 110, 48, 32, 61, 32, // et begin0 = - 100, 100, 108, 32, 63, 32, 96, 77, 32, 36, 123, 100, // ddl ? `M ${d - 100, 91, 48, 93, 91, 48, 93, 125, 44, 36, 123, 100, // d[0][0]},${d - 100, 91, 48, 93, 91, 49, 93, 125, 96, 32, 58, 32, // d[0][1]}` : - 96, 77, 32, 48, 44, 48, 96, 59, 10, 32, 32, 108, // `M 0,0`;. l - 101, 116, 32, 98, 101, 103, 105, 110, 32, 61, 32, 96, // et begin = ` - 77, 32, 36, 123, 119, 49, 125, 44, 36, 123, 104, 32, // M ${w1},${h - 45, 32, 104, 50, 125, 96, 59, 32, 32, 47, 47, 32, // - h2}`; // - 73, 110, 105, 116, 105, 97, 108, 32, 112, 111, 105, 110, // Initial poin - 116, 10, 32, 32, 108, 101, 116, 32, 101, 110, 100, 32, // t. let end - 61, 32, 100, 100, 108, 32, 63, 32, 96, 76, 32, 36, // = ddl ? `L $ - 123, 100, 100, 91, 100, 100, 108, 32, 45, 32, 49, 93, // {dd[ddl - 1] - 91, 48, 93, 125, 44, 36, 123, 104, 32, 45, 32, 104, // [0]},${h - h - 50, 125, 96, 32, 58, 32, 96, 76, 32, 36, 123, 119, // 2}` : `L ${w - 49, 125, 44, 36, 123, 104, 32, 45, 32, 104, 50, 125, // 1},${h - h2} - 96, 59, 10, 32, 32, 108, 101, 116, 32, 115, 101, 114, // `;. let ser - 105, 101, 115, 32, 61, 32, 100, 100, 108, 32, 63, 32, // ies = ddl ? - 100, 100, 46, 109, 97, 112, 40, 112, 32, 61, 62, 32, // dd.map(p => - 96, 76, 32, 36, 123, 112, 91, 48, 93, 125, 32, 36, // `L ${p[0]} $ - 123, 112, 91, 49, 93, 125, 96, 41, 32, 58, 32, 91, // {p[1]}`) : [ - 93, 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, // . `;.};...con - 115, 116, 32, 67, 104, 97, 114, 116, 32, 61, 32, 102, // st Chart = 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, 100, 97, 116, 97, 44, 32, 115, 101, 116, 68, // [data, setD - 97, 116, 97, 93, 32, 61, 32, 117, 115, 101, 83, 116, // ata] = useSt - 97, 116, 101, 40, 91, 93, 41, 59, 10, 32, 32, 117, // ate([]);. u - 115, 101, 69, 102, 102, 101, 99, 116, 40, 40, 41, 32, // seEffect(() - 61, 62, 32, 123, 10, 32, 32, 32, 32, 99, 111, 110, // => {. con - 115, 116, 32, 105, 100, 32, 61, 32, 80, 117, 98, 83, // st id = PubS - 117, 98, 46, 115, 117, 98, 115, 99, 114, 105, 98, 101, // ub.subscribe - 40, 102, 117, 110, 99, 116, 105, 111, 110, 40, 109, 115, // (function(ms - 103, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, 105, // g) {. 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, 114, 101, 116, 117, 114, 110, 59, 10, 32, 32, // ) return;. - 32, 32, 32, 32, 115, 101, 116, 68, 97, 116, 97, 40, // setData( - 120, 32, 61, 62, 32, 120, 46, 99, 111, 110, 99, 97, // x => x.conca - 116, 40, 91, 109, 115, 103, 46, 100, 97, 116, 97, 93, // t([msg.data] - 41, 46, 115, 112, 108, 105, 99, 101, 40, 45, 77, 97, // ).splice(-Ma - 120, 77, 101, 116, 114, 105, 99, 115, 68, 97, 116, 97, // xMetricsData - 80, 111, 105, 110, 116, 115, 41, 41, 59, 10, 32, 32, // Points));. - 32, 32, 125, 41, 59, 10, 32, 32, 32, 32, 114, 101, // });. re - 116, 117, 114, 110, 32, 80, 117, 98, 83, 117, 98, 46, // turn PubSub. - 117, 110, 115, 117, 98, 115, 99, 114, 105, 98, 101, 40, // unsubscribe( - 105, 100, 41, 59, 10, 32, 32, 125, 44, 32, 91, 93, // id);. }, [] - 41, 59, 10, 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, 100, 97, 116, 97, 46, 108, 101, // ts - data.le - 110, 103, 116, 104, 59, 10, 32, 32, 105, 102, 32, 40, // ngth;. if ( - 109, 105, 115, 115, 105, 110, 103, 32, 62, 32, 48, 41, // missing > 0) - 32, 120, 109, 97, 120, 32, 61, 32, 77, 97, 116, 104, // xmax = Math - 46, 114, 111, 117, 110, 100, 40, 68, 97, 116, 101, 46, // .round(Date. - 110, 111, 119, 40, 41, 32, 47, 32, 49, 48, 48, 48, // now() / 1000 - 41, 32, 43, 32, 109, 105, 115, 115, 105, 110, 103, 59, // ) + missing; - 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 104, 116, // . return ht - 109, 108, 96, 10, 60, 100, 105, 118, 32, 99, 108, 97, // ml`.
.

Data Char - 116, 60, 47, 104, 51, 62, 10, 32, 32, 60, 100, 105, // t

. . <${S - 86, 71, 125, 32, 104, 101, 105, 103, 104, 116, 61, 50, // VG} height=2 - 52, 48, 32, 119, 105, 100, 116, 104, 61, 54, 48, 48, // 40 width=600 - 32, 121, 109, 105, 110, 61, 48, 32, 121, 109, 97, 120, // ymin=0 ymax - 61, 50, 48, 32, 120, 109, 97, 120, 61, 36, 123, 120, // =20 xmax=${x - 109, 97, 120, 125, 32, 100, 97, 116, 97, 61, 36, 123, // max} data=${ - 100, 97, 116, 97, 125, 32, 47, 62, 10, 32, 32, 60, // data} />. < - 47, 100, 105, 118, 62, 10, 32, 32, 60, 100, 105, 118, // /div>.
. This c - 104, 97, 114, 116, 32, 112, 108, 111, 116, 115, 32, 108, // hart plots l - 105, 118, 101, 32, 115, 101, 110, 115, 111, 114, 32, 100, // ive sensor d - 97, 116, 97, 44, 32, 115, 101, 110, 116, 32, 98, 121, // ata, sent by - 32, 97, 32, 100, 101, 118, 105, 99, 101, 32, 118, 105, // a device vi - 97, 32, 47, 97, 112, 105, 47, 119, 97, 116, 99, 104, // a /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>`;.};.. - 99, 111, 110, 115, 116, 32, 65, 112, 112, 32, 61, 32, // const App = - 102, 117, 110, 99, 116, 105, 111, 110, 40, 112, 114, 111, // function(pro - 112, 115, 41, 32, 123, 10, 32, 32, 99, 111, 110, 115, // ps) {. cons - 116, 32, 91, 117, 115, 101, 114, 44, 32, 115, 101, 116, // t [user, set - 85, 115, 101, 114, 93, 32, 61, 32, 117, 115, 101, 83, // User] = useS - 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, 10, 32, // tate('');.. - 32, 99, 111, 110, 115, 116, 32, 103, 101, 116, 99, 111, // const getco - 110, 102, 105, 103, 32, 61, 32, 40, 41, 32, 61, 62, // nfig = () => - 10, 32, 32, 32, 32, 32, 32, 102, 101, 116, 99, 104, // . fetch - 40, 39, 47, 97, 112, 105, 47, 99, 111, 110, 102, 105, // ('/api/confi - 103, 47, 103, 101, 116, 39, 44, 32, 123, 104, 101, 97, // g/get', {hea - 100, 101, 114, 115, 58, 32, 123, 65, 117, 116, 104, 111, // ders: {Autho - 114, 105, 122, 97, 116, 105, 111, 110, 58, 32, 39, 39, // rization: '' - 125, 125, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, // }}). - 32, 32, 46, 116, 104, 101, 110, 40, 114, 32, 61, 62, // .then(r => - 32, 114, 46, 106, 115, 111, 110, 40, 41, 41, 10, 32, // r.json()). - 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, // .th - 101, 110, 40, 114, 32, 61, 62, 32, 80, 117, 98, 83, // en(r => PubS - 117, 98, 46, 112, 117, 98, 108, 105, 115, 104, 40, 123, // ub.publish({ - 110, 97, 109, 101, 58, 32, 39, 110, 101, 119, 99, 111, // name: 'newco - 110, 102, 105, 103, 39, 44, 32, 100, 97, 116, 97, 58, // nfig', data: - 32, 114, 125, 41, 41, 59, 10, 10, 32, 32, 99, 111, // r}));.. co - 110, 115, 116, 32, 108, 111, 103, 105, 110, 32, 61, 32, // nst login = - 102, 117, 110, 99, 116, 105, 111, 110, 40, 117, 41, 32, // function(u) - 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, 36, 123, 117, 46, 116, 111, 107, 101, 110, 125, // n=${u.token} - 59, 112, 97, 116, 104, 61, 47, 59, 109, 97, 120, 45, // ;path=/;max- - 97, 103, 101, 61, 51, 54, 48, 48, 96, 59, 10, 32, // age=3600`;. - 32, 32, 32, 115, 101, 116, 85, 115, 101, 114, 40, 117, // setUser(u - 46, 117, 115, 101, 114, 41, 59, 10, 32, 32, 32, 32, // .user);. - 114, 101, 116, 117, 114, 110, 32, 103, 101, 116, 99, 111, // return getco - 110, 102, 105, 103, 40, 41, 59, 10, 32, 32, 125, 59, // nfig();. }; - 10, 10, 32, 32, 99, 111, 110, 115, 116, 32, 108, 111, // .. const lo - 103, 111, 117, 116, 32, 61, 32, 101, 118, 32, 61, 62, // gout = ev => - 32, 123, 10, 32, 32, 32, 32, 100, 111, 99, 117, 109, // {. docum - 101, 110, 116, 46, 99, 111, 111, 107, 105, 101, 32, 61, // ent.cookie = - 32, 96, 97, 99, 99, 101, 115, 115, 95, 116, 111, 107, // `access_tok - 101, 110, 61, 59, 112, 97, 116, 104, 61, 47, 59, 109, // en=;path=/;m - 97, 120, 45, 97, 103, 101, 61, 48, 96, 59, 10, 32, // ax-age=0`;. - 32, 32, 32, 115, 101, 116, 85, 115, 101, 114, 40, 39, // setUser(' - 39, 41, 59, 10, 32, 32, 125, 59, 10, 10, 32, 32, // ');. };.. - 47, 47, 32, 87, 97, 116, 99, 104, 32, 102, 111, 114, // // Watch for - 32, 110, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, // notificatio - 110, 115, 46, 32, 65, 115, 32, 115, 111, 111, 110, 32, // ns. As soon - 97, 115, 32, 97, 32, 110, 111, 116, 105, 102, 105, 99, // as a notific - 97, 116, 105, 111, 110, 32, 97, 114, 114, 105, 118, 101, // ation arrive - 115, 44, 32, 112, 97, 115, 115, 32, 105, 116, 32, 111, // s, pass it o - 110, 10, 32, 32, 47, 47, 32, 116, 111, 32, 97, 108, // n. // to al - 108, 32, 115, 117, 98, 115, 99, 114, 105, 98, 101, 100, // l subscribed - 32, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 10, // components. - 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, 108, 32, 61, 32, 119, 105, 110, 100, 111, 119, 46, // l = window. - 108, 111, 99, 97, 116, 105, 111, 110, 44, 32, 112, 114, // location, pr - 111, 116, 111, 32, 61, 32, 108, 46, 112, 114, 111, 116, // oto = l.prot - 111, 99, 111, 108, 46, 114, 101, 112, 108, 97, 99, 101, // ocol.replace - 40, 39, 104, 116, 116, 112, 39, 44, 32, 39, 119, 115, // ('http', 'ws - 39, 41, 59, 10, 32, 32, 32, 32, 118, 97, 114, 32, // ');. var - 116, 105, 100, 44, 32, 119, 115, 85, 82, 73, 32, 61, // tid, wsURI = - 32, 112, 114, 111, 116, 111, 32, 43, 32, 39, 47, 47, // proto + '// - 39, 32, 43, 32, 108, 46, 104, 111, 115, 116, 32, 43, // ' + l.host + - 32, 39, 47, 97, 112, 105, 47, 119, 97, 116, 99, 104, // '/api/watch - 39, 10, 32, 32, 32, 32, 118, 97, 114, 32, 114, 101, // '. var re - 99, 111, 110, 110, 101, 99, 116, 32, 61, 32, 102, 117, // connect = fu - 110, 99, 116, 105, 111, 110, 40, 41, 32, 123, 10, 32, // nction() {. - 32, 32, 32, 32, 32, 118, 97, 114, 32, 119, 115, 32, // var ws - 61, 32, 110, 101, 119, 32, 87, 101, 98, 83, 111, 99, // = new WebSoc - 107, 101, 116, 40, 119, 115, 85, 82, 73, 41, 59, 10, // ket(wsURI);. + 10, 99, 111, 110, 115, 116, 32, 65, 112, 112, 32, 61, // .const App = + 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, 117, 115, 101, 114, 44, 32, 115, 101, // st [user, se + 116, 85, 115, 101, 114, 93, 32, 61, 32, 117, 115, 101, // tUser] = use + 83, 116, 97, 116, 101, 40, 39, 39, 41, 59, 10, 32, // State('');. + 32, 99, 111, 110, 115, 116, 32, 91, 99, 111, 110, 102, // const [conf + 105, 103, 44, 32, 115, 101, 116, 67, 111, 110, 102, 105, // ig, setConfi + 103, 93, 32, 61, 32, 117, 115, 101, 83, 116, 97, 116, // g] = useStat + 101, 40, 123, 125, 41, 59, 10, 10, 32, 32, 99, 111, // e({});.. co + 110, 115, 116, 32, 103, 101, 116, 99, 111, 110, 102, 105, // nst getconfi + 103, 32, 61, 32, 40, 41, 32, 61, 62, 10, 32, 32, // g = () =>. + 32, 32, 32, 32, 102, 101, 116, 99, 104, 40, 39, 47, // fetch('/ + 97, 112, 105, 47, 99, 111, 110, 102, 105, 103, 47, 103, // api/config/g + 101, 116, 39, 44, 32, 123, 104, 101, 97, 100, 101, 114, // et', {header + 115, 58, 32, 123, 65, 117, 116, 104, 111, 114, 105, 122, // s: {Authoriz + 97, 116, 105, 111, 110, 58, 32, 39, 39, 125, 125, 41, // ation: ''}}) + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, // . . + 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 114, 46, // then(r => r. + 106, 115, 111, 110, 40, 41, 41, 10, 32, 32, 32, 32, // json()). + 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, // .then( + 114, 32, 61, 62, 32, 115, 101, 116, 67, 111, 110, 102, // r => setConf + 105, 103, 40, 114, 41, 41, 10, 32, 32, 32, 32, 32, // ig(r)). + 32, 32, 32, 32, 32, 46, 99, 97, 116, 99, 104, 40, // .catch( + 101, 114, 114, 32, 61, 62, 32, 99, 111, 110, 115, 111, // err => conso + 108, 101, 46, 108, 111, 103, 40, 101, 114, 114, 41, 41, // le.log(err)) + 59, 10, 10, 32, 32, 99, 111, 110, 115, 116, 32, 108, // ;.. const l + 111, 103, 105, 110, 32, 61, 32, 102, 117, 110, 99, 116, // ogin = funct + 105, 111, 110, 40, 117, 41, 32, 123, 10, 32, 32, 32, // ion(u) {. + 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 111, // document.co + 111, 107, 105, 101, 32, 61, 32, 96, 97, 99, 99, 101, // okie = `acce + 115, 115, 95, 116, 111, 107, 101, 110, 61, 36, 123, 117, // ss_token=${u + 46, 116, 111, 107, 101, 110, 125, 59, 112, 97, 116, 104, // .token};path + 61, 47, 59, 109, 97, 120, 45, 97, 103, 101, 61, 51, // =/;max-age=3 + 54, 48, 48, 96, 59, 10, 32, 32, 32, 32, 115, 101, // 600`;. se + 116, 85, 115, 101, 114, 40, 117, 46, 117, 115, 101, 114, // tUser(u.user + 41, 59, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, // );. retur + 110, 32, 103, 101, 116, 99, 111, 110, 102, 105, 103, 40, // n getconfig( + 41, 59, 10, 32, 32, 125, 59, 10, 10, 32, 32, 99, // );. };.. c + 111, 110, 115, 116, 32, 108, 111, 103, 111, 117, 116, 32, // onst logout + 61, 32, 101, 118, 32, 61, 62, 32, 123, 10, 32, 32, // = ev => {. + 32, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, // document.c + 111, 111, 107, 105, 101, 32, 61, 32, 96, 97, 99, 99, // ookie = `acc + 101, 115, 115, 95, 116, 111, 107, 101, 110, 61, 59, 112, // ess_token=;p + 97, 116, 104, 61, 47, 59, 109, 97, 120, 45, 97, 103, // ath=/;max-ag + 101, 61, 48, 96, 59, 10, 32, 32, 32, 32, 115, 101, // e=0`;. se + 116, 85, 115, 101, 114, 40, 39, 39, 41, 59, 10, 32, // tUser('');. + 32, 125, 59, 10, 10, 32, 32, 47, 47, 32, 87, 97, // };.. // Wa + 116, 99, 104, 32, 102, 111, 114, 32, 110, 111, 116, 105, // tch for noti + 102, 105, 99, 97, 116, 105, 111, 110, 115, 46, 32, 65, // fications. A + 115, 32, 115, 111, 111, 110, 32, 97, 115, 32, 97, 32, // s soon as a + 110, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, // notification + 32, 97, 114, 114, 105, 118, 101, 115, 44, 32, 112, 97, // arrives, pa + 115, 115, 32, 105, 116, 32, 111, 110, 10, 32, 32, 47, // ss it on. / + 47, 32, 116, 111, 32, 97, 108, 108, 32, 115, 117, 98, // / to all sub + 115, 99, 114, 105, 98, 101, 100, 32, 99, 111, 109, 112, // scribed comp + 111, 110, 101, 110, 116, 115, 10, 32, 32, 99, 111, 110, // onents. con + 115, 116, 32, 119, 97, 116, 99, 104, 32, 61, 32, 102, // st watch = f + 117, 110, 99, 116, 105, 111, 110, 40, 41, 32, 123, 10, // unction() {. + 32, 32, 32, 32, 118, 97, 114, 32, 108, 32, 61, 32, // var l = + 119, 105, 110, 100, 111, 119, 46, 108, 111, 99, 97, 116, // window.locat + 105, 111, 110, 44, 32, 112, 114, 111, 116, 111, 32, 61, // ion, proto = + 32, 108, 46, 112, 114, 111, 116, 111, 99, 111, 108, 46, // l.protocol. + 114, 101, 112, 108, 97, 99, 101, 40, 39, 104, 116, 116, // replace('htt + 112, 39, 44, 32, 39, 119, 115, 39, 41, 59, 10, 32, // p', 'ws');. + 32, 32, 32, 118, 97, 114, 32, 116, 105, 100, 44, 32, // var tid, + 119, 115, 85, 82, 73, 32, 61, 32, 112, 114, 111, 116, // wsURI = prot + 111, 32, 43, 32, 39, 47, 47, 39, 32, 43, 32, 108, // o + '//' + l + 46, 104, 111, 115, 116, 32, 43, 32, 39, 47, 97, 112, // .host + '/ap + 105, 47, 119, 97, 116, 99, 104, 39, 10, 32, 32, 32, // i/watch'. + 32, 118, 97, 114, 32, 114, 101, 99, 111, 110, 110, 101, // var reconne + 99, 116, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, // ct = functio + 110, 40, 41, 32, 123, 10, 32, 32, 32, 32, 32, 32, // n() {. + 118, 97, 114, 32, 119, 115, 32, 61, 32, 110, 101, 119, // var ws = new + 32, 87, 101, 98, 83, 111, 99, 107, 101, 116, 40, 119, // WebSocket(w + 115, 85, 82, 73, 41, 59, 10, 32, 32, 32, 32, 32, // sURI);. + 32, 119, 115, 46, 111, 110, 111, 112, 101, 110, 32, 61, // ws.onopen = + 32, 40, 41, 32, 61, 62, 32, 99, 111, 110, 115, 111, // () => conso + 108, 101, 46, 108, 111, 103, 40, 39, 119, 115, 32, 99, // le.log('ws c + 111, 110, 110, 101, 99, 116, 101, 100, 39, 41, 59, 10, // onnected');. 32, 32, 32, 32, 32, 32, 119, 115, 46, 111, 110, 109, // ws.onm 101, 115, 115, 97, 103, 101, 32, 61, 32, 102, 117, 110, // essage = fun 99, 116, 105, 111, 110, 40, 101, 118, 41, 32, 123, 10, // ction(ev) {. @@ -1118,33 +1124,37 @@ static const unsigned char v2[] = { 100, 32, 61, 32, 115, 101, 116, 84, 105, 109, 101, 111, // d = setTimeo 117, 116, 40, 114, 101, 99, 111, 110, 110, 101, 99, 116, // ut(reconnect 44, 32, 49, 48, 48, 48, 41, 59, 10, 32, 32, 32, // , 1000);. - 32, 32, 32, 125, 59, 10, 32, 32, 32, 32, 125, 59, // };. }; - 10, 32, 32, 32, 32, 114, 101, 99, 111, 110, 110, 101, // . reconne - 99, 116, 40, 41, 59, 10, 32, 32, 125, 59, 10, 10, // ct();. };.. - 32, 32, 117, 115, 101, 69, 102, 102, 101, 99, 116, 40, // useEffect( - 40, 41, 32, 61, 62, 32, 123, 10, 32, 32, 32, 32, // () => {. - 47, 47, 32, 67, 97, 108, 108, 101, 100, 32, 111, 110, // // Called on - 99, 101, 32, 97, 116, 32, 105, 110, 105, 116, 32, 116, // ce at init t - 105, 109, 101, 10, 32, 32, 32, 32, 102, 101, 116, 99, // ime. fetc - 104, 40, 39, 47, 97, 112, 105, 47, 108, 111, 103, 105, // h('/api/logi - 110, 39, 44, 32, 123, 104, 101, 97, 100, 101, 114, 115, // n', {headers - 58, 32, 123, 65, 117, 116, 104, 111, 114, 105, 122, 97, // : {Authoriza - 116, 105, 111, 110, 58, 32, 39, 39, 125, 125, 41, 10, // tion: ''}}). - 32, 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, // .the - 110, 40, 114, 32, 61, 62, 32, 114, 46, 106, 115, 111, // n(r => r.jso - 110, 40, 41, 41, 10, 32, 32, 32, 32, 32, 32, 32, // n()). - 32, 46, 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, // .then(r => - 108, 111, 103, 105, 110, 40, 114, 41, 41, 10, 32, 32, // login(r)). - 32, 32, 32, 32, 32, 32, 46, 99, 97, 116, 99, 104, // .catch - 40, 101, 114, 114, 32, 61, 62, 32, 115, 101, 116, 85, // (err => setU - 115, 101, 114, 40, 39, 39, 41, 41, 59, 10, 32, 32, // ser(''));. - 32, 32, 119, 97, 116, 99, 104, 40, 41, 59, 10, 32, // watch();. - 32, 32, 32, 80, 117, 98, 83, 117, 98, 46, 115, 117, // PubSub.su - 98, 115, 99, 114, 105, 98, 101, 40, 109, 115, 103, 32, // bscribe(msg - 61, 62, 32, 109, 115, 103, 46, 110, 97, 109, 101, 32, // => msg.name - 61, 61, 32, 39, 99, 111, 110, 102, 105, 103, 39, 32, // == 'config' - 38, 38, 32, 103, 101, 116, 99, 111, 110, 102, 105, 103, // && getconfig - 40, 41, 41, 59, 10, 32, 32, 125, 44, 32, 91, 93, // ());. }, [] + 32, 32, 32, 32, 32, 99, 111, 110, 115, 111, 108, 101, // console + 46, 108, 111, 103, 40, 39, 119, 115, 32, 100, 105, 115, // .log('ws dis + 99, 111, 110, 110, 101, 99, 116, 101, 100, 39, 41, 59, // connected'); + 10, 32, 32, 32, 32, 32, 32, 125, 59, 10, 32, 32, // . };. + 32, 32, 125, 59, 10, 32, 32, 32, 32, 114, 101, 99, // };. rec + 111, 110, 110, 101, 99, 116, 40, 41, 59, 10, 32, 32, // onnect();. + 125, 59, 10, 10, 32, 32, 117, 115, 101, 69, 102, 102, // };.. useEff + 101, 99, 116, 40, 40, 41, 32, 61, 62, 32, 123, 10, // ect(() => {. + 32, 32, 32, 32, 47, 47, 32, 67, 97, 108, 108, 101, // // Calle + 100, 32, 111, 110, 99, 101, 32, 97, 116, 32, 105, 110, // d once at in + 105, 116, 32, 116, 105, 109, 101, 10, 32, 32, 32, 32, // it time. + 80, 117, 98, 83, 117, 98, 46, 115, 117, 98, 115, 99, // PubSub.subsc + 114, 105, 98, 101, 40, 109, 115, 103, 32, 61, 62, 32, // ribe(msg => + 109, 115, 103, 46, 110, 97, 109, 101, 32, 61, 61, 32, // msg.name == + 39, 99, 111, 110, 102, 105, 103, 39, 32, 38, 38, 32, // 'config' && + 103, 101, 116, 99, 111, 110, 102, 105, 103, 40, 41, 41, // getconfig()) + 59, 10, 32, 32, 32, 32, 102, 101, 116, 99, 104, 40, // ;. fetch( + 39, 47, 97, 112, 105, 47, 108, 111, 103, 105, 110, 39, // '/api/login' + 44, 32, 123, 104, 101, 97, 100, 101, 114, 115, 58, 32, // , {headers: + 123, 65, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, // {Authorizati + 111, 110, 58, 32, 39, 39, 125, 125, 41, 10, 32, 32, // on: ''}}). + 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, // .then( + 114, 32, 61, 62, 32, 114, 46, 106, 115, 111, 110, 40, // r => r.json( + 41, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 46, // )). . + 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 108, 111, // then(r => lo + 103, 105, 110, 40, 114, 41, 41, 10, 32, 32, 32, 32, // gin(r)). + 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, 119, 97, // .then(wa + 116, 99, 104, 41, 10, 32, 32, 32, 32, 32, 32, 32, // tch). + 32, 46, 99, 97, 116, 99, 104, 40, 101, 114, 114, 32, // .catch(err + 61, 62, 32, 115, 101, 116, 85, 115, 101, 114, 40, 39, // => setUser(' + 39, 41, 41, 59, 10, 32, 32, 125, 44, 32, 91, 93, // '));. }, [] 41, 59, 10, 10, 32, 32, 105, 102, 32, 40, 33, 117, // );.. if (!u 115, 101, 114, 41, 32, 114, 101, 116, 117, 114, 110, 32, // ser) return 104, 116, 109, 108, 96, 60, 36, 123, 76, 111, 103, 105, // html`<${Logi @@ -1168,22 +1178,24 @@ static const unsigned char v2[] = { 125, 32, 47, 62, 60, 47, 100, 105, 118, 62, 10, 32, // } />
. 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, //
${user == - 39, 97, 100, 109, 105, 110, 39, 32, 38, 38, 32, 104, // 'admin' && h - 40, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, // (Configurati - 111, 110, 41, 125, 60, 47, 100, 105, 118, 62, 10, 32, // on)}
. - 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, //
<${Message - 115, 125, 32, 47, 62, 60, 47, 100, 105, 118, 62, 10, // s} />
. - 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, // . < - 36, 123, 70, 111, 111, 116, 101, 114, 125, 32, 47, 62, // ${Footer} /> - 10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, // .`;.}; - 10, 10, 119, 105, 110, 100, 111, 119, 46, 111, 110, 108, // ..window.onl - 111, 97, 100, 32, 61, 32, 40, 41, 32, 61, 62, 32, // oad = () => - 114, 101, 110, 100, 101, 114, 40, 104, 40, 65, 112, 112, // render(h(App - 41, 44, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, // ), document. - 98, 111, 100, 121, 41, 59, 10, 0 // body);. + 34, 62, 10, 32, 32, 32, 32, 32, 32, 36, 123, 117, // ">. ${u + 115, 101, 114, 32, 61, 61, 32, 39, 97, 100, 109, 105, // ser == 'admi + 110, 39, 32, 38, 38, 32, 104, 40, 67, 111, 110, 102, // n' && h(Conf + 105, 103, 117, 114, 97, 116, 105, 111, 110, 44, 32, 123, // iguration, { + 99, 111, 110, 102, 105, 103, 125, 41, 125, 10, 32, 32, // config})}. + 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, 32, // . + 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, //
+ 60, 36, 123, 77, 101, 115, 115, 97, 103, 101, 115, 125, // <${Messages} + 32, 99, 111, 110, 102, 105, 103, 61, 36, 123, 99, 111, // config=${co + 110, 102, 105, 103, 125, 32, 47, 62, 60, 47, 100, 105, // nfig} />.
. + 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, @@ -2381,63 +2393,66 @@ static const unsigned char v4[] = { 110, 58, 32, 49, 101, 109, 32, 48, 59, 32, 125, 10, // n: 1em 0; }. 46, 115, 101, 99, 116, 105, 111, 110, 32, 123, 32, 109, // .section { m 97, 114, 103, 105, 110, 58, 32, 48, 32, 49, 101, 109, // argin: 0 1em - 59, 32, 125, 10, 46, 116, 111, 112, 105, 99, 32, 123, // ; }..topic { - 32, 98, 97, 99, 107, 103, 114, 111, 117, 110, 100, 58, // background: - 32, 35, 102, 101, 97, 59, 32, 112, 97, 100, 100, 105, // #fea; paddi - 110, 103, 58, 32, 48, 46, 50, 101, 109, 32, 49, 101, // ng: 0.2em 1e - 109, 59, 32, 98, 111, 114, 100, 101, 114, 45, 114, 97, // m; border-ra - 100, 105, 117, 115, 58, 32, 48, 46, 52, 101, 109, 59, // dius: 0.4em; - 32, 125, 10, 46, 100, 97, 116, 97, 32, 123, 32, 98, // }..data { b - 97, 99, 107, 103, 114, 111, 117, 110, 100, 58, 32, 35, // ackground: # - 97, 101, 102, 59, 32, 112, 97, 100, 100, 105, 110, 103, // aef; padding - 58, 32, 48, 46, 50, 101, 109, 32, 49, 101, 109, 59, // : 0.2em 1em; + 59, 32, 125, 10, 46, 116, 111, 112, 105, 99, 44, 32, // ; }..topic, + 46, 100, 97, 116, 97, 44, 32, 46, 113, 111, 115, 32, // .data, .qos + 123, 32, 32, 112, 97, 100, 100, 105, 110, 103, 58, 32, // { padding: + 48, 46, 50, 101, 109, 32, 48, 46, 53, 101, 109, 59, // 0.2em 0.5em; 32, 98, 111, 114, 100, 101, 114, 45, 114, 97, 100, 105, // border-radi - 117, 115, 58, 32, 48, 46, 52, 101, 109, 59, 32, 125, // us: 0.4em; } - 10, 10, 47, 42, 32, 71, 114, 105, 100, 32, 42, 47, // ../* Grid */ - 10, 46, 114, 111, 119, 32, 123, 32, 100, 105, 115, 112, // ..row { disp - 108, 97, 121, 58, 32, 102, 108, 101, 120, 59, 32, 102, // lay: flex; f - 108, 101, 120, 45, 119, 114, 97, 112, 58, 32, 119, 114, // lex-wrap: wr - 97, 112, 59, 32, 125, 10, 46, 99, 111, 108, 32, 123, // ap; }..col { - 32, 109, 97, 114, 103, 105, 110, 58, 32, 48, 59, 32, // margin: 0; - 112, 97, 100, 100, 105, 110, 103, 58, 32, 48, 59, 32, // padding: 0; - 111, 118, 101, 114, 102, 108, 111, 119, 58, 32, 97, 117, // overflow: au - 116, 111, 59, 32, 125, 10, 46, 99, 111, 108, 45, 49, // to; }..col-1 - 50, 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, // 2 { width: 1 - 48, 48, 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, // 00%; }..col- - 49, 49, 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, // 11 { width: - 57, 49, 46, 54, 54, 37, 59, 32, 125, 10, 46, 99, // 91.66%; }..c - 111, 108, 45, 49, 48, 32, 123, 32, 119, 105, 100, 116, // ol-10 { widt - 104, 58, 32, 56, 51, 46, 51, 51, 37, 59, 32, 125, // h: 83.33%; } - 10, 46, 99, 111, 108, 45, 57, 32, 123, 32, 119, 105, // ..col-9 { wi - 100, 116, 104, 58, 32, 55, 53, 37, 59, 32, 125, 10, // dth: 75%; }. - 46, 99, 111, 108, 45, 56, 32, 123, 32, 119, 105, 100, // .col-8 { wid - 116, 104, 58, 32, 54, 54, 46, 54, 54, 37, 59, 32, // th: 66.66%; - 125, 10, 46, 99, 111, 108, 45, 55, 32, 123, 32, 119, // }..col-7 { w - 105, 100, 116, 104, 58, 32, 53, 56, 46, 51, 51, 37, // idth: 58.33% - 59, 32, 125, 10, 46, 99, 111, 108, 45, 54, 32, 123, // ; }..col-6 { - 32, 119, 105, 100, 116, 104, 58, 32, 53, 48, 37, 59, // width: 50%; - 32, 125, 10, 46, 99, 111, 108, 45, 53, 32, 123, 32, // }..col-5 { - 119, 105, 100, 116, 104, 58, 32, 52, 49, 46, 54, 54, // width: 41.66 - 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 52, 32, // %; }..col-4 - 123, 32, 119, 105, 100, 116, 104, 58, 32, 51, 51, 46, // { width: 33. - 51, 51, 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, // 33%; }..col- - 51, 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 50, // 3 { width: 2 - 53, 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 50, // 5%; }..col-2 - 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, 54, // { width: 16 + 117, 115, 58, 32, 48, 46, 52, 101, 109, 59, 32, 109, // us: 0.4em; m + 97, 114, 103, 105, 110, 45, 114, 105, 103, 104, 116, 58, // argin-right: + 32, 48, 46, 53, 101, 109, 59, 32, 32, 125, 10, 46, // 0.5em; }.. + 113, 111, 115, 32, 123, 32, 98, 97, 99, 107, 103, 114, // qos { backgr + 111, 117, 110, 100, 58, 32, 35, 101, 102, 97, 59, 32, // ound: #efa; + 125, 10, 46, 116, 111, 112, 105, 99, 32, 123, 32, 98, // }..topic { b + 97, 99, 107, 103, 114, 111, 117, 110, 100, 58, 32, 35, // ackground: # + 102, 101, 97, 59, 32, 125, 10, 46, 100, 97, 116, 97, // fea; }..data + 32, 123, 32, 98, 97, 99, 107, 103, 114, 111, 117, 110, // { backgroun + 100, 58, 32, 35, 97, 101, 102, 59, 32, 125, 10, 10, // d: #aef; }.. + 47, 42, 32, 71, 114, 105, 100, 32, 42, 47, 10, 46, // /* Grid */.. + 114, 111, 119, 32, 123, 32, 100, 105, 115, 112, 108, 97, // row { displa + 121, 58, 32, 102, 108, 101, 120, 59, 32, 102, 108, 101, // y: flex; fle + 120, 45, 119, 114, 97, 112, 58, 32, 119, 114, 97, 112, // x-wrap: wrap + 59, 32, 125, 10, 46, 99, 111, 108, 32, 123, 32, 109, // ; }..col { m + 97, 114, 103, 105, 110, 58, 32, 48, 59, 32, 112, 97, // argin: 0; pa + 100, 100, 105, 110, 103, 58, 32, 48, 59, 32, 111, 118, // dding: 0; ov + 101, 114, 102, 108, 111, 119, 58, 32, 97, 117, 116, 111, // erflow: auto + 59, 32, 125, 10, 46, 99, 111, 108, 45, 49, 50, 32, // ; }..col-12 + 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, 48, 48, // { width: 100 + 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 49, 49, // %; }..col-11 + 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 57, 49, // { width: 91 46, 54, 54, 37, 59, 32, 125, 10, 46, 99, 111, 108, // .66%; }..col - 45, 49, 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, // -1 { width: - 56, 46, 51, 51, 37, 59, 32, 125, 10, 64, 109, 101, // 8.33%; }.@me - 100, 105, 97, 32, 40, 109, 105, 110, 45, 119, 105, 100, // dia (min-wid - 116, 104, 58, 32, 49, 51, 49, 48, 112, 120, 41, 32, // th: 1310px) - 123, 32, 46, 99, 111, 110, 116, 97, 105, 110, 101, 114, // { .container - 32, 123, 32, 109, 97, 114, 103, 105, 110, 58, 32, 97, // { margin: a - 117, 116, 111, 59, 32, 119, 105, 100, 116, 104, 58, 32, // uto; width: - 49, 50, 55, 48, 112, 120, 59, 32, 125, 32, 125, 10, // 1270px; } }. - 64, 109, 101, 100, 105, 97, 32, 40, 109, 97, 120, 45, // @media (max- - 119, 105, 100, 116, 104, 58, 32, 57, 50, 48, 112, 120, // width: 920px - 41, 32, 123, 32, 46, 114, 111, 119, 32, 46, 99, 111, // ) { .row .co - 108, 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 49, // l { width: 1 - 48, 48, 37, 59, 32, 125, 32, 125, 10, 0 // 00%; } }. + 45, 49, 48, 32, 123, 32, 119, 105, 100, 116, 104, 58, // -10 { width: + 32, 56, 51, 46, 51, 51, 37, 59, 32, 125, 10, 46, // 83.33%; }.. + 99, 111, 108, 45, 57, 32, 123, 32, 119, 105, 100, 116, // col-9 { widt + 104, 58, 32, 55, 53, 37, 59, 32, 125, 10, 46, 99, // h: 75%; }..c + 111, 108, 45, 56, 32, 123, 32, 119, 105, 100, 116, 104, // ol-8 { width + 58, 32, 54, 54, 46, 54, 54, 37, 59, 32, 125, 10, // : 66.66%; }. + 46, 99, 111, 108, 45, 55, 32, 123, 32, 119, 105, 100, // .col-7 { wid + 116, 104, 58, 32, 53, 56, 46, 51, 51, 37, 59, 32, // th: 58.33%; + 125, 10, 46, 99, 111, 108, 45, 54, 32, 123, 32, 119, // }..col-6 { w + 105, 100, 116, 104, 58, 32, 53, 48, 37, 59, 32, 125, // idth: 50%; } + 10, 46, 99, 111, 108, 45, 53, 32, 123, 32, 119, 105, // ..col-5 { wi + 100, 116, 104, 58, 32, 52, 49, 46, 54, 54, 37, 59, // dth: 41.66%; + 32, 125, 10, 46, 99, 111, 108, 45, 52, 32, 123, 32, // }..col-4 { + 119, 105, 100, 116, 104, 58, 32, 51, 51, 46, 51, 51, // width: 33.33 + 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 51, 32, // %; }..col-3 + 123, 32, 119, 105, 100, 116, 104, 58, 32, 50, 53, 37, // { width: 25% + 59, 32, 125, 10, 46, 99, 111, 108, 45, 50, 32, 123, // ; }..col-2 { + 32, 119, 105, 100, 116, 104, 58, 32, 49, 54, 46, 54, // width: 16.6 + 54, 37, 59, 32, 125, 10, 46, 99, 111, 108, 45, 49, // 6%; }..col-1 + 32, 123, 32, 119, 105, 100, 116, 104, 58, 32, 56, 46, // { width: 8. + 51, 51, 37, 59, 32, 125, 10, 64, 109, 101, 100, 105, // 33%; }.@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 { + 32, 109, 97, 114, 103, 105, 110, 58, 32, 97, 117, 116, // margin: aut + 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, 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 // %; } }. }; static const unsigned char v5[] = { 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, // .PNG........ @@ -2771,9 +2786,9 @@ static const struct packed_file { time_t mtime; } packed_files[] = { {"/web_root/index.html", v1, sizeof(v1), 1654437619}, - {"/web_root/main.js", v2, sizeof(v2), 1654673323}, + {"/web_root/main.js", v2, sizeof(v2), 1654710571}, {"/web_root/preact.min.js", v3, sizeof(v3), 1652374364}, - {"/web_root/style.css", v4, sizeof(v4), 1654445635}, + {"/web_root/style.css", v4, sizeof(v4), 1654709515}, {"/web_root/user.png", v5, sizeof(v5), 1626172939}, {NULL, NULL, 0, 0} }; diff --git a/examples/device-dashboard/web_root/main.js b/examples/device-dashboard/web_root/main.js index 7828fd79..4bebf590 100644 --- a/examples/device-dashboard/web_root/main.js +++ b/examples/device-dashboard/web_root/main.js @@ -36,12 +36,6 @@ const Nav = props => html` `; -const Footer = props => html` -
- Copyright (c) Your Company -
-`; - const Hero = props => html`
@@ -107,20 +101,15 @@ const Login = function(props) { const Configuration = function(props) { - const [url, setUrl] = useState(''); - const [pub, setPub] = useState(''); - const [sub, setSub] = useState(''); + const [url, setUrl] = useState(props.config.url || ''); + const [pub, setPub] = useState(props.config.pub || ''); + const [sub, setSub] = useState(props.config.sub || ''); useEffect(() => { - 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); - }, []); + setUrl(props.config.url); + setPub(props.config.pub); + setSub(props.config.sub); + }, [props.config]); const update = (name, val) => fetch('/api/config/set', { method: 'post', @@ -130,6 +119,7 @@ const Configuration = function(props) { const updatepub = ev => update('pub', pub); const updatesub = ev => update('sub', sub); + console.log(props, [url, pub, sub]); return html`

@@ -158,6 +148,10 @@ const Configuration = function(props) {

+
+ You can use + HiveMQ Websocket web client to send messages to this console. +
Device keeps a persistent connection to the configured MQTT server. Changes to this configuration are propagated to all dashboards: try @@ -172,18 +166,17 @@ const Configuration = function(props) { const Message = m => html`
+ qos: ${m.message.qos} topic: ${m.message.topic} data: ${m.message.data}
`; const Messages = function(props) { 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); @@ -193,12 +186,12 @@ const Messages = function(props) { method: 'post', body: `message=${encodeURIComponent(txt)}` }).then(r => setTxt('')); - + const connstatus = props.config.connected ? 'connected' : 'diconnected'; return html`

MQTT messages

- MQTT server status: ${cfg.connected ? 'connected' : 'diconnected'} + MQTT server status: ${connstatus}
${messages.map(message => h(Message, {message}))} @@ -312,11 +305,13 @@ const Chart = function(props) { const App = function(props) { const [user, setUser] = useState(''); + const [config, setConfig] = useState({}); const getconfig = () => fetch('/api/config/get', {headers: {Authorization: ''}}) .then(r => r.json()) - .then(r => PubSub.publish({name: 'newconfig', data: r})); + .then(r => setConfig(r)) + .catch(err => console.log(err)); const login = function(u) { document.cookie = `access_token=${u.token};path=/;max-age=3600`; @@ -336,6 +331,7 @@ const App = function(props) { var tid, wsURI = proto + '//' + l.host + '/api/watch' var reconnect = function() { var ws = new WebSocket(wsURI); + ws.onopen = () => console.log('ws connected'); ws.onmessage = function(ev) { try { var msg = JSON.parse(ev.data); @@ -348,6 +344,7 @@ const App = function(props) { ws.onclose = function() { clearTimeout(tid); tid = setTimeout(reconnect, 1000); + console.log('ws disconnected'); }; }; reconnect(); @@ -355,12 +352,12 @@ const App = function(props) { useEffect(() => { // Called once at init time + PubSub.subscribe(msg => msg.name == 'config' && getconfig()); fetch('/api/login', {headers: {Authorization: ''}}) .then(r => r.json()) .then(r => login(r)) + .then(watch) .catch(err => setUser('')); - watch(); - PubSub.subscribe(msg => msg.name == 'config' && getconfig()); }, []); if (!user) return html`<${Login} login=${login} />`; @@ -371,10 +368,11 @@ const App = function(props) {
<${Hero} />
<${Chart} />
-
${user == 'admin' && h(Configuration)}
-
<${Messages} />
+
+ ${user == 'admin' && h(Configuration, {config})} +
+
<${Messages} config=${config} />
- <${Footer} />
`; }; diff --git a/examples/device-dashboard/web_root/style.css b/examples/device-dashboard/web_root/style.css index 9725a089..b483f801 100644 --- a/examples/device-dashboard/web_root/style.css +++ b/examples/device-dashboard/web_root/style.css @@ -19,8 +19,10 @@ a, a:visited, a:active { color: #55f; } .nowrap { white-space: nowrap; } .msg { background: #def; border-left: 5px solid #59d; padding: 0.5em; font-size: 90%; margin: 1em 0; } .section { margin: 0 1em; } -.topic { background: #fea; padding: 0.2em 1em; border-radius: 0.4em; } -.data { background: #aef; padding: 0.2em 1em; border-radius: 0.4em; } +.topic, .data, .qos { padding: 0.2em 0.5em; border-radius: 0.4em; margin-right: 0.5em; } +.qos { background: #efa; } +.topic { background: #fea; } +.data { background: #aef; } /* Grid */ .row { display: flex; flex-wrap: wrap; }