@transitive-sdk/utils-web 0.14.4 → 0.14.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client/hooks.jsx CHANGED
@@ -47,7 +47,6 @@ export const useMqttSync = ({jwt, id, mqttUrl, appReact}) => {
47
47
  let reconnectPeriod = RECONNECT_PERIOD_DEFAULT; // default to start with
48
48
  const transformWsUrl = (url, options, client) => {
49
49
  options.reconnectPeriod = reconnectPeriod;
50
- log.info(`reconnect in ${options.reconnectPeriod} s`);
51
50
  return url;
52
51
  }
53
52
 
@@ -59,24 +58,37 @@ export const useMqttSync = ({jwt, id, mqttUrl, appReact}) => {
59
58
  });
60
59
 
61
60
  // Increase backoff with each close (since we can't actually detect auth
62
- // errors)
63
- client.on('close', () =>
64
- reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX)
65
- );
61
+ // errors); stop reconnecting if JWT is invalid by now.
62
+ client.on('close', () => {
63
+ reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX);
64
+
65
+ if ((iat + validity) * 1e3 < Date.now()) {
66
+ const error = 'MQTT connection closed and the JWT is expired by now. Not reconnecting.';
67
+ log.warn(error, payload);
68
+ setStatus(`error: ${error}`);
69
+ // give up, do not try to reconnect; user needs to provide a fresh JWT.
70
+ client.end();
71
+ } else {
72
+ const msg = `reconnect in ${reconnectPeriod / 1000} s`;
73
+ log.info(msg);
74
+ setStatus(msg);
75
+ }
76
+ });
66
77
 
67
78
  // reset to default after a successful connection
68
- client.on('connect', () => reconnectPeriod = RECONNECT_PERIOD_DEFAULT);
79
+ client.on('connect', () => {
80
+ reconnectPeriod = RECONNECT_PERIOD_DEFAULT;
81
+ log.debug('MQTT (re-)connected');
82
+ setStatus('connected');
83
+ });
69
84
 
70
85
  client.once('connect', () => {
71
- log.debug('MQTT connected');
72
-
73
86
  const mqttSyncClient = new MqttSync({
74
87
  mqttClient: client,
75
88
  ignoreRetain: true,
76
89
  onHeartbeatGranted: () => setHeartbeatGranted(true)
77
90
  });
78
91
  setMqttSync(mqttSyncClient);
79
- setStatus('connected');
80
92
 
81
93
  // Update data on change. Note: need to clone object to force reaction
82
94
  mqttSyncClient.data.subscribe(_.throttle(() =>
package/dist/utils-web.js CHANGED
@@ -788,7 +788,7 @@ var require_MqttSync = __commonJS({
788
788
  } else {
789
789
  this.receivedTopics.add(topic);
790
790
  let path = topicToPath2(topic);
791
- log2.debug("processing message", topic, path);
791
+ log2.debug("processing message", topic);
792
792
  if (sliceTopic) {
793
793
  path = path.slice(sliceTopic);
794
794
  topic = pathToTopic2(path);
@@ -1367,7 +1367,6 @@ var useMqttSync = ({ jwt, id, mqttUrl, appReact }) => {
1367
1367
  let reconnectPeriod = RECONNECT_PERIOD_DEFAULT;
1368
1368
  const transformWsUrl = (url, options, client2) => {
1369
1369
  options.reconnectPeriod = reconnectPeriod;
1370
- log.info(`reconnect in ${options.reconnectPeriod} s`);
1371
1370
  return url;
1372
1371
  };
1373
1372
  log.debug("(re-)create mqtt client");
@@ -1376,20 +1375,31 @@ var useMqttSync = ({ jwt, id, mqttUrl, appReact }) => {
1376
1375
  password: jwt,
1377
1376
  transformWsUrl
1378
1377
  });
1379
- client.on(
1380
- "close",
1381
- () => reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX)
1382
- );
1383
- client.on("connect", () => reconnectPeriod = RECONNECT_PERIOD_DEFAULT);
1378
+ client.on("close", () => {
1379
+ reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX);
1380
+ if ((iat + validity) * 1e3 < Date.now()) {
1381
+ const error = "MQTT connection closed and the JWT is expired by now. Not reconnecting.";
1382
+ log.warn(error, payload);
1383
+ setStatus(`error: ${error}`);
1384
+ client.end();
1385
+ } else {
1386
+ const msg = `reconnect in ${reconnectPeriod / 1e3} s`;
1387
+ log.info(msg);
1388
+ setStatus(msg);
1389
+ }
1390
+ });
1391
+ client.on("connect", () => {
1392
+ reconnectPeriod = RECONNECT_PERIOD_DEFAULT;
1393
+ log.debug("MQTT (re-)connected");
1394
+ setStatus("connected");
1395
+ });
1384
1396
  client.once("connect", () => {
1385
- log.debug("MQTT connected");
1386
1397
  const mqttSyncClient = new MqttSync2({
1387
1398
  mqttClient: client,
1388
1399
  ignoreRetain: true,
1389
1400
  onHeartbeatGranted: () => setHeartbeatGranted(true)
1390
1401
  });
1391
1402
  setMqttSync(mqttSyncClient);
1392
- setStatus("connected");
1393
1403
  mqttSyncClient.data.subscribe(import_lodash.default.throttle(() => setData((0, client_exports.clone)(mqttSyncClient.data.get())), 50));
1394
1404
  });
1395
1405
  client.on("error", (error) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../client/react-web-component/getStyleElementsFromReactWebComponentStyleLoader.js", "../client/react-web-component/extractAttributes.js", "../client/react-web-component/index.js", "../../common/constants.js", "../../common/common.js", "../../common/DataCache.js", "../../common/MqttSync.js", "../index.js", "../client/shared.jsx", "../client/client.js", "../client/hooks.jsx"],
4
- "sourcesContent": ["/*\n * An optional library which is conditionally added\n * @returns {[]}\n */\nmodule.exports = () => {\n try {\n return require('react-web-component-style-loader/exports').styleElements;\n } catch (e) {\n return [];\n }\n};\n", "/*\n * Takes in a node attributes map and returns an object with camelCased\n * properties and values\n * @param nodeMap\n * @returns {{}}\n */\nmodule.exports = function extractAttributes(nodeMap) {\n if (!nodeMap.attributes) {\n return {};\n }\n\n let obj = {};\n let attribute;\n const attributesAsNodeMap = [...nodeMap.attributes];\n const attributes = attributesAsNodeMap.map((attribute) =>\n ({ [attribute.name]: attribute.value }));\n\n for (attribute of attributes) {\n const key = Object.keys(attribute)[0];\n const camelCasedKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());\n obj[camelCasedKey] = attribute[key];\n }\n\n return obj;\n};\n", "const React = require('react');\nconst ReactDOM = require('react-dom');\nconst { createRoot } = require('react-dom/client');\n\n// const { createRoot } = require('react-dom/client'); // react 18; wip\nconst retargetEvents = require('react-shadow-dom-retarget-events');\nconst getStyleElementsFromReactWebComponentStyleLoader = require('./getStyleElementsFromReactWebComponentStyleLoader');\nconst extractAttributes = require('./extractAttributes');\n\n// require('@webcomponents/shadydom');\n// require('@webcomponents/custom-elements');\n\nconst lifeCycleHooks = {\n attachedCallback: 'webComponentAttached',\n connectedCallback: 'webComponentConnected',\n disconnectedCallback: 'webComponentDisconnected',\n adoptedCallback: 'webComponentAdopted'\n};\n\nmodule.exports = {\n /*\n * @param {JSX.Element} wrapper: the wrapper component class to be instantiated and wrapped\n * @param {string} tagName - The name of the web component. Has to be minus \"-\" delimited.\n * @param {boolean} useShadowDom - If the value is set to \"true\" the web component will use the `shadowDom`. The default value is true.\n */\n create: (wrapper, tagName, useShadowDom = true, compRef = undefined) => {\n\n const proto = class extends HTMLElement {\n instance = null; // the instance we create of the wrapper\n\n callConstructorHook() {\n if (this.instance['webComponentConstructed']) {\n this.instance['webComponentConstructed'].apply(this.instance, [this])\n }\n }\n\n callLifeCycleHook(hook, params = []) {\n const method = lifeCycleHooks[hook];\n if (method && this.instance && this.instance[method]) {\n this.instance[method].apply(this.instance, params);\n }\n }\n\n connectedCallback() {\n const self = this;\n let mountPoint = self;\n\n if (useShadowDom) {\n // Re-assign the self (this) to the newly created shadowRoot\n const shadowRoot = self.attachShadow({ mode: 'open' });\n\n // Re-assign the mountPoint to the newly created \"div\" element\n mountPoint = document.createElement('div');\n\n // Move all of the styles assigned to the react component inside of\n // the shadowRoot. By default this is not used, only if the library is\n // explicitly installed\n const styles = getStyleElementsFromReactWebComponentStyleLoader();\n styles.forEach((style) => {\n shadowRoot.appendChild(style.cloneNode(shadowRoot));\n });\n\n shadowRoot.appendChild(mountPoint);\n retargetEvents(shadowRoot);\n }\n\n createRoot(mountPoint).render(\n // This is where we instantiate the actual component (in its wrapper)\n React.createElement(wrapper, {_element: self, ...extractAttributes(self)})\n );\n }\n\n disconnectedCallback() {\n this.callLifeCycleHook('disconnectedCallback');\n }\n\n adoptedCallback(oldDocument, newDocument) {\n this.callLifeCycleHook('adoptedCallback', [oldDocument, newDocument]);\n }\n\n /* call a function defined in the component, either as a class method, or\n * via useImperativeHandle */\n call(functionName, args) {\n return compRef?.current?.[functionName]?.call(compRef?.current, args);\n }\n\n /* predefined function to retrieve the pre-defined config object of the\n * state, populated via the pre-defined `setConfig` method given as prop\n * to the wrapped component. */\n getConfig() {\n return this.instance.state.config;\n }\n }\n\n customElements.define(tagName, proto);\n\n return proto;\n },\n};\n", "module.exports = {\n rosReleases: {\n kinetic: { rosVersion: 1, ubuntuCodename: 'xenial' },\n melodic: { rosVersion: 1, ubuntuCodename: 'bionic' },\n noetic: { rosVersion: 1, ubuntuCodename: 'focal' },\n dashing: { rosVersion: 2 },\n eloquent: { rosVersion: 2 },\n foxy: { rosVersion: 2 },\n galactic: { rosVersion: 2 },\n humble: { rosVersion: 2 },\n iron: { rosVersion: 2 },\n jazzy: { rosVersion: 2 },\n kilted: { rosVersion: 2 },\n rolling: { rosVersion: 2 },\n }\n};\n", "const semverCompare = require('semver/functions/compare');\nconst semverMinVersion = require('semver/ranges/min-version');\n\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst loglevel = require('loglevel');\nconst chalk = require('chalk');\n\nconst constants = require('./constants');\n\n/* Convenience function to set all loggers to the given level. */\nloglevel.setAll = (level) =>\n Object.values(loglevel.getLoggers()).forEach(l => l.setLevel(level));\n\nconst methodColors = {\n warn: chalk.yellow,\n error: chalk.red,\n info: chalk.green,\n debug: chalk.gray,\n};\nconst coloredMethod = (method) =>\n methodColors[method] ? methodColors[method](method) : method;\n\n// patch the methodFactory to prefix logs with name and level\nconst originalFactory = loglevel.methodFactory;\nloglevel.methodFactory = (methodName, level, loggerName) => {\n const rawMethod = originalFactory(methodName, level, loggerName);\n\n if (typeof window != 'undefined') {\n // browser: keep it simple\n const context = `${loggerName} ${methodName}`;\n return (...args) => rawMethod(`[${context}]`, ...args);\n }\n\n const context = `${loggerName} ${coloredMethod(methodName)}`;\n return (...args) => rawMethod(\n `[${chalk.blue((new Date()).toISOString())} ${context}]`, ...args);\n};\n\n/** Get a new loglevel logger; call with a name, e.g., `module.id`. The returned\n* logger has methods trace, debug, info, warn, error. See\n* https://www.npmjs.com/package/loglevel for details.\n*/\nconst getLogger = loglevel.getLogger;\n\n/** Deep-clone the given object. All functionality is lost, just data is kept. */\nconst clone = (obj) => JSON.parse(JSON.stringify(obj));\n\n/** Parse JWT and return the decoded payload (JSON). */\nconst decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n// TODO: make this robust against bad JWTs (throw a more readable error)\n\n/** Try parsing JSON, return null if unsuccessful */\nconst tryJSONParse = (string) => {\n try {\n return JSON.parse(string);\n } catch (e) {\n return null;\n }\n};\n\n/** Reusable visitor pattern: iteratively visits all nodes in the tree\n described by `object`, where `childField` indicates the child-of predicate.\n*/\nconst visit = (object, childField, visitor) => {\n if (!object) return;\n visitor(object);\n object[childField]?.forEach(child => visit(child, childField, visitor));\n};\n\n/** Given an object and a path, visit each ancestor of the path */\nconst visitAncestor = (object, path, visitor, prefix = []) => {\n visitor(object, prefix);\n const next = path[0];\n if (next) {\n const sub = object[next];\n if (sub) {\n visitAncestor(sub, path.slice(1), visitor, prefix.concat(next));\n }\n }\n};\n\n/** Wait for delay ms, for use in async functions. */\nconst wait = (delay) => new Promise((resolve) => { setTimeout(resolve, delay); });\n\n// -------------------------------------------------------------------------\n// DataCache tools\n\n/**\n * Given an object, return a new flat object of topic+value pairs, e.g.:\n```js\n{a: {b: 1, c: 2}, d: 3} \u2192 {'/a/b': 1, '/a/c': 2, '/d': 3}\n```\nNote: not idempotent!\n```js\n{'/a/b': 1, '/a/c': 2, d: 3} \u2192 {'%2Fa%2Fb': 1, '%2Fa%2Fc': 2, '/d': 3}\n```\n*/\nconst toFlatObject = (obj, prefix = [], rtv = {}) => {\n _.forEach(obj, (value, key) => {\n // const newPrefix = prefix.concat(topicToPath(String(key)));\n const newPrefix = prefix.concat(String(key));\n\n // TODO: using isPlainObject also means custom objects (classes) do not get\n // broken down.\n if ((_.isPlainObject(value) || value instanceof Array) && value !== null) {\n // it's an object or array\n toFlatObject(value, newPrefix, rtv);\n } else {\n // it's a primitive\n rtv[pathToTopic(newPrefix)] = value;\n }\n });\n return rtv;\n};\n\n/** Iterate through the object and invoke callback for each match of path (with\nnamed wildcards) */\nconst forMatchIterator = (obj, path, callback, pathSoFar = [], matchSoFar = {}) => {\n\n if (path.length == 0 || path[0] == '#') {\n callback(obj, pathSoFar, matchSoFar);\n return;\n }\n\n const next = path[0]; // don't use shift, we don't want to modify path\n if (next) {\n for (let key in obj) {\n if (key == next || next == '*' || next.startsWith('+')) {\n const match = next.startsWith('+') && next.length > 1 ?\n Object.assign({}, matchSoFar, {[next.slice(1)]: key}) :\n matchSoFar;\n forMatchIterator(obj[key], path.slice(1), callback,\n pathSoFar.concat([key]), match);\n }\n }\n }\n};\n\n/** Like _.set but without arrays. This allows using numbers as keys. */\nconst setFromPath = (obj, path, value) => {\n if (path.length == 0) return obj;\n const next = path.shift();\n if (path.length == 0) {\n obj[next] = value;\n } else {\n if (!obj[next]) obj[next] = {};\n setFromPath(obj[next], path, value);\n }\n};\n\nconst encodeTopicElement = x => x.replace(/%/g, '%25').replace(/\\//g, '%2F');\nconst decodeTopicElement = x => x.replace(/%25/g, '%').replace(/%2F/g, '/');\n\n/** convert a path array to mqtt topic; reduces +id identifiers to + */\nconst pathToTopic = (pathArray) => {\n /** reduce wildcards with Ids, such as `+sessionId`, to just + */\n const dropWildcardIds = (x) => x.startsWith('+') ? '+' : x;\n return `/${pathArray.map(dropWildcardIds).map(encodeTopicElement).join('/')}`;\n};\n\n/** convert topic to path array */\nconst topicToPath = (topic) => {\n // split topic by slashes, but not if they are escaped\n // const path = topic.match(/(\\\\.|[^/])+/g) || [];\n // split topic by slashes and unescape slashes in each item\n const path = topic.split('/').map(decodeTopicElement);\n // handle leading slash\n path.length > 0 && path[0].length == 0 && path.shift();\n // handle trailing slash\n path.length > 0 && path.at(-1).length == 0 && path.pop();\n return path;\n};\n\n/** match a slash-separated topic with a selector using +XYZ for (named)\n wildcards. Return the matching result.\n*/\nconst topicMatch = (selector, topic) => {\n const byArray = (s, p) => {\n if (s.length == 0) return true; // we are done: prefix matched\n if (s[0][0] == '#') return true; // explicit tail-wildcard\n // if (p.length < s.length) return false;\n if (p.length == 0) return true; // we are done, matched all\n // simple match:\n if (s[0] == p[0]) return byArray(s.slice(1), p.slice(1));\n // wild card match:\n if (s[0][0] == '+') {\n const sub = byArray(s.slice(1), p.slice(1));\n return sub && Object.assign({[s[0].slice(1)]: p[0]}, sub);\n }\n // else: failure!\n return false;\n };\n\n const selectorArray = topicToPath(selector);\n const pathArray = topicToPath(topic);\n // const selectorArray = selector.split('/');\n // const pathArray = topic.split('/');\n return byArray(selectorArray, pathArray);\n};\n\n/** sub is a strict sub-topic of parent, and in particular not equal */\nconst isSubTopicOf = (sub, parent) => {\n const pPath = topicToPath(parent);\n const sPath = topicToPath(sub);\n return isPrefixOf(pPath, sPath) && pPath.length < sPath.length;\n};\n\n/** prefixArray is a prefix of the array */\nconst isPrefixOf = (prefixArray, array) => {\n if (prefixArray.length == 0) return true;\n return (prefixArray[0] == array[0] &&\n isPrefixOf(prefixArray.slice(1), array.slice(1))\n );\n}\n\n\n// -------------------------------------------------------------------------\n// MQTT Tools\n\n/** parse usernames used in MQTT */\nconst parseMQTTUsername = (username) => {\n const parts = username.split(':');\n return {\n organization: parts[0],\n client: parts[1],\n sub: parts.slice(2)\n }\n};\n\n/** parse an MQTT topic according to our topic schema */\nconst parseMQTTTopic = (topic) => {\n const parts = topicToPath(topic);\n return {\n organization: parts[0],\n device: parts[1],\n capabilityScope: parts[2],\n capabilityName: parts[3],\n capability: `${parts[2]}/${parts[3]}`,\n version: parts[4],\n sub: parts.slice(5)\n }\n};\n\nconst mqttParsePayload = (payload) =>\n payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// TODO: ^ This can probably now just become tryJSONParse\n\n/** delete all retained messages in a certain topic prefix, waiting for\n a given delay to collect existing retained. Use with care, never delete topics\n not owned by us. Harmless within capabilities, which are namespaced already.\n*/\nconst mqttClearRetained = (mqttClient, prefixes, callback, delay = 1000) => {\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n // mqttTopicMatch(topic, `${prefix}/#`) && toDelete.push(topic)\n topicMatch(`${prefix}/#`, topic) && toDelete.push(topic)\n );\n }\n mqttClient.on('message', collectToDelete);\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n mqttClient.subscribe(`${prefix}/#`);\n } else {\n console.warn('Ignoring', prefix, 'since it is not a string.');\n }\n });\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n setTimeout(() => {\n mqttClient.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => mqttClient.unsubscribe(`${prefix}/#`));\n\n const count = toDelete.length;\n console.log(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n mqttClient.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n }, delay);\n};\n\n\n// WIP: a cleaner, more explicit way to serialize/deserialize mqtt payloads\n// /** Serialize a message for transport via MQTT */\n// const mqttSerialize = (message) => {\n// return value == null ? null : JSON.stringify(message);\n// };\n\n// /** Deserialize a message from MQTT */\n// const mqttDeserialize = (payload) => {\n// return payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// };\n\n\n// -------------------------------------------------------------------------\n\n/** Generate a random id (base36) */\nconst getRandomId = (bytes = 6) => {\n const buffer = new Uint8Array(bytes);\n crypto.getRandomValues(buffer);\n return buffer.reduce((memo, i) => memo + i.toString(36), '');\n};\n\n/** Convert number to base52 [a-zA-Z] */\nconst toBase52 = (num) => {\n const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n const list = [];\n do {\n list.unshift(characters[num % 52]);\n num = Math.floor(num / 52);\n } while (num > 0);\n return list.join('');\n}\n\n/** Get a base52 representation [a-zA-Z] of the current date (ms since epoch) */\nconst getDateBase52 = () => toBase52(Date.now());\n\n// -------------------------------------------------------------------------\n\n/** Compare to version strings. Return -1 if a is lower than b,\n0 if they are equal, and 1 otherwise. If either is not a complete version,\ne.g., 2.0, interpret it as a range and use its minimum version for the\ncomparison. Hence, 2.0 < 2.0.1. */\nconst versionCompare = (a, b) =>\n semverCompare(semverMinVersion(a), semverMinVersion(b));\n\n// -------------------------------------------------------------------------\n\n/** given an object where the keys are versions, merge this into one object\n where the latest version of each subfield overwrites any previous */\nconst mergeVersions = (versionsObject, subTopic = undefined, options = {}) => {\n if (!versionsObject) {\n return subTopic ? _.set({}, subTopic, versionsObject) : versionsObject;\n }\n\n const versions = Object.keys(versionsObject).filter(ver =>\n (!options.maxVersion || versionCompare(ver, options.maxVersion) <= 0) &&\n (!options.minVersion || versionCompare(options.minVersion, ver) <= 0))\n .sort(versionCompare);\n\n const merged = {};\n const subPath = subTopic && topicToPath(subTopic);\n versions.forEach(nextVersion => {\n const newValue = subPath ? _.get(versionsObject[nextVersion], subPath) :\n versionsObject[nextVersion];\n // Object.assign(merged, newValue);\n _.merge(merged, newValue);\n });\n return subPath ? _.set({}, subPath, merged) : merged;\n};\n\n// -------------------------------------------------------------------------\n// Formatting tools\n\nconst units = ['B', 'KB', 'MB', 'GB', 'TB'];\nconst formatBytes = (bytes) => {\n if (!bytes) return '--';\n let i = 0;\n while (bytes > 1024) {\n bytes /= 1024;\n i++;\n }\n return `${bytes.toFixed(2)} ${units[i]}`;\n}\n\nconst formatDuration = (seconds) => {\n if (!seconds) return '--';\n const parts = {};\n if (seconds > 3600) {\n parts.h = Math.floor(seconds / 3600);\n seconds = seconds % 3600;\n }\n if (seconds > 60) {\n parts.m = Math.floor(seconds / 60);\n seconds = seconds % 60;\n }\n parts.s = Math.floor(seconds);\n\n let rtv = '';\n parts.h > 0 && (rtv += `${parts.h}h `);\n parts.m > 0 && (rtv += `${parts.m}m `);\n !parts.h && (rtv += `${parts.s}s`);\n return rtv.trim();\n};\n\n// -------------------------------------------------------------------------\n\nmodule.exports = { parseMQTTUsername, parseMQTTTopic,\n pathToTopic, topicToPath, toFlatObject, topicMatch,\n mqttParsePayload, getRandomId, toBase52, getDateBase52, versionCompare,\n loglevel, getLogger,\n mergeVersions, mqttClearRetained, isSubTopicOf, clone, setFromPath,\n forMatchIterator, encodeTopicElement, decodeTopicElement, constants, visit,\n wait, formatBytes, formatDuration, tryJSONParse,\n decodeJWT, visitAncestor\n};\n", "\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst {topicToPath, pathToTopic, toFlatObject, topicMatch, forMatchIterator}\n = require('./common');\n\n/** Unset the topic in that obj, and clean up parent if empty, recursively.\nReturn the path to the removed node.\n*/\nconst unset = (obj, path) => {\n if (!path || path.length == 0) return;\n _.unset(obj, path);\n const parentPath = path.slice(0, -1);\n // _.get doesn't do the intuitive thing for the empty path, handle it ourselves\n const parent = parentPath.length == 0 ? obj : _.get(obj, parentPath);\n if (_.isEmpty(parent)) {\n return unset(obj, parentPath);\n } else {\n return path;\n }\n};\n\n/** Given a modifier `{\"a/b/c\": \"xyz\"}` update the object `obj` such that\n`obj.a.b.c = \"xyz\"`. */\nconst updateObject = (obj, modifier) => {\n _.forEach( modifier, (value, topic) => {\n const path = topicToPath(topic);\n if (value == null) {\n unset(obj, path);\n } else {\n _.set(obj, path, value);\n }\n });\n return obj;\n};\n\n/** Given an object and a path with wildcards (`*` and `+`), *modify* the object\nto only contain elements matched by the path, e.g.,\n`{a: {b: 1, c: 2}, d: 2}` and `['a','+']` would give `{a: {b: 1, c: 2}}`\n\n@param {object} obj - The object to select from\n@param {array} path - An array specifying the path to select, potentially\ncontaining mqtt wildcards ('+').\n*/\nconst selectFromObject = (obj, path) => {\n if (path.length == 0) return;\n const next = path[0];\n if (next) {\n for (let key in obj) {\n if (key != next && next != '*' && !next.startsWith('+')) {\n delete obj[key];\n } else {\n selectFromObject(obj[key], path.slice(1));\n }\n }\n }\n};\n\n\n/**\n* A class implementing a local data cache, used as a local data store with\n* deduplication detection and update events. While this class is very handy\n* you probably won't need to create instances of it directly. Instead use\n* the mqttSync.data instance which holds the locally stored data\n* subscribed/published from/to MQTTSync.\n* For example on the robot:\n* ```js\n* // update/publish our status:\n* mqttSync.data.update('status', {changed: Date.now(), msg: 'OK'});\n* // subscribe to new user requests (e.g., from UI):\n* mqttSync.data.subscribePath('+user/request', (request, key, {user}) => {\n* log.debug(`user ${user} made request`, request);\n* });\n* ```\n* In the cloud or in a web component you would need to use the full topic including\n* org, device, scope, cap-name, and version.\n*/\nclass DataCache {\n\n #data = {};\n #listeners = [];\n #flatListeners = [];\n\n constructor(data = {}) {\n this.#data = data;\n }\n\n /** Update the object with the given value at the given path, remove empty;\n return the flat changes (see toFlatObject). Add `tags` to updates to mark\n them somehow based on the context, e.g., so that some subscriptions can choose\n to ignore updates with a certain tag.\n */\n updateFromArray(path, value, tags = {}) {\n // const empty = Object.keys(this.#data).length == 0; // object already empty\n const current = _.get(this.#data, path);\n if (value == null) {\n if (current === undefined || current === null) {\n return {}; // no change, do not call listeners\n } else {\n unset(this.#data, path);\n }\n } else {\n if (_.eq(current, value)) {\n // note: this is just a shallow equal, so replacing a sub-document\n // with an atomic copy of it should still trigger listeners.\n // TODO: Note also that when value is an object, we will set it by\n // reference here, so any changes made to that object will *not* trigger\n // listeners because `current` will already be changed -- which is\n // probably wrong. May want to always clone value first.\n return {}; // nothing to do, do not bother listeners\n }\n // console.log('setting', path, value);\n _.set(this.#data, path, value);\n // TODO: implement this ourselves so we can do better change-checking\n }\n\n const topic = pathToTopic(path);\n const obj = {[topic]: value};\n\n // flatten the value and combine eith topic (without reflattening the topic):\n let flatChanges;\n if (value instanceof Object) {\n const flatValue = toFlatObject(value);\n flatChanges = {};\n _.forEach(flatValue, (atomic, flatKey) => {\n flatChanges[`${topic}${flatKey}`] = atomic;\n });\n } else {\n flatChanges = obj;\n }\n\n // option 1. using flat changes (sub-documents are never atomic)\n // this.#listeners.forEach(fn => fn(flatChanges));\n\n // option 2. allow atomic sub-document changes\n this.#listeners.forEach(fn => fn(obj, tags));\n\n this.#flatListeners.forEach(fn => fn(flatChanges, tags));\n\n return flatChanges;\n }\n\n /** Update the value at the given path (array or dot separated string) */\n update(path, value, tags) {\n if (typeof path == 'string') {\n return this.updateFromTopic(path, value, tags);\n } else if (path instanceof Array) {\n return this.updateFromArray(path, value, tags);\n } else {\n throw new Error('unrecognized path expression');\n }\n }\n\n /** Set value from the given topic (with or without leading or trailing slash) */\n updateFromTopic(topic, value, tags) {\n return this.updateFromArray(topicToPath(topic), value, tags);\n }\n\n /** Update data from a modifier object where keys are topic names to be\n interpreted as paths, and values are the values to set */\n updateFromModifier(modifier, tags) {\n return _.map(modifier, (value, topic) =>\n this.updateFromTopic(topic, value, tags));\n }\n\n /** Add a callback for all change events. */\n subscribe(callback) {\n if (callback instanceof Function) {\n this.#listeners.push(callback);\n } else {\n console.warn('DataCache.subscribe expects a function as argument. Did you mean to use subscribePath?');\n }\n }\n\n /** Subscribe to a specific topic only. Callback receives\n `value, key, matched, tags`. TODO: rename to subscribeTopic. */\n subscribePath(topic, callback) {\n this.#listeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(topic, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Same as subscribePath but always get all changes in flat form */\n subscribePathFlat(topic, callback) {\n this.#flatListeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(topic, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Remove a callback previously registered using `subscribe`. */\n unsubscribe(callback) {\n this.#listeners = this.#listeners.filter(f => f != callback);\n }\n\n /** Get sub-value at path, or entire object if none given */\n get(path = []) {\n return path.length == 0 ? this.#data : _.get(this.#data, path);\n }\n\n /** Get sub-value specified by topic */\n getByTopic(topic) {\n return this.get(topicToPath(topic));\n }\n\n /** Filter the object using path with wildcards */\n filter(path) {\n const rtv = JSON.parse(JSON.stringify(this.get()));\n selectFromObject(rtv, path);\n return rtv;\n }\n\n /** Filter the object using topic with wildcards */\n filterByTopic(topic) {\n return this.filter(topicToPath(topic));\n }\n\n /** For each topic match, invoke the callback with the value, path, and match\n just like subscribePath, but on the current data rather than future changes. */\n forMatch(topic, callback) {\n const path = topicToPath(topic);\n this.forPathMatch(path, callback);\n }\n\n /** For each path match, invoke the callback with the value, path, and match\n just like subscribePath */\n forPathMatch(path, callback) {\n forMatchIterator(this.get(), path, callback);\n }\n};\n\nmodule.exports = {\n DataCache, updateObject\n}", "'use strict';\n\nconst _ = require('lodash');\n\nconst { mqttParsePayload, topicMatch, topicToPath, pathToTopic,\ntoFlatObject, getLogger, mergeVersions, parseMQTTTopic, isSubTopicOf,\nversionCompare, encodeTopicElement, visitAncestor, getRandomId }\n = require('./common');\nconst { DataCache } = require('./DataCache');\n\n\nconst log = getLogger('MqttSync');\nlog.setLevel('info');\n\nconst HEARTBEAT_TOPIC = '$SYS/broker/uptime';\nconst specialKey = '$_'; // special key to reify \"value\" in publishedMessages\n\nconst noop = () => {};\n\n/* clone a mqtt payload, if necessary */\nconst clone = (payload) => {\n if (typeof payload == 'object') {\n return JSON.parse(JSON.stringify(payload));\n } else {\n return payload;\n }\n};\n\n/* return new string that ends in /# for sure */\nconst ensureHashSuffix = (topic) =>\n topic.endsWith('/#') ? topic :\n ( topic.endsWith('/') ? topic.concat('#') :\n topic.concat('/#') );\n\n/* given a path, replace any double slashes, '//', with single ones */\nconst resolveDoubleSlashes = (path) => path.replace(/\\/\\//g, '/');\n\n\n/** A class that combines DataCache and MQTT to implement a data synchronization\nfeature over the latter. Relies on retained messages in mqtt for persistence.\n* @param {object} options\n* @param {object} options.mqttClient - An already connected mqtt.js client.\n* @param {boolean} [options.ignoreRetain] - retain all messages, ignorant of the retain\n* flag.\n* @param {number} [options.sliceTopic] - a number indicating at what level to\n* slice the topic, i.e., only use a suffix. Used in robot-capabilities to slice\noff the topic prefix (namespaces).\n* @param {array} [options.migrate] - an array of objects of the form\n* `{topic, newVersion, level}`. Only meaningful in the cloud. Instructs MQTTSync\nto first migrate existing topics to a new version namespace, publishing at the\ndesignated level down from the version level. For example:\n```js\n[{ topic: `/myorg/mydevice/@local/my-cap/+/config`,\n newVersion: this.version,\n level: 1\n}]\n```\nWould migrate any existing data in the capability's `config` namespace to the\ncurrent version of the package, publishing at the `config/+` level (rather than\natomically at the config level itself).\n* @param {function} [options.onReady] - A function that is called when the MQTTSync\nclient is ready and has completed any requested migrations.\n* @param {function} [options.onChange] - A function that is called any time there\nis a change to the shared data. This is not usually used. It's usually better to\nuse the finer grained `MqttSync.data.subscribePath` instead, that allows you to\nsubscribe to changes just on a specific sun-object instead, see DataCache.\n*/\nclass MqttSync {\n\n data = new DataCache();\n\n /* Directory of paths we've subscribed to in this class; this matters\n because the same mqtt client may have subscriptions to paths that we don't\n care to store (sync). */\n subscribedPaths = {};\n\n publishedPaths = {}; // not used in atomic mode\n\n /* Store messages retained on mqtt so we can publish what is necessary to\n achieve the \"should-be\" state. Note that we cannot use a structured document\n for storing these publishedMessages since we need to be able to store separate\n values at non-leaf nodes in the object (just like mqtt, where you can have\n /a/b = 1 and /a/b/c = 1 at the same time). Note: not used in atomic mode.\n Note: we use specialKey in this DataCache to allow overlapping\n topics (e.g., `/a/b/$_ = 1` and `/a/$_ = {b: 2}`)\n */\n publishedMessages = new DataCache();\n\n /* The order in which we send retained messages matters, which is why we use\n a queue for sending things. Note that we here use the property of Map that it\n remembers insertion order of keys. */\n publishQueue = new Map();\n\n /* We need to keep a record of all received topics (not messages) so far in\n case we want to clear any of them. */\n receivedTopics = new Set();\n\n /* List of callbacks waiting for next heartbeat, gets purged with each\n heartbeat */\n heartbeatWaitersOnce = [];\n\n heartbeats = 0;\n\n beforeDisconnectHooks = [];\n\n rpcHandlers = {}; // handlers for incoming RPC requests\n rpcCallbacks = {}; // callback for RPC requests we've sent\n\n constructor({mqttClient, onChange, ignoreRetain, migrate, onReady,\n sliceTopic, onHeartbeatGranted }) {\n\n this.mqtt = mqttClient;\n this.sliceTopic = sliceTopic;\n\n this.mqtt.on('message', (topic, payload, packet) => {\n const payloadString = payload && payload.toString()\n // log.debug('got message', topic, payloadString.slice(0, 180),\n // payloadString.length > 180 ? `... (${payloadString.length} bytes)` : '',\n // packet.retain);\n\n if (topic == HEARTBEAT_TOPIC) {\n if (this.heartbeats > 0) { // ignore initial heartbeat (retained)\n this.heartbeatWaitersOnce.forEach(cb => cb());\n this.heartbeatWaitersOnce = [];\n }\n if (this.heartbeats == 1 && !migrate && onReady) onReady();\n this.heartbeats++;\n\n } else {\n this.receivedTopics.add(topic);\n // Do NOT parse payload just yet, since it may be binary and ignored by us\n\n let path = topicToPath(topic);\n log.debug('processing message', topic, path);\n if (sliceTopic) {\n path = path.slice(sliceTopic);\n topic = pathToTopic(path);\n }\n\n if (this.rpcHandlers[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCRequest(topic, json);\n\n } else if (this.rpcCallbacks[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCResponse(topic, json);\n\n } else if (packet.retain || ignoreRetain) {\n\n if (this.isPublished(topic)) {\n const json = mqttParsePayload(payload);\n // store plain messages, still stored in a structure, but values are\n // not interpreted; we just store them to undo them if necessary, e.g.,\n // for switching between atomic and non-atomic subdocuments\n // log.trace('setting publishedMessages', topic);\n this.publishedMessages.updateFromArray([...path, specialKey], json);\n\n // this.pubData.update(topic, json);\n // Still need to update the data so that we can detect changes we make\n // and publish them. But we need to break the reaction-chain to avoid\n // loops, so tag this update with 'published' and then ignore those\n // updates in this.publish.\n this.data.update(topic, json, {external: true});\n\n } else if (this.isSubscribed(topic)) {\n const json = mqttParsePayload(payload);\n\n log.debug('applying received update', topic);\n const changes = this.data.update(topic, json);\n onChange && Object.keys(changes).length > 0 && onChange(changes);\n }\n }\n // else: do not try to parse it, it might be a binary message sent\n // directly using the client (with or without retain)\n }\n });\n\n this.mqtt.subscribe(HEARTBEAT_TOPIC, {rap: true}, (err, granted) => {\n log.debug(HEARTBEAT_TOPIC, {granted});\n granted && granted.length > 0 && onHeartbeatGranted?.();\n });\n\n migrate?.length > 0 && this.migrate(migrate, () => {\n log.debug('done migrating');\n onReady && this.waitForHeartbeatOnce(onReady);\n });\n }\n\n /**\n * Publish all values at the given level of the given object under the given\n * topic (plus sub-key, of course).\n * TODO: Is this OK, or do we need to go through this.publish?\n */\n publishAtLevel(topic, value, level) {\n log.debug(`publishingAtLevel ${level}`, topic, value);\n\n if (level > 0) {\n _.forEach(value, (subValue, subKey) => {\n const subTopic = `${topic}/${encodeTopicElement(subKey)}`;\n log.debug(`publishing ${subTopic}`);\n this.publishAtLevel(subTopic, subValue, level - 1);\n });\n } else {\n this.mqtt.publish(topic, JSON.stringify(value), {retain: true}, (err) => {\n err && log.warn('Error when publishing migration result', err);\n });\n }\n }\n\n /** Migrate a list of `{topic, newVersion, transform}`. The version number in\n * topic will be ignored, and all versions' values will be merged, applied in\n * order, such that the latest version is applied last. `topic` may include\n * wildcards in the part before the version number but not after.\n *\n * Example:\n * ```js\n * mqttSync.migrate([{topic: '/+/dId/@scope/capname/+/b', newVersion: '1.2.0'}]\n * ```\n */\n migrate(list, onReady = undefined) {\n\n let toGo = list.length;\n if (toGo == 0) {\n onReady && onReady(); // in case an empty list was given\n return;\n }\n\n /* called each time one item is done */\n const oneDown = () => --toGo == 0 && onReady && onReady();\n\n list.forEach(({topic, newVersion, transform = undefined, flat = false,\n level = 0}) => {\n log.debug('migrating', topic, newVersion);\n const {organization, device, capability, sub} = parseMQTTTopic(topic);\n const prefix = `/${organization}/${device}/${capability}`;\n\n const suffix = sub.length == 0 ? '/#' : pathToTopic(sub);\n // suffix will have a leading slash\n const subTopic = `${prefix}/+${suffix}`;\n\n this.subscribe(subTopic, (err) => {\n if (err) {\n log.warn('Error during migration', err);\n oneDown();\n return;\n }\n\n const all = {};\n this.waitForHeartbeatOnce(() => {\n\n // for each match (prefix can include wildcards) merge everything\n this.data.forMatch(prefix, (value, path, match) => {\n // an actual (ground, aka. no wildcard) prefix\n const groundPrefix = pathToTopic(path);\n\n log.debug('got heartbeat', {prefix, topic, subTopic, suffix}, groundPrefix, value);\n if (!value) {\n // no data to migrate\n return;\n }\n // collect for cleanup\n Object.assign(all, value);\n\n const merged = mergeVersions(value, suffix, {maxVersion: newVersion});\n // get suffix in merged\n const suffixMergedValue = _.get(merged, topicToPath(suffix));\n log.debug({value, suffix, merged, suffixMergedValue});\n // ^ this will need to change to support wild-cards in suffix\n const transformed = transform ? transform(suffixMergedValue) :\n suffixMergedValue;\n\n // Publish the transformed value under the ground prefix as\n // `newVersion/suffix`\n const newTopic =\n resolveDoubleSlashes(`${groundPrefix}/${newVersion}/${suffix}`);\n log.debug('publishing merged', newTopic);\n\n if (flat) {\n const flatObj = toFlatObject(transformed);\n const newPath = topicToPath(newTopic);\n _.forEach(flatObj, (value, key) => {\n const keyTopic = pathToTopic(newPath.concat(topicToPath(key)));\n // TODO: Is this OK, or do we need to go through this.publish?\n this.mqtt.publish(keyTopic, JSON.stringify(value),\n {retain: true}, (err) => {\n err && log.warn(\n `Error when publishing migration result for ${key}`, err);\n });\n });\n\n } else {\n this.publishAtLevel(newTopic, transformed, level);\n }\n });\n\n this.unsubscribe(subTopic);\n\n if (Object.keys(all).length == 0) {\n // no data to migrate\n oneDown();\n return;\n }\n\n this.waitForHeartbeatOnce(() => {\n // now clear this suffix in the old version space\n const oldVersions = Object.keys(all).filter(v =>\n versionCompare(v, newVersion) < 0);\n // log.debug({oldVersions});\n\n const prefixesToClear = oldVersions.map(oldV =>\n resolveDoubleSlashes(`${prefix}/${oldV}/${suffix}`));\n\n this.clear(prefixesToClear);\n oneDown();\n });\n });\n });\n });\n }\n\n /** Delete all retained messages in a certain topic prefix, waiting for\n a mqtt broker heartbeat to collect existing retained. Use with care, never\n delete topics not owned by us. Harmless within capabilities, which are\n namespaced already.\n\n `options.filter(topic)`: a function that can be provided to further,\n programmatically filter the set of topics to clear, e.g., to onlt clear\n topics of old versions.\n\n Note: This may not yet work in robot-capabilities, since the subscription\n prefix and received topic prefix don't match (the device prefix is added to\n subscription by localMQTT.\n */\n clear(prefixes, callback = undefined, options = {}) {\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n topicMatch(`${prefix}/#`, topic)\n && (!options.filter || options.filter(topic))\n && toDelete.push(topic)\n );\n }\n this.mqtt.on('message', collectToDelete);\n // this only collects new topics, not those we've already received\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n this.mqtt.subscribe(`${prefix}/#`);\n } else {\n log.warn('Ignoring', prefix, 'since it is not a string.');\n }\n // add the topics we already know off:\n this.receivedTopics.forEach(topic => {\n if (topic.startsWith(prefix)) {\n log.debug('marking for deletion', `${prefix}${topic}`);\n toDelete.push(topic);\n }\n });\n });\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n this.waitForHeartbeatOnce(() => {\n this.mqtt.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => this.mqtt.unsubscribe(prefix));\n\n const count = toDelete.length;\n log.info(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n this.mqtt.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n });\n };\n\n\n /** register a callback for the next heartbeat from the broker */\n waitForHeartbeatOnce(callback) {\n // need to wait a tick, in case we are still in the callback tree\n // of a previous heartbeat waiter\n setTimeout(() => this.heartbeatWaitersOnce.push(callback), 1);\n }\n\n /** check whether we are subscribed to the given topic */\n isSubscribed(topic) {\n return Object.keys(this.subscribedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic));\n }\n\n /** Check whether we are publishing the given topic in a non-atomic way.\n This is used to determine whether to store the published value or not. */\n isPublished(topic) {\n return Object.keys(this.publishedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic) &&\n !this.publishedPaths[subscribedTopic].atomic\n );\n }\n\n /** Subscribe to the given topic (and all sub-topics). The callback will\n indicate success/failure, *not* a message on the topic. */\n subscribe(topic, callback = noop) {\n topic = ensureHashSuffix(topic);\n log.debug('subscribing to', topic);\n if (this.subscribedPaths[topic]) {\n log.debug('already subscribed to', topic);\n callback();\n return;\n }\n\n this.mqtt.subscribe(topic, {rap: true}, (err, granted) => {\n log.debug('subscribe', topic, 'granted:', granted);\n if (granted && granted.some(grant => grant.topic == topic && grant.qos < 128)) {\n // granted\n this.subscribedPaths[topic] = 1;\n callback(null);\n } else {\n // let user know (somehow) when we don't get permission\n callback(`not permitted to subscribe to topic ${topic}, ${JSON.stringify(granted)}`);\n }\n });\n }\n\n unsubscribe(topic) {\n topic = ensureHashSuffix(topic);\n if (this.subscribedPaths[topic]) {\n this.mqtt.unsubscribe(topic);\n delete this.subscribedPaths[topic];\n }\n }\n\n /** Publish retained to MQTT, store as published, and return a promise */\n _actuallyPublish(topic, value) {\n // return new Promise((resolve, reject) =>\n // this.mqtt.publish(topic,\n // value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n // {retain: true},\n // (err) => {\n // // Note that this returns optimistically at QoS 0, and no error occurs\n // // even when we are not allowed to publish this topic/message, see\n // // https://github.com/mqttjs/MQTT.js/#publish. Only when the client\n // // disconnects it seems.\n // if (err) {\n // log.warn('error in _actuallyPublish:', err);\n // reject(err);\n // // TODO: if this happens, we may need to force a full-sync\n // } else {\n // resolve();\n // }\n // }));\n\n if (!this.mqtt.connected) {\n log.warn('not connected, not publishing', topic);\n return false;\n }\n log.debug('actually publishing', topic);\n this.mqtt.publish(topic,\n value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n {retain: true});\n return true;\n }\n\n /** Send all items in the queue in sequence, if any and if not already\n running. */\n // async _processQueue() {\n // if (this._processing) return; // already running (and probably waiting)\n //\n // this._processing = true;\n // while (this.publishQueue.length > 0) {\n // const {topic, value} = this.publishQueue.shift();\n // await this._actuallyPublish(topic, value);\n // }\n // this._processing = false;\n // }\n\n // when using Map\n _processQueue_rec(cb) {\n if (this.publishQueue.size > 0) {\n const [topic, value] = this.publishQueue.entries().next().value;\n // this.publishQueue.delete(topic);\n // this._actuallyPublish(topic, value).then(\n // () => this._processQueue_rec(cb),\n // cb); // always call cb, even in rejection case\n if (this._actuallyPublish(topic, value)) {\n this.publishQueue.delete(topic);\n this._processQueue_rec(cb);\n } else {\n // try again soon\n setTimeout(() => this._processQueue_rec(cb), 5000);\n }\n } else {\n cb();\n }\n }\n\n _processQueue() {\n if (this._processing) return; // already running (and probably waiting)\n\n this._processing = true; // semaphore\n this._processQueue_rec(() => this._processing = false);\n }\n\n /** Set delay between processing of publishing queue in milliseconds. This\n allows you to effectively throttle the rate at which this instance will\n publish changes. Note that updates to a topic already in the queue will not\n cause multiple publications. Only the latest value will be published.\n @param {number} [delay] - Number of milliseconds to wait between processing\n of publish queue.\n */\n setThrottle(delay) {\n this._processQueueThrottled =\n _.throttle(this._processQueue.bind(this), delay);\n }\n\n /** Clear the set throttling delay. */\n clearThrottle() {\n delete this._processQueueThrottled;\n }\n\n addToQueue(topic, value) {\n // this.publishQueue.push({topic, value});\n this.publishQueue.set(topic, value);\n }\n\n /** Add to publication queue */\n _enqueue(topic, value) {\n log.debug('enqueuing', topic);\n this.addToQueue(topic, value);\n if (this._processQueueThrottled) {\n this._processQueueThrottled();\n } else {\n this._processQueue();\n }\n // yes, this is optimistic, but if we don't, then upcoming changes\n // may not work as expected (e.g., when switching from flat to atomic to flat)\n const path = topicToPath(topic);\n this.publishedMessages.updateFromArray([...path, specialKey],\n value == null ? null : clone(value));\n }\n\n /** Register a listener for path in data. Make sure to populate the data\n before calling this or set the data all at once afterwards.\n\n With option \"atomic\" this will always send the whole sub-document,\n not flat changes. Useful, e.g., for desiredPackages, see\n https://github.com/chfritz/transitive/issues/85.\n\n @return true if publication added (false, e.g., when already present)\n */\n publish(topic, options = {atomic: false}) {\n topic = ensureHashSuffix(topic);\n\n if (_.isEqual(this.publishedPaths[topic], options)) {\n return false;\n // avoid double subscription\n }\n this.publishedPaths[topic] = options;\n\n if (options.atomic) {\n // this case is quite simple\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n // do not re-publish changes received from external:\n if (tags?.external) return;\n\n log.debug('processing change (atomic)', key, topic);\n // instantiate topic according to key (topic may have wildcards)\n const topicWithoutHash = topic.slice(0, topic.length - 2);\n const groundedTopic = pathToTopic(\n // get length of topic (how many levels of selectors), get that many\n // levels from key prefix\n topicToPath(key).slice(0, topicToPath(topicWithoutHash).length)\n );\n this._enqueue(groundedTopic, this.data.getByTopic(groundedTopic));\n });\n return true;\n }\n\n this.mqtt.subscribe(topic);\n\n // second: keep them up to date by publishing updates as changes happen\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n if (tags?.external) return;\n\n log.debug('processing change', key);\n\n /* First: establish clarity by ensuring that the object defined by the\n currently present retained messages under this path accurately reflect\n the current value of this.data (and if not, publish what is necessary to\n create consistency). */\n // first, clear/replace all messages below or above this sub-path (if any)\n const path = topicToPath(key);\n\n // Check flat to atomic\n const publishedSub = this.publishedMessages.get(path);\n _.each(publishedSub, (oldSubVal, oldSubKey) => {\n if (oldSubKey == specialKey) return true;\n // We are going from flat to atomic, i.e., we are publishing at a\n // higher level than before: clear out old sub-keys.\n\n // Find all sub-sub-keys that end in `specialKey`:\n const toClear = Object.keys(toFlatObject(oldSubVal))\n .filter(subkey => subkey.endsWith(specialKey));\n\n log.debug('flat->atomic: ', {toClear}, oldSubKey);\n // Clear them all:\n toClear.forEach(oldSubSubKey => {\n const oldKey = oldSubSubKey.slice(0, -(specialKey.length + 1));\n const clearKey = `${key}/${oldSubKey}/${oldKey}`\n // log.debug('flat->atomic: clear', clearKey);\n this._enqueue(clearKey, null);\n });\n });\n\n // Check atomic to flat\n const published = this.publishedMessages.get();\n visitAncestor(published, path.slice(0, -1), (subObj, prefix) => {\n const oldVal = subObj[specialKey];\n if (oldVal && _.isObject(oldVal)) {\n log.debug('atomic->flat', {oldVal});\n // A parent topic has been published. We are going from atomic to\n // separate values: need to transform existing sub-document to flat\n // values.\n\n // Remove the old published (atomic) message:\n const prefixTopic = pathToTopic(prefix);\n this._enqueue(prefixTopic, null);\n\n // Now re-add as separate flat messages\n const flat = toFlatObject(oldVal);\n _.each(flat, (flatValue, flatKey) => {\n const oldFlatKey = `${prefixTopic}${flatKey}`;\n this._enqueue(oldFlatKey, flatValue);\n })\n }\n });\n\n /* We need to first wait until all of the above messages are out;\n otherwise replacing an atomic `/a = {c: 1}` with `/a/c = 2` would create\n a race condition where it is not clear which message, the replacement\n c = 1 or the new c = 2, would be sent last (and hence retained). That's\n why we use a publishing queue in this class.\n */\n this._enqueue(key, value);\n return true;\n });\n }\n\n /** Run all registered hooks before disconnecting */\n beforeDisconnect() {\n this.beforeDisconnectHooks.forEach(fn => fn(this));\n }\n\n /** Register a new hook to be called before disconnecting */\n onBeforeDisconnect(fn) {\n this.beforeDisconnectHooks.push(fn);\n }\n\n /* --------------------------------------------------------------------------\n * Remote Procedure Calls (RPC)\n */\n\n /* Handle RPC requests */\n async handleRPCRequest(topic, json) {\n log.debug('handling RPC request for', topic, json);\n const handler = this.rpcHandlers[topic];\n const result = handler(json.args);\n\n const responseTopic = `${topic.replace('/request', '/response')}/${json.id}`;\n\n if (result instanceof Promise) {\n result.then( resultValue => this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result: resultValue }),\n {retain: false, qos: 2}));\n } else {\n this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result }),\n {retain: false, qos: 2});\n }\n }\n\n /* Handle RPC response */\n handleRPCResponse(topic, json) {\n log.debug('handle RPC response', topic, json);\n this.rpcCallbacks[topic](json.result);\n delete this.rpcCallbacks[topic];\n this.mqtt.unsubscribe(topic);\n }\n\n /** Register an RPC request handler. Example:\n * ```js\n * mqttSync.register('/mySquare', arg => {\n * log.debug('running /mySquare with args', arg);\n * return arg * arg;\n * });\n * ```\n * Note that the command topic needs to be in the capabilities namespace like\n * any other topic. In robot capabilities, as usual, these can start in `/`\n * because the local mqtt bridge operated by the robot agent will place all\n * topics in their respective namespace. In the cloud and on the web you will\n * need to use the respective namespace, i.e.,\n * `/orgId/deviceId/@scope/capName/capVersion/`.\n *\n * #### Async/Await\n * Yes, you can make the handler `async` and use `await` inside of it. This\n * will be handled correctly, i.e., MqttSync will await the result of the\n * handler before responding to the RPC request client.\n */\n register(command, handler) {\n log.debug('registering RPC handler for', command);\n const requestTopic = `${command}/request`;\n\n this.rpcHandlers[requestTopic] = handler;\n this.mqtt.subscribe(requestTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC topic ${requestTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC topic ${requestTopic}`);\n }\n });\n }\n\n /** Make an RPC request. Example:\n * ```js\n * mqttSync.call('/mySquare', 11, result => {\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * });\n * ```\n * Alternative you can omit the callback and use async/await:\n * ```js\n * const result = await mqttSync.call('/mySquare', 11);\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * ```\n * See the note about namespaces in `register`.\n *\n * Note: It is your responsibility to only call methods that exist (have been\n * registered). Calling a non-existent command just hangs.\n */\n call(command, args, callback = undefined) {\n const id = getRandomId();\n\n const responseTopic = `${command}/response/${id}`;\n this.mqtt.subscribe(responseTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC response topic ${responseTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC response topic ${responseTopic}`);\n }\n });\n\n const requestTopic = `${command}/request`\n log.debug('calling RPC', requestTopic);\n this.mqtt.publish(requestTopic, JSON.stringify({ id, args }),\n {retain: false, qos: 2});\n\n if (callback) {\n this.rpcCallbacks[responseTopic] = callback;\n } else {\n return new Promise((resolve, reject) => {\n this.rpcCallbacks[responseTopic] = resolve;\n });\n }\n }\n}\n\nmodule.exports = MqttSync;\n", "export * from './client/shared.jsx';\nexport * from './client/hooks.jsx';\nexport * from './client/client';\n", "import React, { useState, useEffect, useMemo, useRef } from 'react';\nimport { Button, Accordion, AccordionContext, Card, Badge }\n from 'react-bootstrap';\nimport ReactWebComponent from './react-web-component';\n\nimport { parseCookie, decodeJWT } from './client';\nimport { useCapability } from './hooks';\n\nconst styles = {\n badge: {\n width: '4em'\n },\n code: {\n color: '#700',\n borderLeft: '3px solid #aaa',\n padding: '0.5em 0px 0.5em 2em',\n backgroundColor: '#f0f0f0',\n borderRadius: '4px',\n marginTop: '0.5em',\n },\n inlineCode: {\n color: '#700',\n margin: '0px 0.5em 0px 0.5em',\n }\n};\n\nconst levelBadges = [\n <Badge bg=\"success\" style={styles.badge}>OK</Badge>,\n <Badge bg=\"warning\" style={styles.badge}>Warn</Badge>,\n <Badge bg=\"danger\" style={styles.badge}>Error</Badge>,\n <Badge bg=\"secondary\" style={styles.badge}>Stale</Badge>,\n];\n\n/* The right badge for the level */\nexport const LevelBadge = ({level}) => levelBadges[level] || <span>{level}</span>;\n\n/** Reusable component for showing code */\nexport const Code = ({children}) => <pre style={styles.code}>\n {children}\n</pre>;\n\nexport const InlineCode = ({children}) => <tt style={styles.inlineCode}>\n {children}\n</tt>;\n\n\nconst intervals = {};\n\nexport const TimerContext = React.createContext({});\nexport const Timer = ({duration, onTimeout, onStart, setOnDisconnect, children}) => {\n duration = duration || 60;\n const [timer, setTimer] = useState(duration);\n const [running, setRunning] = useState(false);\n const id = useMemo(() => Math.random().toString(36).slice(2), []);\n\n const stop = () => {\n console.log('stopping timer for', id);\n onTimeout && setTimeout(onTimeout, 1);\n clearInterval(intervals[id]);\n intervals[id] = null;\n setRunning(false);\n };\n\n const startTimer = () => {\n const interval = intervals[id];\n console.log(interval, intervals, timer);\n if (!interval && timer > 0) {\n setRunning(true);\n intervals[id] = setInterval(() =>\n setTimer(t => {\n if (--t > 0) {\n return t;\n } else {\n stop();\n }\n }), 1000);\n onStart && setTimeout(onStart, 1);\n }\n\n return stop;\n };\n\n useEffect(() => { timer > 0 && !running && startTimer() }, [timer]);\n\n useEffect(() => stop, []);\n\n setOnDisconnect && setOnDisconnect(() => {\n // call on disconnect of the web component\n stop()\n });\n\n const reset = () => setTimer(duration);\n\n return <TimerContext.Provider value={{reset, duration, timer}}>\n {timer > 0 ? <div>\n {children}\n {timer < 60 && <div>Timeout in: {timer} seconds</div>}\n </div> :\n <div>Timed out. <Button onClick={reset}>\n Resume\n </Button>\n </div>}\n </TimerContext.Provider>;\n};\n\n\n/** Dynamically load and use the Transitive web component specified in the JWT.\n* Embedding Transitive components this way also enables the use of functional\n* and object properties, which get lost when using the custom element (Web\n* Component) because HTML attributes are strings.\n* Example:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* myconfig={{a: 1, b: 2}}\n* onData={(data) => setData(data)}\n* onclick={() => { console.log('custom click handler'); }}\n* />\n* ```\n*\n* Always loads the capability specified in the JWT and will default to the\n* main component for that JWT (`-device` or `-fleet`). To specify a secondary\n* component offered by the capability specify `component`, e.g., to load\n* `webrtc-video-supervisor` instead of `webrtc-video-device`, provide a device\n* JWT for webrtc-video and use:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* component='webrtc-video-supervisor'\n* auto=\"true\"\n* />\n* ```\n*/\nexport const TransitiveCapability = ({\n jwt, host = 'transitiverobotics.com', ssl = true, ...config\n }) => {\n\n const assertPresent = (value, name) => {\n if (!value) throw new Error(`JWT is missing ${name}`);\n };\n\n const {id, device, capability} = decodeJWT(jwt);\n // Throw an error when any of the above payload is missing\n assertPresent(id, 'id');\n assertPresent(device, 'device');\n assertPresent(capability, 'capability');\n\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n const component = config.component || name;\n\n const { loaded } = useCapability({\n capability,\n name,\n userId: id || config.userId, // accept both id and userId, see #492\n deviceId: device,\n host,\n ssl\n });\n\n const ref = useRef();\n // Attach functional and object properties to the component when ready and\n // on change\n useEffect(() => {\n ref.current?.instance?.setState(s =>\n ({ ...s, id, jwt, host, ssl, ...config }));\n }, [ref.current, loaded, id, jwt, host, ssl, ...Object.values(config)]);\n\n // Disrupt the reactive chain of the MutationObserver to the customElement,\n // so we are not competing with it for updating the props.\n const propClone = useMemo(() => ({id, jwt, host, ssl, ...config}), []);\n\n if (!loaded) return <div>Loading {name}</div>;\n return React.createElement(component, {...propClone, ref});\n };\n\n\n/** A simple error boundary. Usage:\n* ```jsx\n* <ErrorBoundary message=\"Something went wrong\">\n* <SomeFlakyComponent />\n* </ErrorBoundary>\n* ```\n*/\nexport class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n hasError: false,\n messages: [],\n };\n }\n\n static getDerivedStateFromError(error) {\n return { hasError: true };\n }\n\n componentDidCatch(error, errorInfo) {\n console.warn('ErrorBoundary caught:', error, errorInfo);\n this.setState(({messages}) => ({messages: [...messages, error.message]}));\n }\n\n render() {\n return (this.state.hasError ? <div>\n Error: {this.props.message || this.state.messages?.join(', ')\n || 'Something went wrong here.'}\n </div>\n : this.props.children);\n }\n};\n\n\nexport const CapabilityContext = React.createContext({});\n\n/* Only used internally: the actual context provider, given the loaded module */\nconst LoadedCapabilityContextProvider = (props) => {\n const {children, jwt, id, host, ssl, loadedModule} = props;\n\n const context = loadedModule.provideContext?.({\n jwt, id, host, ssl, appReact: React\n });\n\n return <CapabilityContext.Provider value={{ ...context }}>\n {children}\n </CapabilityContext.Provider>;\n};\n\n/**\n* Context provider for capabilities. Use this to access the front-end API\n* provided by some capabilities. Example:\n* ```jsx\n* <CapabilityContextProvider jwt={jwt}>\n* <MyROSComponent />\n* </CapabilityContextProvider>\n* ```\n* where `jwt` is a JWT for a capability that exposes a front-end API. Then use\n* `useContext` in `MyROSComponent` to get the exposed data and functions, e.g.:\n* ```jsx\n* const MyROSComponent = () => {\n* const { ready, subscribe, data } = useContext(CapabilityContext);\n* // When ready, subscribe to the `/odom` topic in ROS1\n* useEffect(() => { ready && subscribe(1, '/odom'); }, [ready]);\n* return <pre>{JSON.stringify(data, true, 2)}</pre>;\n* }\n* ```\n* Where `ready`, `subscribe`, and `data` are reactive variables and functions\n* exposed by the capability of the provided JWT. In this example, the latest\n* message from the subscribed ROS topics will be available in the capabilities\n* namespace in `data`.\n* @param {object} props\n*/\nexport const CapabilityContextProvider =\n ({children, jwt, host = undefined, ssl = undefined}) => {\n\n const {id, device, capability} = decodeJWT(jwt);\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n\n const {loaded, loadedModule} = useCapability({\n capability,\n name,\n userId: id,\n deviceId: device,\n appReact: React,\n host,\n ssl\n });\n\n if (!loadedModule) return <div>Loading {capability}</div>;\n return <LoadedCapabilityContextProvider {...{jwt, id, host, ssl, loadedModule}}>\n {children}\n </LoadedCapabilityContextProvider>;\n };\n\n\n/* whether or not the given react component allows refs, i.e., is either\n * a functional component wrapped with forwardRef or a class component */\nconst componentPermitsRefs = (Component) =>\n (Component.$$typeof == Symbol.for('react.forward_ref'))\n || Component.prototype?.render;\n\n\n/** Create a WebComponent from the given react component and name that is\n* reactive to all attributes. Used in web capabilities. Example:\n* ```js\n* createWebComponent(Diagnostics, 'health-monitoring-device', TR_PKG_VERSION);\n* ```\n*/\nexport const createWebComponent = (Component, name, version = '0.0.0',\n options = {}) => {\n\n // Only create a ref if the component accepts it. This avoids an ugly\n // error in the console when trying to give a ref to a non-forwardRef-wrapped\n // functional component.\n const compRef = componentPermitsRefs(Component) ? React.createRef() : null;\n\n class Wrapper extends React.Component {\n\n onDisconnect = null;\n state = {};\n\n componentDidMount() {\n this.props._element.instance = this;\n this.webComponentConstructed(this.props._element);\n this.props._element.callLifeCycleHook('connectedCallback');\n }\n\n /* function used by `Component` to register a onDisconnect handler */\n setOnDisconnect(fn) {\n this.onDisconnect = fn;\n }\n\n webComponentConstructed(instance) {\n // Observe all changes to attributes and update React state from it\n const observer = new MutationObserver((mutationRecords) => {\n const update = {};\n mutationRecords.forEach(({attributeName}) => {\n update[attributeName] = instance.getAttribute(attributeName);\n });\n this.setState(old => ({...old, ...update}));\n }).observe(instance, { attributes: true });\n }\n\n webComponentDisconnected() {\n // This ensures that the react component unmounts and all useEffect\n // cleanups are called.\n this.setState({_disconnected: true});\n try {\n this.onDisconnect && this.onDisconnect();\n } catch (e) {\n console.log('Error during onDisconnect of web-component', e);\n }\n }\n\n /* method exposed to the wrapped component via prop that allows setting\n * the \"config\" state variable inside the wrapper (not the component\n * itself). This config is retrieved by the portal for inclusion in the\n * embedding instructions. */\n setConfig(config) {\n this.setState({config});\n }\n\n render() {\n const stylesheets = options.stylesheets || [\n // 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css'\n // Bootstrap 5.3.2 css scoped to `.transitive-bs-root`:\n 'https://cdn.jsdelivr.net/gh/transitiverobotics/transitive-utils@0.8.3/web/css/bootstrap_transitive-bs-root.min.css'\n ];\n\n return <div id={`cap-${name}-${version}`}\n className={options.className || 'transitive-bs-root'}>\n <style>\n {stylesheets.map(url => `@import url(${url});`)}\n </style>\n\n {!this.state._disconnected &&\n <Component ref={compRef}\n {...this.props}\n // Important to keep state *after* props for reactivity to work\n {...this.state}\n setOnDisconnect={this.setOnDisconnect.bind(this)}\n setConfig={this.setConfig.bind(this)}\n />}\n </div>;\n }\n };\n\n return ReactWebComponent.create(Wrapper, name, options.shadowDOM || false,\n compRef);\n };\n", "// It is OK to use paths outside of this package because webpack will bundle them\nexport * from '../../common/common.js';\nexport * from '../../common/DataCache';\nimport MS from '../../common/MqttSync.js';\nexport const MqttSync = MS;\n\n// moved to common\n// export const decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n\n/** parse document cookies */\nexport const parseCookie = str =>\n str.split(';')\n .map(v => v.split('='))\n .reduce((acc, v) => {\n acc[decodeURIComponent(v[0].trim())] =\n v[1] && decodeURIComponent(v[1].trim());\n return acc;\n }, {});\n\n/** get or post (if body given) json */\nexport const fetchJson = (url, callback, options = {}) => {\n fetch(url, {\n method: options.method || (options.body ? 'post' : 'get'),\n mode: 'cors',\n cache: 'no-cache',\n // Maybe we'll need this (when embedding)?\n // credentials: 'same-origin', // include, *same-origin, omit\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers\n },\n redirect: 'follow',\n referrerPolicy: 'no-referrer',\n body: options.body ? JSON.stringify(options.body) : undefined\n }).then(res => {\n const error = !res.ok &&\n `fetching ${url} failed: ${res.status} ${res.statusText}`;\n res.json()\n .then(data => callback(error, data))\n .catch(err => {\n throw new Error(err);\n });\n }).catch((error) => callback(`error: ${error}`));\n};\n", "import React, { useState, useEffect, useMemo } from 'react';\nimport _ from 'lodash';\n// import mqtt1 from 'mqtt';\nimport mqtt from 'mqtt/dist/mqtt.esm';\n\nimport { decodeJWT, getLogger, clone, pathToTopic, mergeVersions, topicToPath }\n from './client';\nconst MqttSync = require('../../common/MqttSync');\n\nconst log = getLogger('utils-web/hooks');\nlog.setLevel('info');\n\nconst RECONNECT_PERIOD_DEFAULT = 1000; // default time until mqtt retries connecting\nconst RECONNECT_PERIOD_MAX = 20000; // max retry time (after dynamic backoff)\n\n/** Hook for using MqttSync in React.\n* @returns {object} An object `{data, mqttSync, ready, StatusComponent, status}`\n* where:\n* `data` is a reactive data source in React containing all the data received by\n* mqttsync,\n* `mqttSync` is the MqttSync object itself,\n* `ready` indicates when mqttSync is ready to be used (connected and received\n* successfully subscribed to mqtt system heartbeats)\n*/\nexport const useMqttSync = ({jwt, id, mqttUrl, appReact}) => {\n const { useState, useRef, useEffect } = appReact || React;\n\n const [status, setStatus] = useState('connecting');\n const [mqttSync, setMqttSync] = useState();\n const [data, setData] = useState({});\n // True once the subscription to the system heartbeat has been granted.\n const [heartbeatGranted, setHeartbeatGranted] = useState(false);\n\n useEffect(() => {\n const payload = decodeJWT(jwt);\n\n // pre-check validity of JWT, don't use if expired\n const { validity, iat } = payload;\n if (!validity || !iat || (iat + validity) * 1e3 < Date.now()) {\n const error = 'The provided JWT is invalid or expired.';\n log.warn(error, payload);\n setStatus(`error: ${error}`);\n return;\n }\n\n /** Implement dynamic backoff when we fail to connect. */\n let reconnectPeriod = RECONNECT_PERIOD_DEFAULT; // default to start with\n const transformWsUrl = (url, options, client) => {\n options.reconnectPeriod = reconnectPeriod;\n log.info(`reconnect in ${options.reconnectPeriod} s`);\n return url;\n }\n\n log.debug('(re-)create mqtt client');\n const client = mqtt.connect(mqttUrl, {\n username: JSON.stringify({id, payload}),\n password: jwt,\n transformWsUrl\n });\n\n // Increase backoff with each close (since we can't actually detect auth\n // errors)\n client.on('close', () =>\n reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX)\n );\n\n // reset to default after a successful connection\n client.on('connect', () => reconnectPeriod = RECONNECT_PERIOD_DEFAULT);\n\n client.once('connect', () => {\n log.debug('MQTT connected');\n\n const mqttSyncClient = new MqttSync({\n mqttClient: client,\n ignoreRetain: true,\n onHeartbeatGranted: () => setHeartbeatGranted(true)\n });\n setMqttSync(mqttSyncClient);\n setStatus('connected');\n\n // Update data on change. Note: need to clone object to force reaction\n mqttSyncClient.data.subscribe(_.throttle(() =>\n setData(clone(mqttSyncClient.data.get())), 50));\n });\n\n client.on('error', (error) => {\n log.error(error);\n setStatus(`error: ${error}`);\n });\n\n return () => {\n log.info('cleaning up useMQTTSync');\n if (mqttSync && mqttSync.beforeDisconnect) {\n mqttSync.beforeDisconnect();\n mqttSync.waitForHeartbeatOnce(() => client.end());\n } else {\n client.end();\n }\n };\n }, [jwt, id]);\n\n return {\n status,\n // ready: status == 'connected',\n ready: heartbeatGranted,\n StatusComponent: () => <div>{status}</div>,\n mqttSync, // Note: mqttSync.data is not reactive.\n data, // This is a reactive data-source (to use meteor terminology).\n };\n};\n\n/** Hook for using Transitive in React. Connects to MQTT, establishes sync, and\n* exposes reactive `data` state variable. */\nexport const useTransitive =\n ({jwt, id, capability, versionNS, appReact,\n host = 'transitiverobotics.com', ssl = true }) => {\n\n const [scope, capabilityName] = capability.split('/');\n\n const { device } = decodeJWT(jwt);\n const prefixPath = [id, device, scope, capabilityName];\n const prefix = pathToTopic(prefixPath);\n const prefixPathVersion = [...prefixPath, versionNS];\n const prefixVersion = pathToTopic(prefixPathVersion);\n\n const mqttUrl = `${ssl && JSON.parse(ssl) ? 'wss' : 'ws'}://mqtt.${host}`;\n const fromMqttSync = useMqttSync({ jwt, id, mqttUrl, appReact });\n\n return {...fromMqttSync, device, prefixPath, prefix, prefixPathVersion,\n prefixVersion};\n };\n\n\n/** Subscribe to MqttSync topics using the provided JWT. This will\n* automatically find which version of the capability named in the JWT is running\n* on the device of the JWT and get the data for that version.\n*\n* Example usage (with webrtc-video):\n*\n* ```js\n* const { agentStatus, topicData } = useTopics({ jwt, topics: [\n* '/options/videoSource',\n* '/stats/+/log/'\n* ]});\n* ```\n*\n* @param {object} options An object containing:\n* `JWT`: A list of subtopics of the capability named in the JWT.\n* `topics`: A list of subtopics of the capability named in the JWT.\n* @returns {object} An object `{data, mqttSync, ready, agentStatus, topicData}`\n* where:\n* `agentStatus` is the `status` field of the running robot agent, including\n* heartbeat and runningPackages, and\n* `topicData` is the data for the selected topics of the capability\n*/\nexport const useTopics = ({jwt, host = 'transitiverobotics.com', ssl = true,\n topics = [], appReact}) => {\n\n const { useState, useEffect } = appReact || React;\n\n // We need to make sure we don't resubscribe (below) when this function\n // is called with the same content of `topics` but a different object.\n const [topicList, setTopicList] = useState();\n !_.isEqual(topicList, topics) && setTopicList(topics);\n\n const {device, id, capability} = decodeJWT(jwt);\n if (device == '_fleet') {\n log.warn('useTopics only works for device JWTs, not _fleet ones');\n return;\n }\n\n const agentPrefix = `/${id}/${device}/@transitive-robotics/_robot-agent/+/status`;\n\n const {mqttSync, data, status, ready, StatusComponent} =\n useMqttSync({jwt, id, mqttUrl: `ws${ssl ? 's' : ''}://mqtt.${host}`, appReact});\n\n useEffect(() => {\n if (ready) {\n mqttSync.subscribe(agentPrefix, (err) => err && console.warn(err));\n }\n }, [mqttSync, ready]);\n\n const agentStatus = mergeVersions(\n data[id]?.[device]['@transitive-robotics']['_robot-agent'], 'status').status;\n const runningPackages = agentStatus?.runningPackages;\n\n const [scope, capName] = capability.split('/');\n const versions = runningPackages?.[scope]?.[capName];\n const runningVersion = versions && Object.values(versions).filter(Boolean)[0];\n const prefix = `/${id}/${device}/${capability}/${runningVersion}`;\n\n useEffect(() => {\n log.debug('topics', topics);\n if (runningVersion) {\n topics.forEach(topic => {\n log.debug(`subscribing to ${prefix}${topic}`);\n mqttSync.subscribe(`${prefix}${topic}`,\n (err) => err && log.warn(err));\n });\n }\n }, [topicList, runningVersion, mqttSync]);\n\n const topicData = _.get(data, topicToPath(prefix));\n // log.debug(data, agentStatus, topicData);\n\n return {data: data?.[id]?.[device], mqttSync, agentStatus, topicData};\n };\n\n\nconst listeners = {};\nconst loadedModules = {};\n/** Hook to load a Transitive capability. Besides loading the custom element,\n* this hook also returns any functions and objects the component exports in\n* `loadedModule`. Example:\n* ```js\n* const {loaded, loadedModule} = useCapability({\n* capability: '@transitive-robotics/terminal',\n* name: 'mock-device',\n* userId: 'user123',\n* deviceId: 'd_mydevice123',\n* });\n* ```\n*/\nexport const useCapability = ({ capability, name, userId, deviceId,\n host = 'transitiverobotics.com', ssl = true, appReact\n }) => {\n const { useState, useEffect } = appReact || React;\n\n const [returns, setReturns] = useState({ loaded: false });\n\n // called when loaded\n const done = (message, theModule) => {\n log.debug(`custom component ${name}: ${message}`);\n loadedModules[name] = theModule;\n setReturns(x => ({...x, loadedModule: theModule, loaded: !!theModule}));\n };\n\n /** set the returns for all listeners */\n const notifyListeners = (...args) => listeners[name].forEach(l => l(...args));\n\n useEffect(() => {\n log.debug(`loading custom component ${name}`);\n\n if (loadedModules[name]) {\n return done('already loaded', loadedModules[name]);\n }\n if (listeners[name]) {\n log.debug('already loading');\n // get notified when loading completes\n listeners[name].push(done);\n return;\n }\n listeners[name] = [done];\n\n const baseUrl = `http${ssl ? 's' : ''}://portal.${host}`;\n const params = new URLSearchParams({ userId, deviceId });\n // filename without extension as we'll try multiple\n const fileBasename = `${baseUrl}/running/${capability}/dist/${name}`;\n\n /* Since some users use webpack and webpack is stupid, we need to use\n this magic comment for it to ignore these (remote) requests, see:\n https://webpack.js.org/api/module-methods/#webpackignore. */\n import(/* webpackIgnore: true */\n `${fileBasename}.esm.js?${params.toString()}`).then(\n esm => notifyListeners('loaded esm', esm),\n error => {\n log.warn(`No ESM module found for ${name}, loading iife`, error);\n import(/* webpackIgnore: true */\n `${fileBasename}.js?${params.toString()}`).then(\n iife => notifyListeners('loaded iife', iife),\n error => log.error(`Failed to load ${name} iife`, error));\n });\n }, [capability, name, userId, deviceId]);\n\n return returns;\n };\n\n\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,4FAAAA,SAAA;AAIA,IAAAA,QAAO,UAAU,MAAM;AACrB,UAAI;AACF,eAAO,QAAQ,0CAA0C,EAAE;AAAA,MAC7D,SAAS,GAAG;AACV,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA;AAAA;;;ACVA;AAAA,6DAAAC,SAAA;AAMA,IAAAA,QAAO,UAAU,SAAS,kBAAkB,SAAS;AACnD,UAAI,CAAC,QAAQ,YAAY;AACvB,eAAO,CAAC;AAAA,MACV;AAEA,UAAI,MAAM,CAAC;AACX,UAAI;AACJ,YAAM,sBAAsB,CAAC,GAAG,QAAQ,UAAU;AAClD,YAAM,aAAa,oBAAoB,IAAI,CAACC,gBACzC,EAAE,CAACA,WAAU,IAAI,GAAGA,WAAU,MAAM,EAAE;AAEzC,WAAK,aAAa,YAAY;AAC5B,cAAM,MAAM,OAAO,KAAK,SAAS,EAAE,CAAC;AACpC,cAAM,gBAAgB,IAAI,QAAQ,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,YAAY,CAAC;AACxE,YAAI,aAAa,IAAI,UAAU,GAAG;AAAA,MACpC;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;;;ACxBA;AAAA,iDAAAC,SAAA;AAAA,QAAMC,SAAQ,QAAQ,OAAO;AAC7B,QAAM,WAAW,QAAQ,WAAW;AACpC,QAAM,EAAE,WAAW,IAAI,QAAQ,kBAAkB;AAGjD,QAAM,iBAAiB,QAAQ,kCAAkC;AACjE,QAAM,mDAAmD;AACzD,QAAM,oBAAoB;AAK1B,QAAM,iBAAiB;AAAA,MACrB,kBAAkB;AAAA,MAClB,mBAAmB;AAAA,MACnB,sBAAsB;AAAA,MACtB,iBAAiB;AAAA,IACnB;AAEA,IAAAD,QAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMf,QAAQ,CAAC,SAAS,SAAS,eAAe,MAAM,UAAU,WAAc;AAEtE,cAAM,QAAQ,cAAc,YAAY;AAAA,UACtC,WAAW;AAAA;AAAA,UAEX,sBAAsB;AACpB,gBAAI,KAAK,SAAS,yBAAyB,GAAG;AAC5C,mBAAK,SAAS,yBAAyB,EAAE,MAAM,KAAK,UAAU,CAAC,IAAI,CAAC;AAAA,YACtE;AAAA,UACF;AAAA,UAEA,kBAAkB,MAAM,SAAS,CAAC,GAAG;AACnC,kBAAM,SAAS,eAAe,IAAI;AAClC,gBAAI,UAAU,KAAK,YAAY,KAAK,SAAS,MAAM,GAAG;AACpD,mBAAK,SAAS,MAAM,EAAE,MAAM,KAAK,UAAU,MAAM;AAAA,YACnD;AAAA,UACF;AAAA,UAEA,oBAAoB;AAClB,kBAAM,OAAO;AACb,gBAAI,aAAa;AAEjB,gBAAI,cAAc;AAEhB,oBAAM,aAAa,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAGrD,2BAAa,SAAS,cAAc,KAAK;AAKzC,oBAAME,UAAS,iDAAiD;AAChE,cAAAA,QAAO,QAAQ,CAAC,UAAU;AACxB,2BAAW,YAAY,MAAM,UAAU,UAAU,CAAC;AAAA,cACpD,CAAC;AAED,yBAAW,YAAY,UAAU;AACjC,6BAAe,UAAU;AAAA,YAC3B;AAEA,uBAAW,UAAU,EAAE;AAAA;AAAA,cAErBD,OAAM,cAAc,SAAS,EAAC,UAAU,MAAM,GAAG,kBAAkB,IAAI,EAAC,CAAC;AAAA,YAC3E;AAAA,UACF;AAAA,UAEA,uBAAuB;AACrB,iBAAK,kBAAkB,sBAAsB;AAAA,UAC/C;AAAA,UAEA,gBAAgB,aAAa,aAAa;AACxC,iBAAK,kBAAkB,mBAAmB,CAAC,aAAa,WAAW,CAAC;AAAA,UACtE;AAAA;AAAA;AAAA,UAIA,KAAK,cAAc,MAAM;AACvB,mBAAO,SAAS,UAAU,YAAY,GAAG,KAAK,SAAS,SAAS,IAAI;AAAA,UACtE;AAAA;AAAA;AAAA;AAAA,UAKA,YAAY;AACV,mBAAO,KAAK,SAAS,MAAM;AAAA,UAC7B;AAAA,QACF;AAEA,uBAAe,OAAO,SAAS,KAAK;AAEpC,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;;;AClGA;AAAA,oCAAAE,SAAA;AAAA,IAAAA,QAAO,UAAU;AAAA,MACf,aAAa;AAAA,QACX,SAAS,EAAE,YAAY,GAAG,gBAAgB,SAAS;AAAA,QACnD,SAAS,EAAE,YAAY,GAAG,gBAAgB,SAAS;AAAA,QACnD,QAAQ,EAAE,YAAY,GAAG,gBAAgB,QAAQ;AAAA,QACjD,SAAS,EAAE,YAAY,EAAE;AAAA,QACzB,UAAU,EAAE,YAAY,EAAE;AAAA,QAC1B,MAAM,EAAE,YAAY,EAAE;AAAA,QACtB,UAAU,EAAE,YAAY,EAAE;AAAA,QAC1B,QAAQ,EAAE,YAAY,EAAE;AAAA,QACxB,MAAM,EAAE,YAAY,EAAE;AAAA,QACtB,OAAO,EAAE,YAAY,EAAE;AAAA,QACvB,QAAQ,EAAE,YAAY,EAAE;AAAA,QACxB,SAAS,EAAE,YAAY,EAAE;AAAA,MAC3B;AAAA,IACF;AAAA;AAAA;;;ACfA;AAAA,iCAAAC,SAAA;AAAA,QAAM,gBAAgB,QAAQ,0BAA0B;AACxD,QAAM,mBAAmB,QAAQ,2BAA2B;AAE5D,QAAMC,KAAI;AAAA,MACR,KAAK,QAAQ,YAAY;AAAA,MACzB,KAAK,QAAQ,YAAY;AAAA,MACzB,OAAO,QAAQ,cAAc;AAAA,MAC7B,SAAS,QAAQ,gBAAgB;AAAA,MACjC,KAAK,QAAQ,YAAY;AAAA,MACzB,SAAS,QAAQ,gBAAgB;AAAA,MACjC,IAAI,QAAQ,gBAAgB;AAAA,MAC5B,eAAe,QAAQ,sBAAsB;AAAA,MAC7C,OAAO,QAAQ,cAAc;AAAA,IAC/B;AAEA,QAAM,WAAW,QAAQ,UAAU;AACnC,QAAM,QAAQ,QAAQ,OAAO;AAE7B,QAAM,YAAY;AAGlB,aAAS,SAAS,CAAC,UACjB,OAAO,OAAO,SAAS,WAAW,CAAC,EAAE,QAAQ,OAAK,EAAE,SAAS,KAAK,CAAC;AAErE,QAAM,eAAe;AAAA,MACnB,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,IACf;AACA,QAAM,gBAAgB,CAAC,WACrB,aAAa,MAAM,IAAI,aAAa,MAAM,EAAE,MAAM,IAAI;AAGxD,QAAM,kBAAkB,SAAS;AACjC,aAAS,gBAAgB,CAAC,YAAY,OAAO,eAAe;AAC1D,YAAM,YAAY,gBAAgB,YAAY,OAAO,UAAU;AAE/D,UAAI,OAAO,UAAU,aAAa;AAEhC,cAAMC,WAAU,GAAG,UAAU,IAAI,UAAU;AAC3C,eAAO,IAAI,SAAS,UAAU,IAAIA,QAAO,KAAK,GAAG,IAAI;AAAA,MACvD;AAEA,YAAM,UAAU,GAAG,UAAU,IAAI,cAAc,UAAU,CAAC;AAC1D,aAAO,IAAI,SAAS;AAAA,QAClB,IAAI,MAAM,MAAM,oBAAI,KAAK,GAAG,YAAY,CAAC,CAAC,IAAI,OAAO;AAAA,QAAK,GAAG;AAAA,MAAI;AAAA,IACrE;AAMA,QAAMC,aAAY,SAAS;AAG3B,QAAMC,SAAQ,CAAC,QAAQ,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;AAGrD,QAAMC,aAAY,CAAC,QAAQ,KAAK,MAAM,KAAK,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AAI7D,QAAM,eAAe,CAAC,WAAW;AAC/B,UAAI;AACF,eAAO,KAAK,MAAM,MAAM;AAAA,MAC1B,SAAS,GAAG;AACV,eAAO;AAAA,MACT;AAAA,IACF;AAKA,QAAM,QAAQ,CAAC,QAAQ,YAAY,YAAY;AAC7C,UAAI,CAAC;AAAQ;AACb,cAAQ,MAAM;AACd,aAAO,UAAU,GAAG,QAAQ,WAAS,MAAM,OAAO,YAAY,OAAO,CAAC;AAAA,IACxE;AAGA,QAAM,gBAAgB,CAAC,QAAQ,MAAM,SAAS,SAAS,CAAC,MAAM;AAC5D,cAAQ,QAAQ,MAAM;AACtB,YAAM,OAAO,KAAK,CAAC;AACnB,UAAI,MAAM;AACR,cAAM,MAAM,OAAO,IAAI;AACvB,YAAI,KAAK;AACP,wBAAc,KAAK,KAAK,MAAM,CAAC,GAAG,SAAS,OAAO,OAAO,IAAI,CAAC;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AAGA,QAAM,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,YAAY;AAAE,iBAAW,SAAS,KAAK;AAAA,IAAG,CAAC;AAehF,QAAM,eAAe,CAAC,KAAK,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM;AACnD,MAAAJ,GAAE,QAAQ,KAAK,CAAC,OAAO,QAAQ;AAE7B,cAAM,YAAY,OAAO,OAAO,OAAO,GAAG,CAAC;AAI3C,aAAKA,GAAE,cAAc,KAAK,KAAK,iBAAiB,UAAU,UAAU,MAAM;AAExE,uBAAa,OAAO,WAAW,GAAG;AAAA,QACpC,OAAO;AAEL,cAAIK,aAAY,SAAS,CAAC,IAAI;AAAA,QAChC;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AAIA,QAAM,mBAAmB,CAAC,KAAK,MAAM,UAAU,YAAY,CAAC,GAAG,aAAa,CAAC,MAAM;AAEjF,UAAI,KAAK,UAAU,KAAK,KAAK,CAAC,KAAK,KAAK;AACtC,iBAAS,KAAK,WAAW,UAAU;AACnC;AAAA,MACF;AAEA,YAAM,OAAO,KAAK,CAAC;AACnB,UAAI,MAAM;AACR,iBAAS,OAAO,KAAK;AACnB,cAAI,OAAO,QAAQ,QAAQ,OAAO,KAAK,WAAW,GAAG,GAAG;AACtD,kBAAM,QAAQ,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,IAClD,OAAO,OAAO,CAAC,GAAG,YAAY,EAAC,CAAC,KAAK,MAAM,CAAC,CAAC,GAAG,IAAG,CAAC,IACpD;AACF;AAAA,cAAiB,IAAI,GAAG;AAAA,cAAG,KAAK,MAAM,CAAC;AAAA,cAAG;AAAA,cACxC,UAAU,OAAO,CAAC,GAAG,CAAC;AAAA,cAAG;AAAA,YAAK;AAAA,UAClC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAM,cAAc,CAAC,KAAK,MAAM,UAAU;AACxC,UAAI,KAAK,UAAU;AAAG,eAAO;AAC7B,YAAM,OAAO,KAAK,MAAM;AACxB,UAAI,KAAK,UAAU,GAAG;AACpB,YAAI,IAAI,IAAI;AAAA,MACd,OAAO;AACL,YAAI,CAAC,IAAI,IAAI;AAAG,cAAI,IAAI,IAAI,CAAC;AAC7B,oBAAY,IAAI,IAAI,GAAG,MAAM,KAAK;AAAA,MACpC;AAAA,IACF;AAEA,QAAM,qBAAqB,OAAK,EAAE,QAAQ,MAAM,KAAK,EAAE,QAAQ,OAAO,KAAK;AAC3E,QAAM,qBAAqB,OAAK,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,QAAQ,GAAG;AAG1E,QAAMA,eAAc,CAAC,cAAc;AAEjC,YAAM,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,MAAM;AACzD,aAAO,IAAI,UAAU,IAAI,eAAe,EAAE,IAAI,kBAAkB,EAAE,KAAK,GAAG,CAAC;AAAA,IAC7E;AAGA,QAAMC,eAAc,CAAC,UAAU;AAI7B,YAAM,OAAO,MAAM,MAAM,GAAG,EAAE,IAAI,kBAAkB;AAEpD,WAAK,SAAS,KAAK,KAAK,CAAC,EAAE,UAAU,KAAK,KAAK,MAAM;AAErD,WAAK,SAAS,KAAK,KAAK,GAAG,EAAE,EAAE,UAAU,KAAK,KAAK,IAAI;AACvD,aAAO;AAAA,IACT;AAKA,QAAM,aAAa,CAAC,UAAU,UAAU;AACtC,YAAM,UAAU,CAAC,GAAG,MAAM;AACxB,YAAI,EAAE,UAAU;AAAG,iBAAO;AAC1B,YAAI,EAAE,CAAC,EAAE,CAAC,KAAK;AAAK,iBAAO;AAE3B,YAAI,EAAE,UAAU;AAAG,iBAAO;AAE1B,YAAI,EAAE,CAAC,KAAK,EAAE,CAAC;AAAG,iBAAO,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAEvD,YAAI,EAAE,CAAC,EAAE,CAAC,KAAK,KAAK;AAClB,gBAAM,MAAM,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC1C,iBAAO,OAAO,OAAO,OAAO,EAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAC,GAAG,GAAG;AAAA,QAC1D;AAEA,eAAO;AAAA,MACT;AAEA,YAAM,gBAAgBA,aAAY,QAAQ;AAC1C,YAAM,YAAYA,aAAY,KAAK;AAGnC,aAAO,QAAQ,eAAe,SAAS;AAAA,IACzC;AAGA,QAAM,eAAe,CAAC,KAAK,WAAW;AACpC,YAAM,QAAQA,aAAY,MAAM;AAChC,YAAM,QAAQA,aAAY,GAAG;AAC7B,aAAO,WAAW,OAAO,KAAK,KAAK,MAAM,SAAS,MAAM;AAAA,IAC1D;AAGA,QAAM,aAAa,CAAC,aAAa,UAAU;AACzC,UAAI,YAAY,UAAU;AAAG,eAAO;AACpC,aAAQ,YAAY,CAAC,KAAK,MAAM,CAAC,KAC7B,WAAW,YAAY,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC;AAAA,IAErD;AAOA,QAAM,oBAAoB,CAAC,aAAa;AACtC,YAAM,QAAQ,SAAS,MAAM,GAAG;AAChC,aAAO;AAAA,QACL,cAAc,MAAM,CAAC;AAAA,QACrB,QAAQ,MAAM,CAAC;AAAA,QACf,KAAK,MAAM,MAAM,CAAC;AAAA,MACpB;AAAA,IACF;AAGA,QAAM,iBAAiB,CAAC,UAAU;AAChC,YAAM,QAAQA,aAAY,KAAK;AAC/B,aAAO;AAAA,QACL,cAAc,MAAM,CAAC;AAAA,QACrB,QAAQ,MAAM,CAAC;AAAA,QACf,iBAAiB,MAAM,CAAC;AAAA,QACxB,gBAAgB,MAAM,CAAC;AAAA,QACvB,YAAY,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AAAA,QACnC,SAAS,MAAM,CAAC;AAAA,QAChB,KAAK,MAAM,MAAM,CAAC;AAAA,MACpB;AAAA,IACF;AAEA,QAAM,mBAAmB,CAAC,YACxB,QAAQ,UAAU,IAAI,OAAO,KAAK,MAAM,QAAQ,SAAS,OAAO,CAAC;AAOnE,QAAM,oBAAoB,CAAC,YAAY,UAAU,UAAU,QAAQ,QAAS;AAE1E,YAAM,WAAW,CAAC;AAClB,YAAM,kBAAkB,CAAC,UAAU;AAEjC,iBAAS;AAAA,UAAQ;AAAA;AAAA,YAEf,WAAW,GAAG,MAAM,MAAM,KAAK,KAAK,SAAS,KAAK,KAAK;AAAA;AAAA,QACzD;AAAA,MACF;AACA,iBAAW,GAAG,WAAW,eAAe;AAGxC,eAAS,QAAQ,YAAU;AACzB,YAAI,OAAO,UAAU,UAAU;AAC7B,qBAAW,UAAU,GAAG,MAAM,IAAI;AAAA,QACpC,OAAO;AACL,kBAAQ,KAAK,YAAY,QAAQ,2BAA2B;AAAA,QAC9D;AAAA,MACF,CAAC;AAGD,YAAM,YAAa,OAAO,UAAU,cAAc,OAAO,MAAM,CAAC,IAAI;AAEpE,iBAAW,MAAM;AACb,mBAAW,eAAe,WAAW,eAAe;AACpD,iBAAS,QAAQ,YAAU,WAAW,YAAY,GAAG,MAAM,IAAI,CAAC;AAEhE,cAAM,QAAQ,SAAS;AACvB,gBAAQ,IAAI,YAAY,KAAK,2BAA2B,QAAQ,EAAE;AAClE,iBAAS,QAAQ,WAAS;AACxB,qBAAW,QAAQ,OAAO,WAAW,EAAC,QAAQ,KAAI,CAAC;AAAA,QACrD,CAAC;AAED,oBAAY,SAAS,KAAK;AAAA,MAC5B,GAAG,KAAK;AAAA,IACZ;AAkBA,QAAM,cAAc,CAAC,QAAQ,MAAM;AACjC,YAAM,SAAS,IAAI,WAAW,KAAK;AACnC,aAAO,gBAAgB,MAAM;AAC7B,aAAO,OAAO,OAAO,CAAC,MAAM,MAAM,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE;AAAA,IAC7D;AAGA,QAAM,WAAW,CAAC,QAAQ;AACxB,YAAM,aAAa;AACnB,YAAM,OAAO,CAAC;AACd,SAAG;AACD,aAAK,QAAQ,WAAW,MAAM,EAAE,CAAC;AACjC,cAAM,KAAK,MAAM,MAAM,EAAE;AAAA,MAC3B,SAAS,MAAM;AACf,aAAO,KAAK,KAAK,EAAE;AAAA,IACrB;AAGA,QAAM,gBAAgB,MAAM,SAAS,KAAK,IAAI,CAAC;AAQ/C,QAAM,iBAAiB,CAAC,GAAG,MACzB,cAAc,iBAAiB,CAAC,GAAG,iBAAiB,CAAC,CAAC;AAMxD,QAAMC,iBAAgB,CAAC,gBAAgB,WAAW,QAAW,UAAU,CAAC,MAAM;AAC5E,UAAI,CAAC,gBAAgB;AACnB,eAAO,WAAWP,GAAE,IAAI,CAAC,GAAG,UAAU,cAAc,IAAI;AAAA,MAC1D;AAEA,YAAM,WAAW,OAAO,KAAK,cAAc,EAAE,OAAO,UAC/C,CAAC,QAAQ,cAAc,eAAe,KAAK,QAAQ,UAAU,KAAK,OAChE,CAAC,QAAQ,cAAc,eAAe,QAAQ,YAAY,GAAG,KAAK,EAAE,EACtE,KAAK,cAAc;AAExB,YAAM,SAAS,CAAC;AAChB,YAAM,UAAU,YAAYM,aAAY,QAAQ;AAChD,eAAS,QAAQ,iBAAe;AAC9B,cAAM,WAAW,UAAUN,GAAE,IAAI,eAAe,WAAW,GAAG,OAAO,IACnE,eAAe,WAAW;AAE5B,QAAAA,GAAE,MAAM,QAAQ,QAAQ;AAAA,MAC1B,CAAC;AACD,aAAO,UAAUA,GAAE,IAAI,CAAC,GAAG,SAAS,MAAM,IAAI;AAAA,IAChD;AAKA,QAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,MAAM,IAAI;AAC1C,QAAM,cAAc,CAAC,UAAU;AAC7B,UAAI,CAAC;AAAO,eAAO;AACnB,UAAI,IAAI;AACR,aAAO,QAAQ,MAAM;AACnB,iBAAS;AACT;AAAA,MACF;AACA,aAAO,GAAG,MAAM,QAAQ,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AAAA,IACxC;AAEA,QAAM,iBAAiB,CAAC,YAAY;AAClC,UAAI,CAAC;AAAS,eAAO;AACrB,YAAM,QAAQ,CAAC;AACf,UAAI,UAAU,MAAM;AAClB,cAAM,IAAI,KAAK,MAAM,UAAU,IAAI;AACnC,kBAAU,UAAU;AAAA,MACtB;AACA,UAAI,UAAU,IAAI;AAChB,cAAM,IAAI,KAAK,MAAM,UAAU,EAAE;AACjC,kBAAU,UAAU;AAAA,MACtB;AACA,YAAM,IAAI,KAAK,MAAM,OAAO;AAE5B,UAAI,MAAM;AACV,YAAM,IAAI,MAAM,OAAO,GAAG,MAAM,CAAC;AACjC,YAAM,IAAI,MAAM,OAAO,GAAG,MAAM,CAAC;AACjC,OAAC,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAC9B,aAAO,IAAI,KAAK;AAAA,IAClB;AAIA,IAAAD,QAAO,UAAU;AAAA,MAAE;AAAA,MAAmB;AAAA,MACpC,aAAAM;AAAA,MAAa,aAAAC;AAAA,MAAa;AAAA,MAAc;AAAA,MACxC;AAAA,MAAkB;AAAA,MAAa;AAAA,MAAU;AAAA,MAAe;AAAA,MACxD;AAAA,MAAU,WAAAJ;AAAA,MACV,eAAAK;AAAA,MAAe;AAAA,MAAmB;AAAA,MAAc,OAAAJ;AAAA,MAAO;AAAA,MACvD;AAAA,MAAkB;AAAA,MAAoB;AAAA,MAAoB;AAAA,MAAW;AAAA,MACrE;AAAA,MAAM;AAAA,MAAa;AAAA,MAAgB;AAAA,MACnC,WAAAC;AAAA,MAAW;AAAA,IACb;AAAA;AAAA;;;AC9ZA;AAAA,oCAAAI,SAAA;AACA,QAAMC,KAAI;AAAA,MACR,KAAK,QAAQ,YAAY;AAAA,MACzB,KAAK,QAAQ,YAAY;AAAA,MACzB,OAAO,QAAQ,cAAc;AAAA,MAC7B,SAAS,QAAQ,gBAAgB;AAAA,MACjC,KAAK,QAAQ,YAAY;AAAA,MACzB,SAAS,QAAQ,gBAAgB;AAAA,MACjC,IAAI,QAAQ,gBAAgB;AAAA,MAC5B,eAAe,QAAQ,sBAAsB;AAAA,MAC7C,OAAO,QAAQ,cAAc;AAAA,IAC/B;AAEA,QAAM,EAAC,aAAAC,cAAa,aAAAC,cAAa,cAAc,YAAY,iBAAgB,IACvE;AAKJ,QAAM,QAAQ,CAAC,KAAK,SAAS;AAC3B,UAAI,CAAC,QAAQ,KAAK,UAAU;AAAG;AAC/B,MAAAF,GAAE,MAAM,KAAK,IAAI;AACjB,YAAM,aAAa,KAAK,MAAM,GAAG,EAAE;AAEnC,YAAM,SAAS,WAAW,UAAU,IAAI,MAAMA,GAAE,IAAI,KAAK,UAAU;AACnE,UAAIA,GAAE,QAAQ,MAAM,GAAG;AACrB,eAAO,MAAM,KAAK,UAAU;AAAA,MAC9B,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAIA,QAAM,eAAe,CAAC,KAAK,aAAa;AACtC,MAAAA,GAAE,QAAS,UAAU,CAAC,OAAO,UAAU;AACrC,cAAM,OAAOC,aAAY,KAAK;AAC9B,YAAI,SAAS,MAAM;AACjB,gBAAM,KAAK,IAAI;AAAA,QACjB,OAAO;AACL,UAAAD,GAAE,IAAI,KAAK,MAAM,KAAK;AAAA,QACxB;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AAUA,QAAM,mBAAmB,CAAC,KAAK,SAAS;AACtC,UAAI,KAAK,UAAU;AAAG;AACtB,YAAM,OAAO,KAAK,CAAC;AACnB,UAAI,MAAM;AACR,iBAAS,OAAO,KAAK;AACnB,cAAI,OAAO,QAAQ,QAAQ,OAAO,CAAC,KAAK,WAAW,GAAG,GAAG;AACvD,mBAAO,IAAI,GAAG;AAAA,UAChB,OAAO;AACL,6BAAiB,IAAI,GAAG,GAAG,KAAK,MAAM,CAAC,CAAC;AAAA,UAC1C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAqBA,QAAM,YAAN,MAAgB;AAAA,MAEd,QAAQ,CAAC;AAAA,MACT,aAAa,CAAC;AAAA,MACd,iBAAiB,CAAC;AAAA,MAElB,YAAY,OAAO,CAAC,GAAG;AACrB,aAAK,QAAQ;AAAA,MACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,gBAAgB,MAAM,OAAO,OAAO,CAAC,GAAG;AAEtC,cAAM,UAAUA,GAAE,IAAI,KAAK,OAAO,IAAI;AACtC,YAAI,SAAS,MAAM;AACjB,cAAI,YAAY,UAAa,YAAY,MAAM;AAC7C,mBAAO,CAAC;AAAA,UACV,OAAO;AACL,kBAAM,KAAK,OAAO,IAAI;AAAA,UACxB;AAAA,QACF,OAAO;AACL,cAAIA,GAAE,GAAG,SAAS,KAAK,GAAG;AAOxB,mBAAO,CAAC;AAAA,UACV;AAEA,UAAAA,GAAE,IAAI,KAAK,OAAO,MAAM,KAAK;AAAA,QAE/B;AAEA,cAAM,QAAQE,aAAY,IAAI;AAC9B,cAAM,MAAM,EAAC,CAAC,KAAK,GAAG,MAAK;AAG3B,YAAI;AACJ,YAAI,iBAAiB,QAAQ;AAC3B,gBAAM,YAAY,aAAa,KAAK;AACpC,wBAAc,CAAC;AACf,UAAAF,GAAE,QAAQ,WAAW,CAAC,QAAQ,YAAY;AACxC,wBAAY,GAAG,KAAK,GAAG,OAAO,EAAE,IAAI;AAAA,UACtC,CAAC;AAAA,QACH,OAAO;AACL,wBAAc;AAAA,QAChB;AAMA,aAAK,WAAW,QAAQ,QAAM,GAAG,KAAK,IAAI,CAAC;AAE3C,aAAK,eAAe,QAAQ,QAAM,GAAG,aAAa,IAAI,CAAC;AAEvD,eAAO;AAAA,MACT;AAAA;AAAA,MAGA,OAAO,MAAM,OAAO,MAAM;AACxB,YAAI,OAAO,QAAQ,UAAU;AAC3B,iBAAO,KAAK,gBAAgB,MAAM,OAAO,IAAI;AAAA,QAC/C,WAAW,gBAAgB,OAAO;AAChC,iBAAO,KAAK,gBAAgB,MAAM,OAAO,IAAI;AAAA,QAC/C,OAAO;AACL,gBAAM,IAAI,MAAM,8BAA8B;AAAA,QAChD;AAAA,MACF;AAAA;AAAA,MAGA,gBAAgB,OAAO,OAAO,MAAM;AAClC,eAAO,KAAK,gBAAgBC,aAAY,KAAK,GAAG,OAAO,IAAI;AAAA,MAC7D;AAAA;AAAA;AAAA,MAIA,mBAAmB,UAAU,MAAM;AACjC,eAAOD,GAAE,IAAI,UAAU,CAAC,OAAO,UAC7B,KAAK,gBAAgB,OAAO,OAAO,IAAI,CAAC;AAAA,MAC5C;AAAA;AAAA,MAGA,UAAU,UAAU;AAClB,YAAI,oBAAoB,UAAU;AAChC,eAAK,WAAW,KAAK,QAAQ;AAAA,QAC/B,OAAO;AACL,kBAAQ,KAAK,wFAAwF;AAAA,QACvG;AAAA,MACF;AAAA;AAAA;AAAA,MAIA,cAAc,OAAO,UAAU;AAC7B,aAAK,WAAW,KAAK,CAAC,SAAS,SAAS;AACtC,UAAAA,GAAE,QAAQ,SAAS,CAAC,OAAO,QAAQ;AACjC,kBAAM,UAAU,WAAW,OAAO,GAAG;AACrC,uBAAW,SAAS,OAAO,KAAK,SAAS,IAAI;AAAA,UAC/C,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA;AAAA,MAGA,kBAAkB,OAAO,UAAU;AACjC,aAAK,eAAe,KAAK,CAAC,SAAS,SAAS;AAC1C,UAAAA,GAAE,QAAQ,SAAS,CAAC,OAAO,QAAQ;AACjC,kBAAM,UAAU,WAAW,OAAO,GAAG;AACrC,uBAAW,SAAS,OAAO,KAAK,SAAS,IAAI;AAAA,UAC/C,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA;AAAA,MAGA,YAAY,UAAU;AACpB,aAAK,aAAa,KAAK,WAAW,OAAO,OAAK,KAAK,QAAQ;AAAA,MAC7D;AAAA;AAAA,MAGA,IAAI,OAAO,CAAC,GAAG;AACb,eAAO,KAAK,UAAU,IAAI,KAAK,QAAQA,GAAE,IAAI,KAAK,OAAO,IAAI;AAAA,MAC/D;AAAA;AAAA,MAGA,WAAW,OAAO;AAChB,eAAO,KAAK,IAAIC,aAAY,KAAK,CAAC;AAAA,MACpC;AAAA;AAAA,MAGA,OAAO,MAAM;AACX,cAAM,MAAM,KAAK,MAAM,KAAK,UAAU,KAAK,IAAI,CAAC,CAAC;AACjD,yBAAiB,KAAK,IAAI;AAC1B,eAAO;AAAA,MACT;AAAA;AAAA,MAGA,cAAc,OAAO;AACnB,eAAO,KAAK,OAAOA,aAAY,KAAK,CAAC;AAAA,MACvC;AAAA;AAAA;AAAA,MAIA,SAAS,OAAO,UAAU;AACxB,cAAM,OAAOA,aAAY,KAAK;AAC9B,aAAK,aAAa,MAAM,QAAQ;AAAA,MAClC;AAAA;AAAA;AAAA,MAIA,aAAa,MAAM,UAAU;AAC3B,yBAAiB,KAAK,IAAI,GAAG,MAAM,QAAQ;AAAA,MAC7C;AAAA,IACF;AAEA,IAAAF,QAAO,UAAU;AAAA,MACf;AAAA,MAAW;AAAA,IACb;AAAA;AAAA;;;ACxPA;AAAA,mCAAAI,SAAA;AAAA;AAEA,QAAMC,KAAI,QAAQ,QAAQ;AAE1B,QAAM;AAAA,MAAE;AAAA,MAAkB;AAAA,MAAY,aAAAC;AAAA,MAAa,aAAAC;AAAA,MACnD;AAAA,MAAc,WAAAC;AAAA,MAAW,eAAAC;AAAA,MAAe;AAAA,MAAgB;AAAA,MACxD;AAAA,MAAgB;AAAA,MAAoB;AAAA,MAAe;AAAA,IAAY,IAC3D;AACJ,QAAM,EAAE,UAAU,IAAI;AAGtB,QAAMC,OAAMF,WAAU,UAAU;AAChC,IAAAE,KAAI,SAAS,MAAM;AAEnB,QAAM,kBAAkB;AACxB,QAAM,aAAa;AAEnB,QAAM,OAAO,MAAM;AAAA,IAAC;AAGpB,QAAMC,SAAQ,CAAC,YAAY;AACzB,UAAI,OAAO,WAAW,UAAU;AAC9B,eAAO,KAAK,MAAM,KAAK,UAAU,OAAO,CAAC;AAAA,MAC3C,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAM,mBAAmB,CAAC,UACxB,MAAM,SAAS,IAAI,IAAI,QACrB,MAAM,SAAS,GAAG,IAAI,MAAM,OAAO,GAAG,IACtC,MAAM,OAAO,IAAI;AAGrB,QAAM,uBAAuB,CAAC,SAAS,KAAK,QAAQ,SAAS,GAAG;AAgChE,QAAMC,YAAN,MAAe;AAAA,MAEb,OAAO,IAAI,UAAU;AAAA;AAAA;AAAA;AAAA,MAKrB,kBAAkB,CAAC;AAAA,MAEnB,iBAAiB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUlB,oBAAoB,IAAI,UAAU;AAAA;AAAA;AAAA;AAAA,MAKlC,eAAe,oBAAI,IAAI;AAAA;AAAA;AAAA,MAIvB,iBAAiB,oBAAI,IAAI;AAAA;AAAA;AAAA,MAIzB,uBAAuB,CAAC;AAAA,MAExB,aAAa;AAAA,MAEb,wBAAwB,CAAC;AAAA,MAEzB,cAAc,CAAC;AAAA;AAAA,MACf,eAAe,CAAC;AAAA;AAAA,MAEhB,YAAY;AAAA,QAAC;AAAA,QAAY;AAAA,QAAU;AAAA,QAAc;AAAA,QAAS;AAAA,QACxD;AAAA,QAAY;AAAA,MAAmB,GAAG;AAElC,aAAK,OAAO;AACZ,aAAK,aAAa;AAElB,aAAK,KAAK,GAAG,WAAW,CAAC,OAAO,SAAS,WAAW;AAClD,gBAAM,gBAAgB,WAAW,QAAQ,SAAS;AAKlD,cAAI,SAAS,iBAAiB;AAC5B,gBAAI,KAAK,aAAa,GAAG;AACvB,mBAAK,qBAAqB,QAAQ,QAAM,GAAG,CAAC;AAC5C,mBAAK,uBAAuB,CAAC;AAAA,YAC/B;AACA,gBAAI,KAAK,cAAc,KAAK,CAAC,WAAW;AAAS,sBAAQ;AACzD,iBAAK;AAAA,UAEP,OAAO;AACL,iBAAK,eAAe,IAAI,KAAK;AAG7B,gBAAI,OAAON,aAAY,KAAK;AAC5B,YAAAI,KAAI,MAAM,sBAAsB,OAAO,IAAI;AAC3C,gBAAI,YAAY;AACd,qBAAO,KAAK,MAAM,UAAU;AAC5B,sBAAQH,aAAY,IAAI;AAAA,YAC1B;AAEA,gBAAI,KAAK,YAAY,KAAK,GAAG;AAC3B,oBAAM,OAAO,iBAAiB,OAAO;AACrC,mBAAK,iBAAiB,OAAO,IAAI;AAAA,YAEnC,WAAW,KAAK,aAAa,KAAK,GAAG;AACnC,oBAAM,OAAO,iBAAiB,OAAO;AACrC,mBAAK,kBAAkB,OAAO,IAAI;AAAA,YAEpC,WAAW,OAAO,UAAU,cAAc;AAExC,kBAAI,KAAK,YAAY,KAAK,GAAG;AAC3B,sBAAM,OAAO,iBAAiB,OAAO;AAKrC,qBAAK,kBAAkB,gBAAgB,CAAC,GAAG,MAAM,UAAU,GAAG,IAAI;AAOlE,qBAAK,KAAK,OAAO,OAAO,MAAM,EAAC,UAAU,KAAI,CAAC;AAAA,cAEhD,WAAW,KAAK,aAAa,KAAK,GAAG;AACnC,sBAAM,OAAO,iBAAiB,OAAO;AAErC,gBAAAG,KAAI,MAAM,4BAA4B,KAAK;AAC3C,sBAAM,UAAU,KAAK,KAAK,OAAO,OAAO,IAAI;AAC5C,4BAAY,OAAO,KAAK,OAAO,EAAE,SAAS,KAAK,SAAS,OAAO;AAAA,cACjE;AAAA,YACF;AAAA,UAGF;AAAA,QACF,CAAC;AAED,aAAK,KAAK,UAAU,iBAAiB,EAAC,KAAK,KAAI,GAAG,CAAC,KAAK,YAAY;AAClE,UAAAA,KAAI,MAAM,iBAAiB,EAAC,QAAO,CAAC;AACpC,qBAAW,QAAQ,SAAS,KAAK,qBAAqB;AAAA,QACxD,CAAC;AAED,iBAAS,SAAS,KAAK,KAAK,QAAQ,SAAS,MAAM;AACjD,UAAAA,KAAI,MAAM,gBAAgB;AAC1B,qBAAW,KAAK,qBAAqB,OAAO;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,eAAe,OAAO,OAAO,OAAO;AAClC,QAAAA,KAAI,MAAM,qBAAqB,KAAK,IAAI,OAAO,KAAK;AAEpD,YAAI,QAAQ,GAAG;AACb,UAAAL,GAAE,QAAQ,OAAO,CAAC,UAAU,WAAW;AACrC,kBAAM,WAAW,GAAG,KAAK,IAAI,mBAAmB,MAAM,CAAC;AACvD,YAAAK,KAAI,MAAM,cAAc,QAAQ,EAAE;AAClC,iBAAK,eAAe,UAAU,UAAU,QAAQ,CAAC;AAAA,UACnD,CAAC;AAAA,QACH,OAAO;AACL,eAAK,KAAK,QAAQ,OAAO,KAAK,UAAU,KAAK,GAAG,EAAC,QAAQ,KAAI,GAAG,CAAC,QAAQ;AACvE,mBAAOA,KAAI,KAAK,0CAA0C,GAAG;AAAA,UAC/D,CAAC;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYA,QAAQ,MAAM,UAAU,QAAW;AAEjC,YAAI,OAAO,KAAK;AAChB,YAAI,QAAQ,GAAG;AACb,qBAAW,QAAQ;AACnB;AAAA,QACF;AAGA,cAAM,UAAU,MAAM,EAAE,QAAQ,KAAK,WAAW,QAAQ;AAExD,aAAK,QAAQ,CAAC;AAAA,UAAC;AAAA,UAAO;AAAA,UAAY,YAAY;AAAA,UAAW,OAAO;AAAA,UAC9D,QAAQ;AAAA,QAAC,MAAM;AACb,UAAAA,KAAI,MAAM,aAAa,OAAO,UAAU;AACxC,gBAAM,EAAC,cAAc,QAAQ,YAAY,IAAG,IAAI,eAAe,KAAK;AACpE,gBAAM,SAAS,IAAI,YAAY,IAAI,MAAM,IAAI,UAAU;AAEvD,gBAAM,SAAS,IAAI,UAAU,IAAI,OAAOH,aAAY,GAAG;AAEvD,gBAAM,WAAW,GAAG,MAAM,KAAK,MAAM;AAErC,eAAK,UAAU,UAAU,CAAC,QAAQ;AAChC,gBAAI,KAAK;AACP,cAAAG,KAAI,KAAK,0BAA0B,GAAG;AACtC,sBAAQ;AACR;AAAA,YACF;AAEA,kBAAM,MAAM,CAAC;AACb,iBAAK,qBAAqB,MAAM;AAG9B,mBAAK,KAAK,SAAS,QAAQ,CAAC,OAAO,MAAM,UAAU;AAEjD,sBAAM,eAAeH,aAAY,IAAI;AAErC,gBAAAG,KAAI,MAAM,iBAAiB,EAAC,QAAQ,OAAO,UAAU,OAAM,GAAG,cAAc,KAAK;AACjF,oBAAI,CAAC,OAAO;AAEV;AAAA,gBACF;AAEA,uBAAO,OAAO,KAAK,KAAK;AAExB,sBAAM,SAASD,eAAc,OAAO,QAAQ,EAAC,YAAY,WAAU,CAAC;AAEpE,sBAAM,oBAAoBJ,GAAE,IAAI,QAAQC,aAAY,MAAM,CAAC;AAC3D,gBAAAI,KAAI,MAAM,EAAC,OAAO,QAAQ,QAAQ,kBAAiB,CAAC;AAEpD,sBAAM,cAAc,YAAY,UAAU,iBAAiB,IACzD;AAIF,sBAAM,WACJ,qBAAqB,GAAG,YAAY,IAAI,UAAU,IAAI,MAAM,EAAE;AAChE,gBAAAA,KAAI,MAAM,qBAAqB,QAAQ;AAEvC,oBAAI,MAAM;AACR,wBAAM,UAAU,aAAa,WAAW;AACxC,wBAAM,UAAUJ,aAAY,QAAQ;AACpC,kBAAAD,GAAE,QAAQ,SAAS,CAACQ,QAAO,QAAQ;AACjC,0BAAM,WAAWN,aAAY,QAAQ,OAAOD,aAAY,GAAG,CAAC,CAAC;AAE7D,yBAAK,KAAK;AAAA,sBAAQ;AAAA,sBAAU,KAAK,UAAUO,MAAK;AAAA,sBAC9C,EAAC,QAAQ,KAAI;AAAA,sBAAG,CAACC,SAAQ;AACvB,wBAAAA,QAAOJ,KAAI;AAAA,0BACT,8CAA8C,GAAG;AAAA,0BAAII;AAAA,wBAAG;AAAA,sBAC5D;AAAA,oBAAC;AAAA,kBACL,CAAC;AAAA,gBAEH,OAAO;AACL,uBAAK,eAAe,UAAU,aAAa,KAAK;AAAA,gBAClD;AAAA,cACF,CAAC;AAED,mBAAK,YAAY,QAAQ;AAEzB,kBAAI,OAAO,KAAK,GAAG,EAAE,UAAU,GAAG;AAEhC,wBAAQ;AACR;AAAA,cACF;AAEA,mBAAK,qBAAqB,MAAM;AAE9B,sBAAM,cAAc,OAAO,KAAK,GAAG,EAAE,OAAO,OAC1C,eAAe,GAAG,UAAU,IAAI,CAAC;AAGnC,sBAAM,kBAAkB,YAAY,IAAI,UACtC,qBAAqB,GAAG,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;AAErD,qBAAK,MAAM,eAAe;AAC1B,wBAAQ;AAAA,cACV,CAAC;AAAA,YACH,CAAC;AAAA,UACH,CAAC;AAAA,QACH,CAAC;AAAA,MACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeA,MAAM,UAAU,WAAW,QAAW,UAAU,CAAC,GAAG;AAElD,cAAM,WAAW,CAAC;AAClB,cAAM,kBAAkB,CAAC,UAAU;AAEjC,mBAAS;AAAA,YAAQ,YACf,WAAW,GAAG,MAAM,MAAM,KAAK,MACzB,CAAC,QAAQ,UAAU,QAAQ,OAAO,KAAK,MACxC,SAAS,KAAK,KAAK;AAAA,UAC1B;AAAA,QACF;AACA,aAAK,KAAK,GAAG,WAAW,eAAe;AAIvC,iBAAS,QAAQ,YAAU;AACzB,cAAI,OAAO,UAAU,UAAU;AAC7B,iBAAK,KAAK,UAAU,GAAG,MAAM,IAAI;AAAA,UACnC,OAAO;AACL,YAAAJ,KAAI,KAAK,YAAY,QAAQ,2BAA2B;AAAA,UAC1D;AAEA,eAAK,eAAe,QAAQ,WAAS;AACnC,gBAAI,MAAM,WAAW,MAAM,GAAG;AAC5B,cAAAA,KAAI,MAAM,wBAAwB,GAAG,MAAM,GAAG,KAAK,EAAE;AACrD,uBAAS,KAAK,KAAK;AAAA,YACrB;AAAA,UACF,CAAC;AAAA,QACH,CAAC;AAGD,cAAM,YAAa,OAAO,UAAU,cAAc,OAAO,MAAM,CAAC,IAAI;AAEpE,aAAK,qBAAqB,MAAM;AAC9B,eAAK,KAAK,eAAe,WAAW,eAAe;AACnD,mBAAS,QAAQ,YAAU,KAAK,KAAK,YAAY,MAAM,CAAC;AAExD,gBAAM,QAAQ,SAAS;AACvB,UAAAA,KAAI,KAAK,YAAY,KAAK,2BAA2B,QAAQ,EAAE;AAC/D,mBAAS,QAAQ,WAAS;AACxB,iBAAK,KAAK,QAAQ,OAAO,WAAW,EAAC,QAAQ,KAAI,CAAC;AAAA,UACpD,CAAC;AAED,sBAAY,SAAS,KAAK;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA;AAAA,MAIA,qBAAqB,UAAU;AAG7B,mBAAW,MAAM,KAAK,qBAAqB,KAAK,QAAQ,GAAG,CAAC;AAAA,MAC9D;AAAA;AAAA,MAGA,aAAa,OAAO;AAClB,eAAO,OAAO,KAAK,KAAK,eAAe,EAAE,KAAK,qBAC5C,WAAW,iBAAiB,KAAK,CAAC;AAAA,MACtC;AAAA;AAAA;AAAA,MAIA,YAAY,OAAO;AACjB,eAAO,OAAO,KAAK,KAAK,cAAc,EAAE;AAAA,UAAK,qBAC3C,WAAW,iBAAiB,KAAK,KACjC,CAAC,KAAK,eAAe,eAAe,EAAE;AAAA,QACxC;AAAA,MACF;AAAA;AAAA;AAAA,MAIA,UAAU,OAAO,WAAW,MAAM;AAChC,gBAAQ,iBAAiB,KAAK;AAC9B,QAAAA,KAAI,MAAM,kBAAkB,KAAK;AACjC,YAAI,KAAK,gBAAgB,KAAK,GAAG;AAC/B,UAAAA,KAAI,MAAM,yBAAyB,KAAK;AACxC,mBAAS;AACT;AAAA,QACF;AAEA,aAAK,KAAK,UAAU,OAAO,EAAC,KAAK,KAAI,GAAG,CAAC,KAAK,YAAY;AACxD,UAAAA,KAAI,MAAM,aAAa,OAAO,YAAY,OAAO;AACjD,cAAI,WAAW,QAAQ,KAAK,WAAS,MAAM,SAAS,SAAS,MAAM,MAAM,GAAG,GAAG;AAE7E,iBAAK,gBAAgB,KAAK,IAAI;AAC9B,qBAAS,IAAI;AAAA,UACf,OAAO;AAEL,qBAAS,uCAAuC,KAAK,KAAK,KAAK,UAAU,OAAO,CAAC,EAAE;AAAA,UACrF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA,YAAY,OAAO;AACjB,gBAAQ,iBAAiB,KAAK;AAC9B,YAAI,KAAK,gBAAgB,KAAK,GAAG;AAC/B,eAAK,KAAK,YAAY,KAAK;AAC3B,iBAAO,KAAK,gBAAgB,KAAK;AAAA,QACnC;AAAA,MACF;AAAA;AAAA,MAGA,iBAAiB,OAAO,OAAO;AAmB7B,YAAI,CAAC,KAAK,KAAK,WAAW;AACxB,UAAAA,KAAI,KAAK,iCAAiC,KAAK;AAC/C,iBAAO;AAAA,QACT;AACA,QAAAA,KAAI,MAAM,uBAAuB,KAAK;AACtC,aAAK,KAAK;AAAA,UAAQ;AAAA,UAChB,SAAS,OAAO,OAAO,KAAK,UAAU,KAAK;AAAA;AAAA,UAC3C,EAAC,QAAQ,KAAI;AAAA,QAAC;AAChB,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,kBAAkB,IAAI;AACpB,YAAI,KAAK,aAAa,OAAO,GAAG;AAC9B,gBAAM,CAAC,OAAO,KAAK,IAAI,KAAK,aAAa,QAAQ,EAAE,KAAK,EAAE;AAK1D,cAAI,KAAK,iBAAiB,OAAO,KAAK,GAAG;AACvC,iBAAK,aAAa,OAAO,KAAK;AAC9B,iBAAK,kBAAkB,EAAE;AAAA,UAC3B,OAAO;AAEL,uBAAW,MAAM,KAAK,kBAAkB,EAAE,GAAG,GAAI;AAAA,UACnD;AAAA,QACF,OAAO;AACL,aAAG;AAAA,QACL;AAAA,MACF;AAAA,MAEA,gBAAgB;AACd,YAAI,KAAK;AAAa;AAEtB,aAAK,cAAc;AACnB,aAAK,kBAAkB,MAAM,KAAK,cAAc,KAAK;AAAA,MACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,YAAY,OAAO;AACjB,aAAK,yBACHL,GAAE,SAAS,KAAK,cAAc,KAAK,IAAI,GAAG,KAAK;AAAA,MACnD;AAAA;AAAA,MAGA,gBAAgB;AACd,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,WAAW,OAAO,OAAO;AAEvB,aAAK,aAAa,IAAI,OAAO,KAAK;AAAA,MACpC;AAAA;AAAA,MAGA,SAAS,OAAO,OAAO;AACrB,QAAAK,KAAI,MAAM,aAAa,KAAK;AAC5B,aAAK,WAAW,OAAO,KAAK;AAC5B,YAAI,KAAK,wBAAwB;AAC/B,eAAK,uBAAuB;AAAA,QAC9B,OAAO;AACL,eAAK,cAAc;AAAA,QACrB;AAGA,cAAM,OAAOJ,aAAY,KAAK;AAC9B,aAAK,kBAAkB;AAAA,UAAgB,CAAC,GAAG,MAAM,UAAU;AAAA,UACzD,SAAS,OAAO,OAAOK,OAAM,KAAK;AAAA,QAAC;AAAA,MACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,QAAQ,OAAO,UAAU,EAAC,QAAQ,MAAK,GAAG;AACxC,gBAAQ,iBAAiB,KAAK;AAE9B,YAAIN,GAAE,QAAQ,KAAK,eAAe,KAAK,GAAG,OAAO,GAAG;AAClD,iBAAO;AAAA,QAET;AACA,aAAK,eAAe,KAAK,IAAI;AAE7B,YAAI,QAAQ,QAAQ;AAElB,eAAK,KAAK,cAAc,OAAO,CAAC,OAAO,KAAK,SAAS,SAAS;AAE5D,gBAAI,MAAM;AAAU;AAEpB,YAAAK,KAAI,MAAM,8BAA8B,KAAK,KAAK;AAElD,kBAAM,mBAAmB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;AACxD,kBAAM,gBAAgBH;AAAA;AAAA;AAAA,cAGpBD,aAAY,GAAG,EAAE,MAAM,GAAGA,aAAY,gBAAgB,EAAE,MAAM;AAAA,YAChE;AACA,iBAAK,SAAS,eAAe,KAAK,KAAK,WAAW,aAAa,CAAC;AAAA,UAClE,CAAC;AACD,iBAAO;AAAA,QACT;AAEA,aAAK,KAAK,UAAU,KAAK;AAGzB,aAAK,KAAK,cAAc,OAAO,CAAC,OAAO,KAAK,SAAS,SAAS;AAC5D,cAAI,MAAM;AAAU;AAEpB,UAAAI,KAAI,MAAM,qBAAqB,GAAG;AAOlC,gBAAM,OAAOJ,aAAY,GAAG;AAG5B,gBAAM,eAAe,KAAK,kBAAkB,IAAI,IAAI;AACpD,UAAAD,GAAE,KAAK,cAAc,CAAC,WAAW,cAAc;AAC7C,gBAAI,aAAa;AAAY,qBAAO;AAKpC,kBAAM,UAAU,OAAO,KAAK,aAAa,SAAS,CAAC,EAC9C,OAAO,YAAU,OAAO,SAAS,UAAU,CAAC;AAEjD,YAAAK,KAAI,MAAM,kBAAkB,EAAC,QAAO,GAAG,SAAS;AAEhD,oBAAQ,QAAQ,kBAAgB;AAC9B,oBAAM,SAAS,aAAa,MAAM,GAAG,EAAE,WAAW,SAAS,EAAE;AAC7D,oBAAM,WAAW,GAAG,GAAG,IAAI,SAAS,IAAI,MAAM;AAE9C,mBAAK,SAAS,UAAU,IAAI;AAAA,YAC9B,CAAC;AAAA,UACH,CAAC;AAGD,gBAAM,YAAY,KAAK,kBAAkB,IAAI;AAC7C,wBAAc,WAAW,KAAK,MAAM,GAAG,EAAE,GAAG,CAAC,QAAQ,WAAW;AAC9D,kBAAM,SAAS,OAAO,UAAU;AAChC,gBAAI,UAAUL,GAAE,SAAS,MAAM,GAAG;AAChC,cAAAK,KAAI,MAAM,gBAAgB,EAAC,OAAM,CAAC;AAMlC,oBAAM,cAAcH,aAAY,MAAM;AACtC,mBAAK,SAAS,aAAa,IAAI;AAG/B,oBAAM,OAAO,aAAa,MAAM;AAChC,cAAAF,GAAE,KAAK,MAAM,CAAC,WAAW,YAAY;AACnC,sBAAM,aAAa,GAAG,WAAW,GAAG,OAAO;AAC3C,qBAAK,SAAS,YAAY,SAAS;AAAA,cACrC,CAAC;AAAA,YACH;AAAA,UACF,CAAC;AAQD,eAAK,SAAS,KAAK,KAAK;AACxB,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA;AAAA,MAGA,mBAAmB;AACjB,aAAK,sBAAsB,QAAQ,QAAM,GAAG,IAAI,CAAC;AAAA,MACnD;AAAA;AAAA,MAGA,mBAAmB,IAAI;AACrB,aAAK,sBAAsB,KAAK,EAAE;AAAA,MACpC;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,MAAM,iBAAiB,OAAO,MAAM;AAClC,QAAAK,KAAI,MAAM,4BAA4B,OAAO,IAAI;AACjD,cAAM,UAAU,KAAK,YAAY,KAAK;AACtC,cAAM,SAAS,QAAQ,KAAK,IAAI;AAEhC,cAAM,gBAAgB,GAAG,MAAM,QAAQ,YAAY,WAAW,CAAC,IAAI,KAAK,EAAE;AAE1E,YAAI,kBAAkB,SAAS;AAC7B,iBAAO,KAAM,iBAAe,KAAK,KAAK;AAAA,YAAQ;AAAA,YAC5C,KAAK,UAAU,EAAE,IAAI,KAAK,IAAI,QAAQ,YAAY,CAAC;AAAA,YACnD,EAAC,QAAQ,OAAO,KAAK,EAAC;AAAA,UAAC,CAAC;AAAA,QAC5B,OAAO;AACL,eAAK,KAAK;AAAA,YAAQ;AAAA,YAChB,KAAK,UAAU,EAAE,IAAI,KAAK,IAAI,OAAO,CAAC;AAAA,YACtC,EAAC,QAAQ,OAAO,KAAK,EAAC;AAAA,UAAC;AAAA,QAC3B;AAAA,MACF;AAAA;AAAA,MAGA,kBAAkB,OAAO,MAAM;AAC7B,QAAAA,KAAI,MAAM,uBAAuB,OAAO,IAAI;AAC5C,aAAK,aAAa,KAAK,EAAE,KAAK,MAAM;AACpC,eAAO,KAAK,aAAa,KAAK;AAC9B,aAAK,KAAK,YAAY,KAAK;AAAA,MAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAqBA,SAAS,SAAS,SAAS;AACzB,QAAAA,KAAI,MAAM,+BAA+B,OAAO;AAChD,cAAM,eAAe,GAAG,OAAO;AAE/B,aAAK,YAAY,YAAY,IAAI;AACjC,aAAK,KAAK,UAAU,cAAc,EAAC,KAAK,MAAM,KAAK,EAAC,GAAG,CAAC,KAAK,YAAY;AACvE,cAAI,KAAK;AACP,YAAAA,KAAI,KAAK,kCAAkC,YAAY,IAAI,GAAG;AAAA,UAChE,WAAW,WAAW,QAAQ,UAAU,GAAG;AACzC,YAAAA,KAAI,KAAK,yCAAyC,YAAY,EAAE;AAAA,UAClE;AAAA,QACF,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,KAAK,SAAS,MAAM,WAAW,QAAW;AACxC,cAAM,KAAK,YAAY;AAEvB,cAAM,gBAAgB,GAAG,OAAO,aAAa,EAAE;AAC/C,aAAK,KAAK,UAAU,eAAe,EAAC,KAAK,MAAM,KAAK,EAAC,GAAG,CAAC,KAAK,YAAY;AACxE,cAAI,KAAK;AACP,YAAAA,KAAI,KAAK,2CAA2C,aAAa,IAAI,GAAG;AAAA,UAC1E,WAAW,WAAW,QAAQ,UAAU,GAAG;AACzC,YAAAA,KAAI,KAAK,kDAAkD,aAAa,EAAE;AAAA,UAC5E;AAAA,QACF,CAAC;AAED,cAAM,eAAe,GAAG,OAAO;AAC/B,QAAAA,KAAI,MAAM,eAAe,YAAY;AACrC,aAAK,KAAK;AAAA,UAAQ;AAAA,UAAc,KAAK,UAAU,EAAE,IAAI,KAAK,CAAC;AAAA,UACzD,EAAC,QAAQ,OAAO,KAAK,EAAC;AAAA,QAAC;AAEzB,YAAI,UAAU;AACZ,eAAK,aAAa,aAAa,IAAI;AAAA,QACrC,OAAO;AACL,iBAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,iBAAK,aAAa,aAAa,IAAI;AAAA,UACrC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,IAAAN,QAAO,UAAUQ;AAAA;AAAA;;;AChwBjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAG,gBAA4D;AAC5D,6BACO;AACP,iCAA8B;;;ACH9B;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,2BAAc;AACd,2BAAc;AACd,sBAAe;AACR,IAAM,WAAW,gBAAAC;AAMjB,IAAM,cAAc,SACzB,IAAI,MAAM,GAAG,EACV,IAAI,OAAK,EAAE,MAAM,GAAG,CAAC,EACrB,OAAO,CAAC,KAAK,MAAM;AAClB,MAAI,mBAAmB,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,IACjC,EAAE,CAAC,KAAK,mBAAmB,EAAE,CAAC,EAAE,KAAK,CAAC;AACxC,SAAO;AACT,GAAG,CAAC,CAAC;AAGF,IAAM,YAAY,CAAC,KAAK,UAAU,UAAU,CAAC,MAAM;AACxD,QAAM,KAAK;AAAA,IACT,QAAQ,QAAQ,WAAW,QAAQ,OAAO,SAAS;AAAA,IACnD,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAAA,IAGP,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,GAAG,QAAQ;AAAA,IACb;AAAA,IACA,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,MAAM,QAAQ,OAAO,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,EACtD,CAAC,EAAE,KAAK,SAAO;AACX,UAAM,QAAQ,CAAC,IAAI,MACjB,YAAY,GAAG,YAAY,IAAI,MAAM,IAAI,IAAI,UAAU;AACzD,QAAI,KAAK,EACN,KAAK,UAAQ,SAAS,OAAO,IAAI,CAAC,EAClC,MAAM,SAAO;AACZ,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB,CAAC;AAAA,EACL,CAAC,EAAE,MAAM,CAAC,UAAU,SAAS,UAAU,KAAK,EAAE,CAAC;AACnD;;;AC3CA,mBAAoD;AACpD,oBAAc;AAEd,kBAAiB;AAIjB,IAAMC,YAAW;AAEjB,IAAM,UAAM,0BAAU,iBAAiB;AACvC,IAAI,SAAS,MAAM;AAEnB,IAAM,2BAA2B;AACjC,IAAM,uBAAuB;AAWtB,IAAM,cAAc,CAAC,EAAC,KAAK,IAAI,SAAS,SAAQ,MAAM;AAC3D,QAAM,EAAE,UAAAC,WAAU,QAAAC,SAAQ,WAAAC,WAAU,IAAI,YAAY,aAAAC;AAEpD,QAAM,CAAC,QAAQ,SAAS,IAAIH,UAAS,YAAY;AACjD,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS;AACzC,QAAM,CAAC,MAAM,OAAO,IAAIA,UAAS,CAAC,CAAC;AAEnC,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAS,KAAK;AAE9D,EAAAE,WAAU,MAAM;AACZ,UAAM,cAAU,0BAAU,GAAG;AAG7B,UAAM,EAAE,UAAU,IAAI,IAAI;AAC1B,QAAI,CAAC,YAAY,CAAC,QAAQ,MAAM,YAAY,MAAM,KAAK,IAAI,GAAG;AAC5D,YAAM,QAAQ;AACd,UAAI,KAAK,OAAO,OAAO;AACvB,gBAAU,UAAU,KAAK,EAAE;AAC3B;AAAA,IACF;AAGA,QAAI,kBAAkB;AACtB,UAAM,iBAAiB,CAAC,KAAK,SAASE,YAAW;AAC/C,cAAQ,kBAAkB;AAC1B,UAAI,KAAK,gBAAgB,QAAQ,eAAe,IAAI;AACpD,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,yBAAyB;AACnC,UAAM,SAAS,YAAAC,QAAK,QAAQ,SAAS;AAAA,MACnC,UAAU,KAAK,UAAU,EAAC,IAAI,QAAO,CAAC;AAAA,MACtC,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAID,WAAO;AAAA,MAAG;AAAA,MAAS,MACjB,kBAAkB,KAAK,IAAI,kBAAkB,GAAG,oBAAoB;AAAA,IACtE;AAGA,WAAO,GAAG,WAAW,MAAM,kBAAkB,wBAAwB;AAErE,WAAO,KAAK,WAAW,MAAM;AAC3B,UAAI,MAAM,gBAAgB;AAE1B,YAAM,iBAAiB,IAAIN,UAAS;AAAA,QAClC,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,oBAAoB,MAAM,oBAAoB,IAAI;AAAA,MACpD,CAAC;AACD,kBAAY,cAAc;AAC1B,gBAAU,WAAW;AAGrB,qBAAe,KAAK,UAAU,cAAAO,QAAE,SAAS,MACvC,YAAQ,sBAAM,eAAe,KAAK,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;AAAA,IAClD,CAAC;AAED,WAAO,GAAG,SAAS,CAAC,UAAU;AAC5B,UAAI,MAAM,KAAK;AACf,gBAAU,UAAU,KAAK,EAAE;AAAA,IAC7B,CAAC;AAED,WAAO,MAAM;AACX,UAAI,KAAK,yBAAyB;AAClC,UAAI,YAAY,SAAS,kBAAkB;AACzC,iBAAS,iBAAiB;AAC1B,iBAAS,qBAAqB,MAAM,OAAO,IAAI,CAAC;AAAA,MAClD,OAAO;AACL,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,KAAK,EAAE,CAAC;AAEd,SAAO;AAAA,IACL;AAAA;AAAA,IAEA,OAAO;AAAA,IACP,iBAAiB,MAAM,6BAAAH,QAAA,cAAC,aAAK,MAAO;AAAA,IACpC;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACF;AAIO,IAAM,gBACX,CAAC;AAAA,EAAC;AAAA,EAAK;AAAA,EAAI;AAAA,EAAY;AAAA,EAAW;AAAA,EAChC,OAAO;AAAA,EAA0B,MAAM;AAAK,MAAM;AAElD,QAAM,CAAC,OAAO,cAAc,IAAI,WAAW,MAAM,GAAG;AAEpD,QAAM,EAAE,OAAO,QAAI,0BAAU,GAAG;AAChC,QAAM,aAAa,CAAC,IAAI,QAAQ,OAAO,cAAc;AACrD,QAAM,aAAS,4BAAY,UAAU;AACrC,QAAM,oBAAoB,CAAC,GAAG,YAAY,SAAS;AACnD,QAAM,oBAAgB,4BAAY,iBAAiB;AAEnD,QAAM,UAAU,GAAG,OAAO,KAAK,MAAM,GAAG,IAAI,QAAQ,IAAI,WAAW,IAAI;AACvE,QAAM,eAAe,YAAY,EAAE,KAAK,IAAI,SAAS,SAAS,CAAC;AAE/D,SAAO;AAAA,IAAC,GAAG;AAAA,IAAc;AAAA,IAAQ;AAAA,IAAY;AAAA,IAAQ;AAAA,IACnD;AAAA,EAAa;AACjB;AAyBK,IAAM,YAAY,CAAC;AAAA,EAAC;AAAA,EAAK,OAAO;AAAA,EAA0B,MAAM;AAAA,EACnE,SAAS,CAAC;AAAA,EAAG;AAAQ,MAAM;AAE3B,QAAM,EAAE,UAAAH,WAAU,WAAAE,WAAU,IAAI,YAAY,aAAAC;AAI5C,QAAM,CAAC,WAAW,YAAY,IAAIH,UAAS;AAC3C,GAAC,cAAAM,QAAE,QAAQ,WAAW,MAAM,KAAK,aAAa,MAAM;AAEpD,QAAM,EAAC,QAAQ,IAAI,WAAU,QAAI,0BAAU,GAAG;AAC9C,MAAI,UAAU,UAAU;AACtB,QAAI,KAAK,uDAAuD;AAChE;AAAA,EACF;AAEA,QAAM,cAAc,IAAI,EAAE,IAAI,MAAM;AAEpC,QAAM,EAAC,UAAU,MAAM,QAAQ,OAAO,gBAAe,IACnD,YAAY,EAAC,KAAK,IAAI,SAAS,KAAK,MAAM,MAAM,EAAE,WAAW,IAAI,IAAI,SAAQ,CAAC;AAEhF,EAAAJ,WAAU,MAAM;AACZ,QAAI,OAAO;AACT,eAAS,UAAU,aAAa,CAAC,QAAQ,OAAO,QAAQ,KAAK,GAAG,CAAC;AAAA,IACnE;AAAA,EACF,GAAG,CAAC,UAAU,KAAK,CAAC;AAEtB,QAAM,kBAAc;AAAA,IAClB,KAAK,EAAE,IAAI,MAAM,EAAE,sBAAsB,EAAE,cAAc;AAAA,IAAG;AAAA,EAAQ,EAAE;AACxE,QAAM,kBAAkB,aAAa;AAErC,QAAM,CAAC,OAAO,OAAO,IAAI,WAAW,MAAM,GAAG;AAC7C,QAAM,WAAW,kBAAkB,KAAK,IAAI,OAAO;AACnD,QAAM,iBAAiB,YAAY,OAAO,OAAO,QAAQ,EAAE,OAAO,OAAO,EAAE,CAAC;AAC5E,QAAM,SAAS,IAAI,EAAE,IAAI,MAAM,IAAI,UAAU,IAAI,cAAc;AAE/D,EAAAA,WAAU,MAAM;AACZ,QAAI,MAAM,UAAU,MAAM;AAC1B,QAAI,gBAAgB;AAClB,aAAO,QAAQ,WAAS;AACtB,YAAI,MAAM,kBAAkB,MAAM,GAAG,KAAK,EAAE;AAC5C,iBAAS;AAAA,UAAU,GAAG,MAAM,GAAG,KAAK;AAAA,UAClC,CAAC,QAAQ,OAAO,IAAI,KAAK,GAAG;AAAA,QAAC;AAAA,MACjC,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,WAAW,gBAAgB,QAAQ,CAAC;AAE1C,QAAM,YAAY,cAAAI,QAAE,IAAI,UAAM,4BAAY,MAAM,CAAC;AAGjD,SAAO,EAAC,MAAM,OAAO,EAAE,IAAI,MAAM,GAAG,UAAU,aAAa,UAAS;AACtE;AAGF,IAAM,YAAY,CAAC;AACnB,IAAM,gBAAgB,CAAC;AAahB,IAAM,gBAAgB,CAAC;AAAA,EAAE;AAAA,EAAY;AAAA,EAAM;AAAA,EAAQ;AAAA,EACtD,OAAO;AAAA,EAA0B,MAAM;AAAA,EAAM;AAC/C,MAAM;AACJ,QAAM,EAAE,UAAAN,WAAU,WAAAE,WAAU,IAAI,YAAY,aAAAC;AAE5C,QAAM,CAAC,SAAS,UAAU,IAAIH,UAAS,EAAE,QAAQ,MAAM,CAAC;AAGxD,QAAM,OAAO,CAAC,SAAS,cAAc;AACnC,QAAI,MAAM,oBAAoB,IAAI,KAAK,OAAO,EAAE;AAChD,kBAAc,IAAI,IAAI;AACtB,eAAW,QAAM,EAAC,GAAG,GAAG,cAAc,WAAW,QAAQ,CAAC,CAAC,UAAS,EAAE;AAAA,EACxE;AAGA,QAAM,kBAAkB,IAAI,SAAS,UAAU,IAAI,EAAE,QAAQ,OAAK,EAAE,GAAG,IAAI,CAAC;AAE5E,EAAAE,WAAU,MAAM;AACZ,QAAI,MAAM,4BAA4B,IAAI,EAAE;AAE5C,QAAI,cAAc,IAAI,GAAG;AACvB,aAAO,KAAK,kBAAkB,cAAc,IAAI,CAAC;AAAA,IACnD;AACA,QAAI,UAAU,IAAI,GAAG;AACnB,UAAI,MAAM,iBAAiB;AAE3B,gBAAU,IAAI,EAAE,KAAK,IAAI;AACzB;AAAA,IACF;AACA,cAAU,IAAI,IAAI,CAAC,IAAI;AAEvB,UAAM,UAAU,OAAO,MAAM,MAAM,EAAE,aAAa,IAAI;AACtD,UAAM,SAAS,IAAI,gBAAgB,EAAE,QAAQ,SAAS,CAAC;AAEvD,UAAM,eAAe,GAAG,OAAO,YAAY,UAAU,SAAS,IAAI;AAKlE;AAAA;AAAA,MACE,GAAG,YAAY,WAAW,OAAO,SAAS,CAAC;AAAA,MAAI;AAAA,MAC7C,SAAO,gBAAgB,cAAc,GAAG;AAAA,MACxC,WAAS;AACP,YAAI,KAAK,2BAA2B,IAAI,kBAAkB,KAAK;AAC/D;AAAA;AAAA,UACE,GAAG,YAAY,OAAO,OAAO,SAAS,CAAC;AAAA,UAAI;AAAA,UACzC,UAAQ,gBAAgB,eAAe,IAAI;AAAA,UAC3C,CAAAK,WAAS,IAAI,MAAM,kBAAkB,IAAI,SAASA,MAAK;AAAA,QAAC;AAAA,MAC9D;AAAA,IAAC;AAAA,EACP,GAAG,CAAC,YAAY,MAAM,QAAQ,QAAQ,CAAC;AAEzC,SAAO;AACT;;;AF3QF,IAAM,SAAS;AAAA,EACb,OAAO;AAAA,IACL,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,WAAW;AAAA,EACb;AAAA,EACA,YAAY;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACF;AAEA,IAAM,cAAc;AAAA,EAClB,8BAAAC,QAAA,cAAC,gCAAM,IAAG,WAAU,OAAO,OAAO,SAAO,IAAE;AAAA,EAC3C,8BAAAA,QAAA,cAAC,gCAAM,IAAG,WAAU,OAAO,OAAO,SAAO,MAAI;AAAA,EAC7C,8BAAAA,QAAA,cAAC,gCAAM,IAAG,UAAS,OAAO,OAAO,SAAO,OAAK;AAAA,EAC7C,8BAAAA,QAAA,cAAC,gCAAM,IAAG,aAAY,OAAO,OAAO,SAAO,OAAK;AAClD;AAGO,IAAM,aAAa,CAAC,EAAC,MAAK,MAAM,YAAY,KAAK,KAAK,8BAAAA,QAAA,cAAC,cAAM,KAAM;AAGnE,IAAM,OAAO,CAAC,EAAC,SAAQ,MAAM,8BAAAA,QAAA,cAAC,SAAI,OAAO,OAAO,QACpD,QACH;AAEO,IAAM,aAAa,CAAC,EAAC,SAAQ,MAAM,8BAAAA,QAAA,cAAC,QAAG,OAAO,OAAO,cACzD,QACH;AAGA,IAAM,YAAY,CAAC;AAEZ,IAAM,eAAe,cAAAA,QAAM,cAAc,CAAC,CAAC;AAC3C,IAAM,QAAQ,CAAC,EAAC,UAAU,WAAW,SAAS,iBAAiB,SAAQ,MAAM;AAClF,aAAW,YAAY;AACvB,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,QAAQ;AAC3C,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAC5C,QAAM,SAAK,uBAAQ,MAAM,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;AAEhE,QAAM,OAAO,MAAM;AACjB,YAAQ,IAAI,sBAAsB,EAAE;AACpC,iBAAa,WAAW,WAAW,CAAC;AACpC,kBAAc,UAAU,EAAE,CAAC;AAC3B,cAAU,EAAE,IAAI;AAChB,eAAW,KAAK;AAAA,EAClB;AAEA,QAAM,aAAa,MAAM;AACvB,UAAM,WAAW,UAAU,EAAE;AAC7B,YAAQ,IAAI,UAAU,WAAW,KAAK;AACtC,QAAI,CAAC,YAAY,QAAQ,GAAG;AAC1B,iBAAW,IAAI;AACf,gBAAU,EAAE,IAAI,YAAY,MAC1B,SAAS,OAAK;AACZ,YAAI,EAAE,IAAI,GAAG;AACX,iBAAO;AAAA,QACT,OAAO;AACL,eAAK;AAAA,QACP;AAAA,MACF,CAAC,GAAG,GAAI;AACV,iBAAW,WAAW,SAAS,CAAC;AAAA,IAClC;AAEA,WAAO;AAAA,EACT;AAEA,+BAAU,MAAM;AAAE,YAAQ,KAAK,CAAC,WAAW,WAAW;AAAA,EAAE,GAAG,CAAC,KAAK,CAAC;AAElE,+BAAU,MAAM,MAAM,CAAC,CAAC;AAExB,qBAAmB,gBAAgB,MAAM;AAEvC,SAAK;AAAA,EACP,CAAC;AAED,QAAM,QAAQ,MAAM,SAAS,QAAQ;AAErC,SAAO,8BAAAA,QAAA,cAAC,aAAa,UAAb,EAAsB,OAAO,EAAC,OAAO,UAAU,MAAK,KACzD,QAAQ,IAAI,8BAAAA,QAAA,cAAC,aACX,UACA,QAAQ,MAAM,8BAAAA,QAAA,cAAC,aAAI,gBAAa,OAAM,UAAQ,CACjD,IACA,8BAAAA,QAAA,cAAC,aAAI,eAAW,8BAAAA,QAAA,cAAC,iCAAO,SAAS,SAAO,QAEtC,CACF,CACF;AACF;AA4BO,IAAM,uBAAuB,CAAC;AAAA,EACjC;AAAA,EAAK,OAAO;AAAA,EAA0B,MAAM;AAAA,EAAM,GAAG;AACvD,MAAM;AAEJ,QAAM,gBAAgB,CAAC,OAAOC,UAAS;AACrC,QAAI,CAAC;AAAO,YAAM,IAAI,MAAM,kBAAkBA,KAAI,EAAE;AAAA,EACtD;AAEA,QAAM,EAAC,IAAI,QAAQ,WAAU,QAAI,0BAAU,GAAG;AAE9C,gBAAc,IAAI,IAAI;AACtB,gBAAc,QAAQ,QAAQ;AAC9B,gBAAc,YAAY,YAAY;AAEtC,QAAM,OAAO,UAAU,WAAW,UAAU;AAC5C,QAAM,UAAU,WAAW,MAAM,GAAG,EAAE,CAAC;AACvC,QAAM,OAAO,GAAG,OAAO,IAAI,IAAI;AAC/B,QAAM,YAAY,OAAO,aAAa;AAEtC,QAAM,EAAE,OAAO,IAAI,cAAc;AAAA,IAC/B;AAAA,IACA;AAAA,IACA,QAAQ,MAAM,OAAO;AAAA;AAAA,IACrB,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,UAAM,sBAAO;AAGnB,+BAAU,MAAM;AACZ,QAAI,SAAS,UAAU,SAAS,QAC7B,EAAE,GAAG,GAAG,IAAI,KAAK,MAAM,KAAK,GAAG,OAAO,EAAE;AAAA,EAC7C,GAAG,CAAC,IAAI,SAAS,QAAQ,IAAI,KAAK,MAAM,KAAK,GAAG,OAAO,OAAO,MAAM,CAAC,CAAC;AAIxE,QAAM,gBAAY,uBAAQ,OAAO,EAAC,IAAI,KAAK,MAAM,KAAK,GAAG,OAAM,IAAI,CAAC,CAAC;AAErE,MAAI,CAAC;AAAQ,WAAO,8BAAAD,QAAA,cAAC,aAAI,YAAS,IAAK;AACvC,SAAO,cAAAA,QAAM,cAAc,WAAW,EAAC,GAAG,WAAW,IAAG,CAAC;AAC3D;AAUK,IAAM,gBAAN,cAA4B,cAAAA,QAAM,UAAU;AAAA,EACjD,YAAY,OAAO;AACjB,UAAM,KAAK;AACX,SAAK,QAAQ;AAAA,MACX,UAAU;AAAA,MACV,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAAA,EAEA,OAAO,yBAAyB,OAAO;AACrC,WAAO,EAAE,UAAU,KAAK;AAAA,EAC1B;AAAA,EAEA,kBAAkB,OAAO,WAAW;AAClC,YAAQ,KAAK,yBAAyB,OAAO,SAAS;AACtD,SAAK,SAAS,CAAC,EAAC,SAAQ,OAAO,EAAC,UAAU,CAAC,GAAG,UAAU,MAAM,OAAO,EAAC,EAAE;AAAA,EAC1E;AAAA,EAEA,SAAS;AACP,WAAQ,KAAK,MAAM,WAAW,8BAAAA,QAAA,cAAC,aAAI,WACvB,KAAK,MAAM,WAAW,KAAK,MAAM,UAAU,KAAK,IAAI,KACvD,4BACP,IACE,KAAK,MAAM;AAAA,EACjB;AACF;AAGO,IAAM,oBAAoB,cAAAE,QAAM,cAAc,CAAC,CAAC;AAGvD,IAAM,kCAAkC,CAAC,UAAU;AACjD,QAAM,EAAC,UAAU,KAAK,IAAI,MAAM,KAAK,aAAY,IAAI;AAErD,QAAM,UAAU,aAAa,iBAAiB;AAAA,IAC5C;AAAA,IAAK;AAAA,IAAI;AAAA,IAAM;AAAA,IAAK,UAAU,cAAAA;AAAA,EAChC,CAAC;AAED,SAAO,8BAAAA,QAAA,cAAC,kBAAkB,UAAlB,EAA2B,OAAO,EAAE,GAAG,QAAQ,KACpD,QACH;AACF;AA0BO,IAAM,4BACX,CAAC,EAAC,UAAU,KAAK,OAAO,QAAW,MAAM,OAAS,MAAM;AAEtD,QAAM,EAAC,IAAI,QAAQ,WAAU,QAAI,0BAAU,GAAG;AAC9C,QAAM,OAAO,UAAU,WAAW,UAAU;AAC5C,QAAM,UAAU,WAAW,MAAM,GAAG,EAAE,CAAC;AACvC,QAAM,OAAO,GAAG,OAAO,IAAI,IAAI;AAE/B,QAAM,EAAC,QAAQ,aAAY,IAAI,cAAc;AAAA,IAC3C;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,UAAU,cAAAA;AAAA,IACV;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,CAAC;AAAc,WAAO,8BAAAA,QAAA,cAAC,aAAI,YAAS,UAAW;AACnD,SAAO,8BAAAA,QAAA,cAAC,mCAAiC,GAAG,EAAC,KAAK,IAAI,MAAM,KAAK,aAAY,KAC1E,QACH;AACF;AAKF,IAAM,uBAAuB,CAAC,cAC3B,UAAU,YAAY,OAAO,IAAI,mBAAmB,KAChD,UAAU,WAAW;AASrB,IAAM,qBAAqB,CAAC,WAAW,MAAM,UAAU,SAC1D,UAAU,CAAC,MAAM;AAKjB,QAAM,UAAU,qBAAqB,SAAS,IAAI,cAAAA,QAAM,UAAU,IAAI;AAAA,EAEtE,MAAM,gBAAgB,cAAAA,QAAM,UAAU;AAAA,IAEpC,eAAe;AAAA,IACf,QAAQ,CAAC;AAAA,IAET,oBAAoB;AAClB,WAAK,MAAM,SAAS,WAAW;AAC/B,WAAK,wBAAwB,KAAK,MAAM,QAAQ;AAChD,WAAK,MAAM,SAAS,kBAAkB,mBAAmB;AAAA,IAC3D;AAAA;AAAA,IAGA,gBAAgB,IAAI;AAClB,WAAK,eAAe;AAAA,IACtB;AAAA,IAEA,wBAAwB,UAAU;AAEhC,YAAM,WAAW,IAAI,iBAAiB,CAAC,oBAAoB;AACvD,cAAM,SAAS,CAAC;AAChB,wBAAgB,QAAQ,CAAC,EAAC,cAAa,MAAM;AAC3C,iBAAO,aAAa,IAAI,SAAS,aAAa,aAAa;AAAA,QAC7D,CAAC;AACD,aAAK,SAAS,UAAQ,EAAC,GAAG,KAAK,GAAG,OAAM,EAAE;AAAA,MAC5C,CAAC,EAAE,QAAQ,UAAU,EAAE,YAAY,KAAK,CAAC;AAAA,IAC7C;AAAA,IAEA,2BAA2B;AAGzB,WAAK,SAAS,EAAC,eAAe,KAAI,CAAC;AACnC,UAAI;AACF,aAAK,gBAAgB,KAAK,aAAa;AAAA,MACzC,SAAS,GAAG;AACV,gBAAQ,IAAI,8CAA8C,CAAC;AAAA,MAC7D;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,UAAU,QAAQ;AAChB,WAAK,SAAS,EAAC,OAAM,CAAC;AAAA,IACxB;AAAA,IAEA,SAAS;AACP,YAAM,cAAc,QAAQ,eAAe;AAAA;AAAA;AAAA,QAGzC;AAAA,MACF;AAEA,aAAO,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UAAI,IAAI,OAAO,IAAI,IAAI,OAAO;AAAA,UACpC,WAAW,QAAQ,aAAa;AAAA;AAAA,QAChC,8BAAAA,QAAA,cAAC,eACE,YAAY,IAAI,SAAO,eAAe,GAAG,IAAI,CAChD;AAAA,QAEC,CAAC,KAAK,MAAM,iBACX,8BAAAA,QAAA;AAAA,UAAC;AAAA;AAAA,YAAU,KAAK;AAAA,YACb,GAAG,KAAK;AAAA,YAER,GAAG,KAAK;AAAA,YACT,iBAAiB,KAAK,gBAAgB,KAAK,IAAI;AAAA,YAC/C,WAAW,KAAK,UAAU,KAAK,IAAI;AAAA;AAAA,QACnC;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAC;AAED,SAAO,2BAAAC,QAAkB;AAAA,IAAO;AAAA,IAAS;AAAA,IAAM,QAAQ,aAAa;AAAA,IAClE;AAAA,EAAO;AACX;;;AD/WF,wBAAc,gBAFd;",
6
- "names": ["module", "module", "attribute", "module", "React", "styles", "module", "module", "_", "context", "getLogger", "clone", "decodeJWT", "pathToTopic", "topicToPath", "mergeVersions", "module", "_", "topicToPath", "pathToTopic", "module", "_", "topicToPath", "pathToTopic", "getLogger", "mergeVersions", "log", "clone", "MqttSync", "value", "err", "import_react", "MS", "MqttSync", "useState", "useRef", "useEffect", "React", "client", "mqtt", "_", "error", "React", "name", "React", "ReactWebComponent"]
3
+ "sources": ["../client/react-web-component/getStyleElementsFromReactWebComponentStyleLoader.js", "../client/react-web-component/extractAttributes.js", "../client/react-web-component/index.js", "../../common/datacache/tools.js", "../../common/constants.js", "../../common/common.js", "../../common/datacache/DataCache.js", "../../common/datacache/index.js", "../../common/MqttSync.js", "../index.js", "../client/shared.jsx", "../client/client.js", "../client/hooks.jsx"],
4
+ "sourcesContent": ["/*\n * An optional library which is conditionally added\n * @returns {[]}\n */\nmodule.exports = () => {\n try {\n return require('react-web-component-style-loader/exports').styleElements;\n } catch (e) {\n return [];\n }\n};\n", "/*\n * Takes in a node attributes map and returns an object with camelCased\n * properties and values\n * @param nodeMap\n * @returns {{}}\n */\nmodule.exports = function extractAttributes(nodeMap) {\n if (!nodeMap.attributes) {\n return {};\n }\n\n let obj = {};\n let attribute;\n const attributesAsNodeMap = [...nodeMap.attributes];\n const attributes = attributesAsNodeMap.map((attribute) =>\n ({ [attribute.name]: attribute.value }));\n\n for (attribute of attributes) {\n const key = Object.keys(attribute)[0];\n const camelCasedKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());\n obj[camelCasedKey] = attribute[key];\n }\n\n return obj;\n};\n", "const React = require('react');\nconst ReactDOM = require('react-dom');\nconst { createRoot } = require('react-dom/client');\n\n// const { createRoot } = require('react-dom/client'); // react 18; wip\nconst retargetEvents = require('react-shadow-dom-retarget-events');\nconst getStyleElementsFromReactWebComponentStyleLoader = require('./getStyleElementsFromReactWebComponentStyleLoader');\nconst extractAttributes = require('./extractAttributes');\n\n// require('@webcomponents/shadydom');\n// require('@webcomponents/custom-elements');\n\nconst lifeCycleHooks = {\n attachedCallback: 'webComponentAttached',\n connectedCallback: 'webComponentConnected',\n disconnectedCallback: 'webComponentDisconnected',\n adoptedCallback: 'webComponentAdopted'\n};\n\nmodule.exports = {\n /*\n * @param {JSX.Element} wrapper: the wrapper component class to be instantiated and wrapped\n * @param {string} tagName - The name of the web component. Has to be minus \"-\" delimited.\n * @param {boolean} useShadowDom - If the value is set to \"true\" the web component will use the `shadowDom`. The default value is true.\n */\n create: (wrapper, tagName, useShadowDom = true, compRef = undefined) => {\n\n const proto = class extends HTMLElement {\n instance = null; // the instance we create of the wrapper\n\n callConstructorHook() {\n if (this.instance['webComponentConstructed']) {\n this.instance['webComponentConstructed'].apply(this.instance, [this])\n }\n }\n\n callLifeCycleHook(hook, params = []) {\n const method = lifeCycleHooks[hook];\n if (method && this.instance && this.instance[method]) {\n this.instance[method].apply(this.instance, params);\n }\n }\n\n connectedCallback() {\n const self = this;\n let mountPoint = self;\n\n if (useShadowDom) {\n // Re-assign the self (this) to the newly created shadowRoot\n const shadowRoot = self.attachShadow({ mode: 'open' });\n\n // Re-assign the mountPoint to the newly created \"div\" element\n mountPoint = document.createElement('div');\n\n // Move all of the styles assigned to the react component inside of\n // the shadowRoot. By default this is not used, only if the library is\n // explicitly installed\n const styles = getStyleElementsFromReactWebComponentStyleLoader();\n styles.forEach((style) => {\n shadowRoot.appendChild(style.cloneNode(shadowRoot));\n });\n\n shadowRoot.appendChild(mountPoint);\n retargetEvents(shadowRoot);\n }\n\n createRoot(mountPoint).render(\n // This is where we instantiate the actual component (in its wrapper)\n React.createElement(wrapper, {_element: self, ...extractAttributes(self)})\n );\n }\n\n disconnectedCallback() {\n this.callLifeCycleHook('disconnectedCallback');\n }\n\n adoptedCallback(oldDocument, newDocument) {\n this.callLifeCycleHook('adoptedCallback', [oldDocument, newDocument]);\n }\n\n /* call a function defined in the component, either as a class method, or\n * via useImperativeHandle */\n call(functionName, args) {\n return compRef?.current?.[functionName]?.call(compRef?.current, args);\n }\n\n /* predefined function to retrieve the pre-defined config object of the\n * state, populated via the pre-defined `setConfig` method given as prop\n * to the wrapped component. */\n getConfig() {\n return this.instance.state.config;\n }\n }\n\n customElements.define(tagName, proto);\n\n return proto;\n },\n};\n", "\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isPlainObject: require('lodash/isPlainObject'),\n};\n\n\n// -------------------------------------------------------------------------\n// DataCache tools\n\n/** convert topic to path array */\nconst topicToPath = (topic) => {\n // split topic by slashes, but not if they are escaped\n // const path = topic.match(/(\\\\.|[^/])+/g) || [];\n // split topic by slashes and unescape slashes in each item\n const path = topic.split('/').map(decodeTopicElement);\n // handle leading slash\n path.length > 0 && path[0].length == 0 && path.shift();\n // handle trailing slash\n path.length > 0 && path.at(-1).length == 0 && path.pop();\n return path;\n};\n\n\n/** convert a path array to mqtt topic; reduces +id identifiers to + */\nconst pathToTopic = (pathArray) => {\n /** reduce wildcards with Ids, such as `+sessionId`, to just + */\n const dropWildcardIds = (x) => x.startsWith('+') ? '+' : x;\n return `/${pathArray.map(dropWildcardIds).map(encodeTopicElement).join('/')}`;\n};\n\n/**\n * Given an object, return a new flat object of topic+value pairs, e.g.:\n```js\n{a: {b: 1, c: 2}, d: 3} \u2192 {'/a/b': 1, '/a/c': 2, '/d': 3}\n```\nNote: not idempotent!\n```js\n{'/a/b': 1, '/a/c': 2, d: 3} \u2192 {'%2Fa%2Fb': 1, '%2Fa%2Fc': 2, '/d': 3}\n```\n*/\nconst toFlatObject = (obj, prefix = [], rtv = {}) => {\n _.forEach(obj, (value, key) => {\n // const newPrefix = prefix.concat(topicToPath(String(key)));\n const newPrefix = prefix.concat(String(key));\n\n // TODO: using isPlainObject also means custom objects (classes) do not get\n // broken down.\n if ((_.isPlainObject(value) || value instanceof Array) && value !== null) {\n // it's an object or array\n toFlatObject(value, newPrefix, rtv);\n } else {\n // it's a primitive\n rtv[pathToTopic(newPrefix)] = value;\n }\n });\n return rtv;\n};\n\n/** Iterate through the object and invoke callback for each match of path (with\nnamed wildcards) */\nconst forMatchIterator = (obj, path, callback, pathSoFar = [], matchSoFar = {}) => {\n\n if (path.length == 0 || path[0] == '#') {\n callback(obj, pathSoFar, matchSoFar);\n return;\n }\n\n const next = path[0]; // don't use shift, we don't want to modify path\n if (next) {\n for (let key in obj) {\n if (key == next || next == '*' || next.startsWith('+')) {\n const match = next.startsWith('+') && next.length > 1 ?\n Object.assign({}, matchSoFar, {[next.slice(1)]: key}) :\n matchSoFar;\n forMatchIterator(obj[key], path.slice(1), callback,\n pathSoFar.concat([key]), match);\n }\n }\n }\n};\n\n/** Like _.set but without arrays. This allows using numbers as keys. */\nconst setFromPath = (obj, path, value) => {\n if (path.length == 0) return obj;\n const next = path.shift();\n if (path.length == 0) {\n obj[next] = value;\n } else {\n if (!obj[next]) obj[next] = {};\n setFromPath(obj[next], path, value);\n }\n};\n\nconst encodeTopicElement = x => x.replace(/%/g, '%25').replace(/\\//g, '%2F');\nconst decodeTopicElement = x => x.replace(/%25/g, '%').replace(/%2F/g, '/');\n\n\n/** Match a slash-separated topic or path array with a selector using +XYZ for\n* (named) wildcards. Return the matching result.\n*/\nconst topicMatch = (selector, topic) => {\n const byArray = (s, p) => {\n if (s.length == 0) return true; // we are done: prefix matched\n if (s[0][0] == '#') return true; // explicit tail-wildcard\n // if (p.length < s.length) return false;\n if (p.length == 0) return true; // we are done, matched all\n // simple match:\n if (s[0] == p[0]) return byArray(s.slice(1), p.slice(1));\n // wild card match:\n if (s[0][0] == '+') {\n const sub = byArray(s.slice(1), p.slice(1));\n return sub && Object.assign({[s[0].slice(1)]: p[0]}, sub);\n }\n // else: failure!\n return false;\n };\n\n const selectorArray = Array.isArray(selector) ? selector : topicToPath(selector);\n const pathArray = Array.isArray(topic) ? topic : topicToPath(topic);\n return byArray(selectorArray, pathArray);\n};\n\n/** sub is a strict sub-topic of parent, and in particular not equal */\nconst isSubTopicOf = (sub, parent) => {\n const pPath = topicToPath(parent);\n const sPath = topicToPath(sub);\n return isPrefixOf(pPath, sPath) && pPath.length < sPath.length;\n};\n\n/** prefixArray is a prefix of the array */\nconst isPrefixOf = (prefixArray, array) => {\n if (prefixArray.length == 0) return true;\n return (prefixArray[0] == array[0] &&\n isPrefixOf(prefixArray.slice(1), array.slice(1))\n );\n}\n\n\nmodule.exports = {\n topicToPath,\n pathToTopic,\n toFlatObject,\n forMatchIterator,\n setFromPath,\n encodeTopicElement,\n decodeTopicElement,\n topicMatch,\n isSubTopicOf,\n};", "module.exports = {\n rosReleases: {\n kinetic: { rosVersion: 1, ubuntuCodename: 'xenial' },\n melodic: { rosVersion: 1, ubuntuCodename: 'bionic' },\n noetic: { rosVersion: 1, ubuntuCodename: 'focal' },\n dashing: { rosVersion: 2 },\n eloquent: { rosVersion: 2 },\n foxy: { rosVersion: 2 },\n galactic: { rosVersion: 2 },\n humble: { rosVersion: 2 },\n iron: { rosVersion: 2 },\n jazzy: { rosVersion: 2 },\n kilted: { rosVersion: 2 },\n rolling: { rosVersion: 2 },\n }\n};\n", "const semverCompare = require('semver/functions/compare');\nconst semverMinVersion = require('semver/ranges/min-version');\n\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst loglevel = require('loglevel');\nconst prefix = require('loglevel-plugin-prefix');\nconst chalk = require('chalk');\n\nconst { topicToPath, pathToTopic, toFlatObject, setFromPath, forMatchIterator,\n topicMatch, isSubTopicOf, encodeTopicElement, decodeTopicElement }\n = require('./datacache/tools');\n\nconst constants = require('./constants');\n\n// ----------------------------------------------------------------------------\n// Logging, incl. logger prefix\n\n/* Convenience function to set all loggers to the given level. */\nloglevel.setAll = (level) =>\n Object.values(loglevel.getLoggers()).forEach(l => l.setLevel(level));\n\nconst logColors = {\n warn: chalk.yellow,\n error: chalk.red,\n info: chalk.green,\n debug: chalk.gray,\n};\n\nconst levelFormatter =\n (level) => logColors[level] ? logColors[level](level) : level;\n\nprefix.reg(loglevel);\n\nif (typeof window != 'undefined') {\n // browser: keep it simple\n prefix.apply(loglevel, {\n template: '[%n %l]',\n });\n} else {\n // back-end + robot: include timestamp and use colors\n prefix.apply(loglevel, {\n template: '[%t %n %l]',\n levelFormatter,\n timestampFormatter: date => chalk.blue(date.toISOString()),\n });\n}\n\n/** Get a new loglevel logger; call with a name, e.g., `module.id`. The returned\n* logger has methods trace, debug, info, warn, error. See\n* https://www.npmjs.com/package/loglevel for details.\n*/\nconst getLogger = loglevel.getLogger;\n\n// ----------------------------------------------------------------------------\n\n/** Deep-clone the given object. All functionality is lost, just data is kept. */\nconst clone = (obj) => JSON.parse(JSON.stringify(obj));\n\n/** Parse JWT and return the decoded payload (JSON). */\nconst decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n// TODO: make this robust against bad JWTs (throw a more readable error)\n\n/** Try parsing JSON, return null if unsuccessful */\nconst tryJSONParse = (string) => {\n try {\n return JSON.parse(string);\n } catch (e) {\n return null;\n }\n};\n\n/** Reusable visitor pattern: iteratively visits all nodes in the tree\n described by `object`, where `childField` indicates the child-of predicate.\n*/\nconst visit = (object, childField, visitor) => {\n if (!object) return;\n visitor(object);\n object[childField]?.forEach(child => visit(child, childField, visitor));\n};\n\n/** Given an object and a path, visit each ancestor of the path */\nconst visitAncestor = (object, path, visitor, prefix = []) => {\n visitor(object, prefix);\n const next = path[0];\n if (next) {\n const sub = object[next];\n if (sub) {\n visitAncestor(sub, path.slice(1), visitor, prefix.concat(next));\n }\n }\n};\n\n/** Wait for delay ms, for use in async functions. */\nconst wait = (delay) => new Promise((resolve) => { setTimeout(resolve, delay); });\n\n\n\n\n// -------------------------------------------------------------------------\n// MQTT Tools\n\n/** parse usernames used in MQTT */\nconst parseMQTTUsername = (username) => {\n const parts = username.split(':');\n return {\n organization: parts[0],\n client: parts[1],\n sub: parts.slice(2)\n }\n};\n\n/** parse an MQTT topic according to our topic schema */\nconst parseMQTTTopic = (topic) => {\n const parts = topicToPath(topic);\n return {\n organization: parts[0],\n device: parts[1],\n capabilityScope: parts[2],\n capabilityName: parts[3],\n capability: `${parts[2]}/${parts[3]}`,\n version: parts[4],\n sub: parts.slice(5)\n }\n};\n\nconst mqttParsePayload = (payload) =>\n payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// TODO: ^ This can probably now just become tryJSONParse\n\n/** delete all retained messages in a certain topic prefix, waiting for\n a given delay to collect existing retained. Use with care, never delete topics\n not owned by us. Harmless within capabilities, which are namespaced already.\n*/\nconst mqttClearRetained = (mqttClient, prefixes, callback, delay = 1000) => {\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n // mqttTopicMatch(topic, `${prefix}/#`) && toDelete.push(topic)\n topicMatch(`${prefix}/#`, topic) && toDelete.push(topic)\n );\n }\n mqttClient.on('message', collectToDelete);\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n mqttClient.subscribe(`${prefix}/#`);\n } else {\n console.warn('Ignoring', prefix, 'since it is not a string.');\n }\n });\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n setTimeout(() => {\n mqttClient.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => mqttClient.unsubscribe(`${prefix}/#`));\n\n const count = toDelete.length;\n console.log(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n mqttClient.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n }, delay);\n};\n\n\n// WIP: a cleaner, more explicit way to serialize/deserialize mqtt payloads\n// /** Serialize a message for transport via MQTT */\n// const mqttSerialize = (message) => {\n// return value == null ? null : JSON.stringify(message);\n// };\n\n// /** Deserialize a message from MQTT */\n// const mqttDeserialize = (payload) => {\n// return payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// };\n\n\n// -------------------------------------------------------------------------\n\n/** Generate a random id (base36) */\nconst getRandomId = (bytes = 6) => {\n const buffer = new Uint8Array(bytes);\n crypto.getRandomValues(buffer);\n return buffer.reduce((memo, i) => memo + i.toString(36), '');\n};\n\n/** Convert number to base52 [a-zA-Z] */\nconst toBase52 = (num) => {\n const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n const list = [];\n do {\n list.unshift(characters[num % 52]);\n num = Math.floor(num / 52);\n } while (num > 0);\n return list.join('');\n}\n\n/** Get a base52 representation [a-zA-Z] of the current date (ms since epoch) */\nconst getDateBase52 = () => toBase52(Date.now());\n\n// -------------------------------------------------------------------------\n\n/** Compare to version strings. Return -1 if a is lower than b,\n0 if they are equal, and 1 otherwise. If either is not a complete version,\ne.g., 2.0, interpret it as a range and use its minimum version for the\ncomparison. Hence, 2.0 < 2.0.1. */\nconst versionCompare = (a, b) =>\n semverCompare(semverMinVersion(a), semverMinVersion(b));\n\n// -------------------------------------------------------------------------\n\n/** given an object where the keys are versions, merge this into one object\n where the latest version of each subfield overwrites any previous */\nconst mergeVersions = (versionsObject, subTopic = undefined, options = {}) => {\n if (!versionsObject) {\n return subTopic ? _.set({}, subTopic, versionsObject) : versionsObject;\n }\n\n const versions = Object.keys(versionsObject).filter(ver =>\n (!options.maxVersion || versionCompare(ver, options.maxVersion) <= 0) &&\n (!options.minVersion || versionCompare(options.minVersion, ver) <= 0))\n .sort(versionCompare);\n\n const merged = {};\n const subPath = subTopic && topicToPath(subTopic);\n versions.forEach(nextVersion => {\n const newValue = subPath ? _.get(versionsObject[nextVersion], subPath) :\n versionsObject[nextVersion];\n // Object.assign(merged, newValue);\n _.merge(merged, newValue);\n });\n return subPath ? _.set({}, subPath, merged) : merged;\n};\n\n// -------------------------------------------------------------------------\n// Formatting tools\n\nconst units = ['B', 'KB', 'MB', 'GB', 'TB'];\nconst formatBytes = (bytes) => {\n if (!bytes) return '--';\n let i = 0;\n while (bytes > 1024) {\n bytes /= 1024;\n i++;\n }\n return `${bytes.toFixed(2)} ${units[i]}`;\n}\n\nconst formatDuration = (seconds) => {\n if (!seconds) return '--';\n const parts = {};\n if (seconds > 3600) {\n parts.h = Math.floor(seconds / 3600);\n seconds = seconds % 3600;\n }\n if (seconds > 60) {\n parts.m = Math.floor(seconds / 60);\n seconds = seconds % 60;\n }\n parts.s = Math.floor(seconds);\n\n let rtv = '';\n parts.h > 0 && (rtv += `${parts.h}h `);\n parts.m > 0 && (rtv += `${parts.m}m `);\n !parts.h && (rtv += `${parts.s}s`);\n return rtv.trim();\n};\n\n// -------------------------------------------------------------------------\n\nmodule.exports = { parseMQTTUsername, parseMQTTTopic,\n pathToTopic, topicToPath, toFlatObject, topicMatch,\n mqttParsePayload, getRandomId, toBase52, getDateBase52, versionCompare,\n loglevel, getLogger,\n mergeVersions, mqttClearRetained, isSubTopicOf, clone, setFromPath,\n forMatchIterator, encodeTopicElement, decodeTopicElement, constants, visit,\n wait, formatBytes, formatDuration, tryJSONParse,\n decodeJWT, visitAncestor\n};\n", "\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst {topicToPath, pathToTopic, toFlatObject, topicMatch, forMatchIterator}\n = require('./tools');\n\n/** Unset the topic in that obj, and clean up parent if empty, recursively.\nReturn the path to the removed node.\n*/\nconst unset = (obj, path) => {\n if (!path || path.length == 0) return;\n _.unset(obj, path);\n const parentPath = path.slice(0, -1);\n // _.get doesn't do the intuitive thing for the empty path, handle it ourselves\n const parent = parentPath.length == 0 ? obj : _.get(obj, parentPath);\n if (_.isEmpty(parent)) {\n return unset(obj, parentPath);\n } else {\n return path;\n }\n};\n\n/** Given a modifier `{\"a/b/c\": \"xyz\"}` update the object `obj` such that\n`obj.a.b.c = \"xyz\"`. */\nconst updateObject = (obj, modifier) => {\n _.forEach( modifier, (value, topic) => {\n const path = topicToPath(topic);\n if (value == null) {\n unset(obj, path);\n } else {\n _.set(obj, path, value);\n }\n });\n return obj;\n};\n\n/** Given an object and a path with wildcards (`*` and `+`), *modify* the object\nto only contain elements matched by the path, e.g.,\n`{a: {b: 1, c: 2}, d: 2}` and `['a','+']` would give `{a: {b: 1, c: 2}}`\n\n@param {object} obj - The object to select from\n@param {array} path - An array specifying the path to select, potentially\ncontaining mqtt wildcards ('+').\n*/\nconst selectFromObject = (obj, path) => {\n if (path.length == 0) return;\n const next = path[0];\n if (next) {\n for (let key in obj) {\n if (key != next && next != '*' && !next.startsWith('+')) {\n delete obj[key];\n } else {\n selectFromObject(obj[key], path.slice(1));\n }\n }\n }\n};\n\n\n/**\n* A class implementing a local data cache, used as a local data store with\n* deduplication detection and update events. While this class is very handy\n* you probably won't need to create instances of it directly. Instead use\n* the mqttSync.data instance which holds the locally stored data\n* subscribed/published from/to MQTTSync.\n* For example on the robot:\n* ```js\n* // update/publish our status:\n* mqttSync.data.update('status', {changed: Date.now(), msg: 'OK'});\n* // subscribe to new user requests (e.g., from UI):\n* mqttSync.data.subscribePath('+user/request', (request, key, {user}) => {\n* log.debug(`user ${user} made request`, request);\n* });\n* ```\n* In the cloud or in a web component you would need to use the full topic including\n* org, device, scope, cap-name, and version.\n*/\nclass DataCache {\n\n #data = {};\n #listeners = [];\n #flatListeners = [];\n\n constructor(data = {}) {\n this.#data = data;\n\n // for now add an alias\n this.subscribeTopic = this.subscribePath;\n }\n\n /** Update the object with the given value at the given path, remove empty;\n return the flat changes (see toFlatObject). Add `tags` to updates to mark\n them somehow based on the context, e.g., so that some subscriptions can choose\n to ignore updates with a certain tag.\n */\n updateFromArray(path, value, tags = {}) {\n // const empty = Object.keys(this.#data).length == 0; // object already empty\n const current = _.get(this.#data, path);\n if (value == null) {\n if (current === undefined || current === null) {\n return {}; // no change, do not call listeners\n } else {\n unset(this.#data, path);\n }\n } else {\n if (_.eq(current, value)) {\n // note: this is just a shallow equal, so replacing a sub-document\n // with an atomic copy of it should still trigger listeners.\n // TODO: Note also that when value is an object, we will set it by\n // reference here, so any changes made to that object will *not* trigger\n // listeners because `current` will already be changed -- which is\n // probably wrong. May want to always clone value first.\n return {}; // nothing to do, do not bother listeners\n }\n // console.log('setting', path, value);\n _.set(this.#data, path, value);\n // TODO: implement this ourselves so we can do better change-checking\n }\n\n const topic = pathToTopic(path);\n const obj = {[topic]: value};\n\n // flatten the value and combine eith topic (without reflattening the topic):\n let flatChanges;\n if (value instanceof Object) {\n const flatValue = toFlatObject(value);\n flatChanges = {};\n _.forEach(flatValue, (atomic, flatKey) => {\n flatChanges[`${topic}${flatKey}`] = atomic;\n });\n } else {\n flatChanges = obj;\n }\n\n // option 1. using flat changes (sub-documents are never atomic)\n // this.#listeners.forEach(fn => fn(flatChanges));\n\n // option 2. allow atomic sub-document changes\n this.#listeners.forEach(fn => fn(obj, tags));\n\n this.#flatListeners.forEach(fn => fn(flatChanges, tags));\n\n return flatChanges;\n }\n\n /** Update the value at the given path (array or dot separated string) */\n update(path, value, tags) {\n if (typeof path == 'string') {\n return this.updateFromTopic(path, value, tags);\n } else if (path instanceof Array) {\n return this.updateFromArray(path, value, tags);\n } else {\n throw new Error('unrecognized path expression');\n }\n }\n\n /** Set value from the given topic (with or without leading or trailing slash) */\n updateFromTopic(topic, value, tags) {\n return this.updateFromArray(topicToPath(topic), value, tags);\n }\n\n /** Update data from a modifier object where keys are topic names to be\n interpreted as paths, and values are the values to set */\n updateFromModifier(modifier, tags) {\n return _.map(modifier, (value, topic) =>\n this.updateFromTopic(topic, value, tags));\n }\n\n /** Add a callback for all change events. */\n subscribe(callback) {\n if (callback instanceof Function) {\n this.#listeners.push(callback);\n } else {\n console.warn('DataCache.subscribe expects a function as argument. Did you mean to use subscribePath?');\n }\n }\n\n /** Subscribe to a specific path (array) only. Callback receives\n `value, key, matched, tags`. */\n subscribePath(path, callback) {\n this.#listeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(path, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Subscribe to a specific topic only. Callback receives\n `value, key, matched, tags`. */\n subscribeTopic(topic, callback) {\n this.subscribePath(topic, callback);\n }\n\n /** Same as subscribePath but always get all changes in flat form */\n subscribePathFlat(topic, callback) {\n this.#flatListeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(topic, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Remove a callback previously registered using `subscribe`. */\n unsubscribe(callback) {\n this.#listeners = this.#listeners.filter(f => f != callback);\n }\n\n /** Get sub-value at path, or entire object if none given */\n get(path = []) {\n return path.length == 0 ? this.#data : _.get(this.#data, path);\n }\n\n /** Get sub-value specified by topic */\n getByTopic(topic) {\n return this.get(topicToPath(topic));\n }\n\n /** Filter the object using path with wildcards */\n filter(path) {\n const rtv = JSON.parse(JSON.stringify(this.get()));\n selectFromObject(rtv, path);\n return rtv;\n }\n\n /** Filter the object using topic with wildcards */\n filterByTopic(topic) {\n return this.filter(topicToPath(topic));\n }\n\n /** For each topic match, invoke the callback with the value, path, and match\n just like subscribePath, but on the current data rather than future changes. */\n forMatch(topic, callback) {\n const path = topicToPath(topic);\n this.forPathMatch(path, callback);\n }\n\n /** For each path match, invoke the callback with the value, path, and match\n just like subscribePath */\n forPathMatch(path, callback) {\n forMatchIterator(this.get(), path, callback);\n }\n};\n\nmodule.exports = {\n DataCache, updateObject\n}", "const dataCache = require('./DataCache');\nconst tools = require('./tools');\n\nmodule.exports = { ...dataCache, ...tools };", "'use strict';\n\nconst _ = require('lodash');\n\nconst { mqttParsePayload, topicMatch, topicToPath, pathToTopic,\ntoFlatObject, getLogger, mergeVersions, parseMQTTTopic, isSubTopicOf,\nversionCompare, encodeTopicElement, visitAncestor, getRandomId }\n = require('./common');\nconst { DataCache } = require('./datacache/DataCache');\n\n\nconst log = getLogger('MqttSync');\nlog.setLevel('info');\n\nconst HEARTBEAT_TOPIC = '$SYS/broker/uptime';\nconst specialKey = '$_'; // special key to reify \"value\" in publishedMessages\n\nconst noop = () => {};\n\n/* clone a mqtt payload, if necessary */\nconst clone = (payload) => {\n if (typeof payload == 'object') {\n return JSON.parse(JSON.stringify(payload));\n } else {\n return payload;\n }\n};\n\n/* return new string that ends in /# for sure */\nconst ensureHashSuffix = (topic) =>\n topic.endsWith('/#') ? topic :\n ( topic.endsWith('/') ? topic.concat('#') :\n topic.concat('/#') );\n\n/* given a path, replace any double slashes, '//', with single ones */\nconst resolveDoubleSlashes = (path) => path.replace(/\\/\\//g, '/');\n\n\n/** A class that combines DataCache and MQTT to implement a data synchronization\nfeature over the latter. Relies on retained messages in mqtt for persistence.\n* @param {object} options\n* @param {object} options.mqttClient - An already connected mqtt.js client.\n* @param {boolean} [options.ignoreRetain] - retain all messages, ignorant of the retain\n* flag.\n* @param {number} [options.sliceTopic] - a number indicating at what level to\n* slice the topic, i.e., only use a suffix. Used in robot-capabilities to slice\noff the topic prefix (namespaces).\n* @param {array} [options.migrate] - an array of objects of the form\n* `{topic, newVersion, level}`. Only meaningful in the cloud. Instructs MQTTSync\nto first migrate existing topics to a new version namespace, publishing at the\ndesignated level down from the version level. For example:\n```js\n[{ topic: `/myorg/mydevice/@local/my-cap/+/config`,\n newVersion: this.version,\n level: 1\n}]\n```\nWould migrate any existing data in the capability's `config` namespace to the\ncurrent version of the package, publishing at the `config/+` level (rather than\natomically at the config level itself).\n* @param {function} [options.onReady] - A function that is called when the MQTTSync\nclient is ready and has completed any requested migrations.\n* @param {function} [options.onChange] - A function that is called any time there\nis a change to the shared data. This is not usually used. It's usually better to\nuse the finer grained `MqttSync.data.subscribePath` instead, that allows you to\nsubscribe to changes just on a specific sun-object instead, see DataCache.\n*/\nclass MqttSync {\n\n data = new DataCache();\n\n /* Directory of paths we've subscribed to in this class; this matters\n because the same mqtt client may have subscriptions to paths that we don't\n care to store (sync). */\n subscribedPaths = {};\n\n publishedPaths = {}; // not used in atomic mode\n\n /* Store messages retained on mqtt so we can publish what is necessary to\n achieve the \"should-be\" state. Note that we cannot use a structured document\n for storing these publishedMessages since we need to be able to store separate\n values at non-leaf nodes in the object (just like mqtt, where you can have\n /a/b = 1 and /a/b/c = 1 at the same time). Note: not used in atomic mode.\n Note: we use specialKey in this DataCache to allow overlapping\n topics (e.g., `/a/b/$_ = 1` and `/a/$_ = {b: 2}`)\n */\n publishedMessages = new DataCache();\n\n /* The order in which we send retained messages matters, which is why we use\n a queue for sending things. Note that we here use the property of Map that it\n remembers insertion order of keys. */\n publishQueue = new Map();\n\n /* We need to keep a record of all received topics (not messages) so far in\n case we want to clear any of them. */\n receivedTopics = new Set();\n\n /* List of callbacks waiting for next heartbeat, gets purged with each\n heartbeat */\n heartbeatWaitersOnce = [];\n\n heartbeats = 0;\n\n beforeDisconnectHooks = [];\n\n rpcHandlers = {}; // handlers for incoming RPC requests\n rpcCallbacks = {}; // callback for RPC requests we've sent\n\n constructor({mqttClient, onChange, ignoreRetain, migrate, onReady,\n sliceTopic, onHeartbeatGranted }) {\n\n this.mqtt = mqttClient;\n this.sliceTopic = sliceTopic;\n\n this.mqtt.on('message', (topic, payload, packet) => {\n const payloadString = payload && payload.toString()\n // log.debug('got message', topic, payloadString.slice(0, 180),\n // payloadString.length > 180 ? `... (${payloadString.length} bytes)` : '',\n // packet.retain);\n\n if (topic == HEARTBEAT_TOPIC) {\n if (this.heartbeats > 0) { // ignore initial heartbeat (retained)\n this.heartbeatWaitersOnce.forEach(cb => cb());\n this.heartbeatWaitersOnce = [];\n }\n if (this.heartbeats == 1 && !migrate && onReady) onReady();\n this.heartbeats++;\n\n } else {\n this.receivedTopics.add(topic);\n // Do NOT parse payload just yet, since it may be binary and ignored by us\n\n let path = topicToPath(topic);\n log.debug('processing message', topic);\n if (sliceTopic) {\n path = path.slice(sliceTopic);\n topic = pathToTopic(path);\n }\n\n if (this.rpcHandlers[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCRequest(topic, json);\n\n } else if (this.rpcCallbacks[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCResponse(topic, json);\n\n } else if (packet.retain || ignoreRetain) {\n\n if (this.isPublished(topic)) {\n const json = mqttParsePayload(payload);\n // store plain messages, still stored in a structure, but values are\n // not interpreted; we just store them to undo them if necessary, e.g.,\n // for switching between atomic and non-atomic subdocuments\n // log.trace('setting publishedMessages', topic);\n this.publishedMessages.updateFromArray([...path, specialKey], json);\n\n // this.pubData.update(topic, json);\n // Still need to update the data so that we can detect changes we make\n // and publish them. But we need to break the reaction-chain to avoid\n // loops, so tag this update with 'published' and then ignore those\n // updates in this.publish.\n this.data.update(topic, json, {external: true});\n\n } else if (this.isSubscribed(topic)) {\n const json = mqttParsePayload(payload);\n\n log.debug('applying received update', topic);\n const changes = this.data.update(topic, json, {external: true});\n onChange && Object.keys(changes).length > 0 && onChange(changes);\n }\n }\n // else: do not try to parse it, it might be a binary message sent\n // directly using the client (with or without retain)\n }\n });\n\n this.mqtt.subscribe(HEARTBEAT_TOPIC, {rap: true}, (err, granted) => {\n log.debug(HEARTBEAT_TOPIC, {granted});\n granted && granted.length > 0 && onHeartbeatGranted?.();\n });\n\n migrate?.length > 0 && this.migrate(migrate, () => {\n log.debug('done migrating');\n onReady && this.waitForHeartbeatOnce(onReady);\n });\n }\n\n /**\n * Publish all values at the given level of the given object under the given\n * topic (plus sub-key, of course).\n * TODO: Is this OK, or do we need to go through this.publish?\n */\n publishAtLevel(topic, value, level) {\n log.debug(`publishingAtLevel ${level}`, topic, value);\n\n if (level > 0) {\n _.forEach(value, (subValue, subKey) => {\n const subTopic = `${topic}/${encodeTopicElement(subKey)}`;\n log.debug(`publishing ${subTopic}`);\n this.publishAtLevel(subTopic, subValue, level - 1);\n });\n } else {\n this.mqtt.publish(topic, JSON.stringify(value), {retain: true}, (err) => {\n err && log.warn('Error when publishing migration result', err);\n });\n }\n }\n\n /** Migrate a list of `{topic, newVersion, transform}`. The version number in\n * topic will be ignored, and all versions' values will be merged, applied in\n * order, such that the latest version is applied last. `topic` may include\n * wildcards in the part before the version number but not after.\n *\n * Example:\n * ```js\n * mqttSync.migrate([{topic: '/+/dId/@scope/capname/+/b', newVersion: '1.2.0'}]\n * ```\n */\n migrate(list, onReady = undefined) {\n\n let toGo = list.length;\n if (toGo == 0) {\n onReady && onReady(); // in case an empty list was given\n return;\n }\n\n /* called each time one item is done */\n const oneDown = () => --toGo == 0 && onReady && onReady();\n\n list.forEach(({topic, newVersion, transform = undefined, flat = false,\n level = 0}) => {\n log.debug('migrating', topic, newVersion);\n const {organization, device, capability, sub} = parseMQTTTopic(topic);\n const prefix = `/${organization}/${device}/${capability}`;\n\n const suffix = sub.length == 0 ? '/#' : pathToTopic(sub);\n // suffix will have a leading slash\n const subTopic = `${prefix}/+${suffix}`;\n\n this.subscribe(subTopic, (err) => {\n if (err) {\n log.warn('Error during migration', err);\n oneDown();\n return;\n }\n\n const all = {};\n this.waitForHeartbeatOnce(() => {\n\n // for each match (prefix can include wildcards) merge everything\n this.data.forMatch(prefix, (value, path, match) => {\n // an actual (ground, aka. no wildcard) prefix\n const groundPrefix = pathToTopic(path);\n\n log.debug('got heartbeat', {prefix, topic, subTopic, suffix}, groundPrefix, value);\n if (!value) {\n // no data to migrate\n return;\n }\n // collect for cleanup\n Object.assign(all, value);\n\n const merged = mergeVersions(value, suffix, {maxVersion: newVersion});\n // get suffix in merged\n const suffixMergedValue = _.get(merged, topicToPath(suffix));\n log.debug({value, suffix, merged, suffixMergedValue});\n // ^ this will need to change to support wild-cards in suffix\n const transformed = transform ? transform(suffixMergedValue) :\n suffixMergedValue;\n\n // Publish the transformed value under the ground prefix as\n // `newVersion/suffix`\n const newTopic =\n resolveDoubleSlashes(`${groundPrefix}/${newVersion}/${suffix}`);\n log.debug('publishing merged', newTopic);\n\n if (flat) {\n const flatObj = toFlatObject(transformed);\n const newPath = topicToPath(newTopic);\n _.forEach(flatObj, (value, key) => {\n const keyTopic = pathToTopic(newPath.concat(topicToPath(key)));\n // TODO: Is this OK, or do we need to go through this.publish?\n this.mqtt.publish(keyTopic, JSON.stringify(value),\n {retain: true}, (err) => {\n err && log.warn(\n `Error when publishing migration result for ${key}`, err);\n });\n });\n\n } else {\n this.publishAtLevel(newTopic, transformed, level);\n }\n });\n\n this.unsubscribe(subTopic);\n\n if (Object.keys(all).length == 0) {\n // no data to migrate\n oneDown();\n return;\n }\n\n this.waitForHeartbeatOnce(() => {\n // now clear this suffix in the old version space\n const oldVersions = Object.keys(all).filter(v =>\n versionCompare(v, newVersion) < 0);\n // log.debug({oldVersions});\n\n const prefixesToClear = oldVersions.map(oldV =>\n resolveDoubleSlashes(`${prefix}/${oldV}/${suffix}`));\n\n this.clear(prefixesToClear);\n oneDown();\n });\n });\n });\n });\n }\n\n /** Delete all retained messages in a certain topic prefix, waiting for\n a mqtt broker heartbeat to collect existing retained. Use with care, never\n delete topics not owned by us. Harmless within capabilities, which are\n namespaced already.\n\n `options.filter(topic)`: a function that can be provided to further,\n programmatically filter the set of topics to clear, e.g., to onlt clear\n topics of old versions.\n\n Note: This may not yet work in robot-capabilities, since the subscription\n prefix and received topic prefix don't match (the device prefix is added to\n subscription by localMQTT.\n */\n clear(prefixes, callback = undefined, options = {}) {\n\n // If prefixes are empty, just skip (call callback and return)\n if (!prefixes || prefixes.length == 0) {\n log.warn('clear was given no prefixes');\n callback?.(0);\n return;\n }\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n topicMatch(`${prefix}/#`, topic)\n && (!options.filter || options.filter(topic))\n && toDelete.push(topic)\n );\n }\n this.mqtt.on('message', collectToDelete);\n // this only collects new topics, not those we've already received\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n this.mqtt.subscribe(`${prefix}/#`);\n } else {\n log.warn('Ignoring', prefix, 'since it is not a string.');\n }\n });\n\n // add matching topics we already know off:\n this.receivedTopics.forEach(collectToDelete);\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n this.waitForHeartbeatOnce(() => {\n this.mqtt.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => this.mqtt.unsubscribe(prefix));\n\n const count = toDelete.length;\n log.info(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n this.mqtt.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n });\n };\n\n\n /** register a callback for the next heartbeat from the broker */\n waitForHeartbeatOnce(callback) {\n // need to wait a tick, in case we are still in the callback tree\n // of a previous heartbeat waiter\n setTimeout(() => this.heartbeatWaitersOnce.push(callback), 1);\n }\n\n /** check whether we are subscribed to the given topic */\n isSubscribed(topic) {\n return Object.keys(this.subscribedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic));\n }\n\n /** Check whether we are publishing the given topic in a non-atomic way.\n This is used to determine whether to store the published value or not. */\n isPublished(topic) {\n return Object.keys(this.publishedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic) &&\n !this.publishedPaths[subscribedTopic].atomic\n );\n }\n\n /** Subscribe to the given topic (and all sub-topics). The callback will\n indicate success/failure, *not* a message on the topic. */\n subscribe(topic, callback = noop) {\n topic = ensureHashSuffix(topic);\n log.debug('subscribing to', topic);\n if (this.subscribedPaths[topic]) {\n log.debug('already subscribed to', topic);\n callback();\n return;\n }\n\n this.mqtt.subscribe(topic, {rap: true}, (err, granted) => {\n log.debug('subscribe', topic, 'granted:', granted);\n if (granted && granted.some(grant => grant.topic == topic && grant.qos < 128)) {\n // granted\n this.subscribedPaths[topic] = 1;\n callback(null);\n } else {\n // let user know (somehow) when we don't get permission\n callback(`not permitted to subscribe to topic ${topic}, ${JSON.stringify(granted)}`);\n }\n });\n }\n\n unsubscribe(topic) {\n topic = ensureHashSuffix(topic);\n if (this.subscribedPaths[topic]) {\n this.mqtt.unsubscribe(topic);\n delete this.subscribedPaths[topic];\n }\n }\n\n /** Publish retained to MQTT, store as published, and return a promise */\n _actuallyPublish(topic, value) {\n // return new Promise((resolve, reject) =>\n // this.mqtt.publish(topic,\n // value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n // {retain: true},\n // (err) => {\n // // Note that this returns optimistically at QoS 0, and no error occurs\n // // even when we are not allowed to publish this topic/message, see\n // // https://github.com/mqttjs/MQTT.js/#publish. Only when the client\n // // disconnects it seems.\n // if (err) {\n // log.warn('error in _actuallyPublish:', err);\n // reject(err);\n // // TODO: if this happens, we may need to force a full-sync\n // } else {\n // resolve();\n // }\n // }));\n\n if (!this.mqtt.connected) {\n log.warn('not connected, not publishing', topic);\n return false;\n }\n log.debug('actually publishing', topic);\n this.mqtt.publish(topic,\n value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n {retain: true});\n return true;\n }\n\n /** Send all items in the queue in sequence, if any and if not already\n running. */\n // async _processQueue() {\n // if (this._processing) return; // already running (and probably waiting)\n //\n // this._processing = true;\n // while (this.publishQueue.length > 0) {\n // const {topic, value} = this.publishQueue.shift();\n // await this._actuallyPublish(topic, value);\n // }\n // this._processing = false;\n // }\n\n // when using Map\n _processQueue_rec(cb) {\n if (this.publishQueue.size > 0) {\n const [topic, value] = this.publishQueue.entries().next().value;\n // this.publishQueue.delete(topic);\n // this._actuallyPublish(topic, value).then(\n // () => this._processQueue_rec(cb),\n // cb); // always call cb, even in rejection case\n if (this._actuallyPublish(topic, value)) {\n this.publishQueue.delete(topic);\n this._processQueue_rec(cb);\n } else {\n // try again soon\n setTimeout(() => this._processQueue_rec(cb), 5000);\n }\n } else {\n cb();\n }\n }\n\n _processQueue() {\n if (this._processing) return; // already running (and probably waiting)\n\n this._processing = true; // semaphore\n this._processQueue_rec(() => this._processing = false);\n }\n\n /** Set delay between processing of publishing queue in milliseconds. This\n allows you to effectively throttle the rate at which this instance will\n publish changes. Note that updates to a topic already in the queue will not\n cause multiple publications. Only the latest value will be published.\n @param {number} [delay] - Number of milliseconds to wait between processing\n of publish queue.\n */\n setThrottle(delay) {\n this._processQueueThrottled =\n _.throttle(this._processQueue.bind(this), delay);\n }\n\n /** Clear the set throttling delay. */\n clearThrottle() {\n delete this._processQueueThrottled;\n }\n\n addToQueue(topic, value) {\n // this.publishQueue.push({topic, value});\n this.publishQueue.set(topic, value);\n }\n\n /** Add to publication queue */\n _enqueue(topic, value) {\n log.debug('enqueuing', topic);\n this.addToQueue(topic, value);\n if (this._processQueueThrottled) {\n this._processQueueThrottled();\n } else {\n this._processQueue();\n }\n // yes, this is optimistic, but if we don't, then upcoming changes\n // may not work as expected (e.g., when switching from flat to atomic to flat)\n const path = topicToPath(topic);\n this.publishedMessages.updateFromArray([...path, specialKey],\n value == null ? null : clone(value));\n }\n\n /** Register a listener for path in data. Make sure to populate the data\n before calling this or set the data all at once afterwards.\n\n With option \"atomic\" this will always send the whole sub-document,\n not flat changes. Useful, e.g., for desiredPackages, see\n https://github.com/chfritz/transitive/issues/85.\n\n @return true if publication added (false, e.g., when already present)\n */\n publish(topic, options = {atomic: false}) {\n topic = ensureHashSuffix(topic);\n\n if (_.isEqual(this.publishedPaths[topic], options)) {\n return false;\n // avoid double subscription\n }\n this.publishedPaths[topic] = options;\n\n if (options.atomic) {\n // this case is quite simple\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n // do not re-publish changes received from external:\n if (tags?.external) return;\n\n log.debug('processing change (atomic)', key, topic);\n // instantiate topic according to key (topic may have wildcards)\n const topicWithoutHash = topic.slice(0, topic.length - 2);\n const groundedTopic = pathToTopic(\n // get length of topic (how many levels of selectors), get that many\n // levels from key prefix\n topicToPath(key).slice(0, topicToPath(topicWithoutHash).length)\n );\n this._enqueue(groundedTopic, this.data.getByTopic(groundedTopic));\n });\n return true;\n }\n\n this.mqtt.subscribe(topic);\n\n // second: keep them up to date by publishing updates as changes happen\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n if (tags?.external) return;\n\n log.debug('processing change', key);\n\n /* First: establish clarity by ensuring that the object defined by the\n currently present retained messages under this path accurately reflect\n the current value of this.data (and if not, publish what is necessary to\n create consistency). */\n // first, clear/replace all messages below or above this sub-path (if any)\n const path = topicToPath(key);\n\n // Check flat to atomic\n const publishedSub = this.publishedMessages.get(path);\n _.each(publishedSub, (oldSubVal, oldSubKey) => {\n if (oldSubKey == specialKey) return true;\n // We are going from flat to atomic, i.e., we are publishing at a\n // higher level than before: clear out old sub-keys.\n\n // Find all sub-sub-keys that end in `specialKey`:\n const toClear = Object.keys(toFlatObject(oldSubVal))\n .filter(subkey => subkey.endsWith(specialKey));\n\n log.debug('flat->atomic: ', {toClear}, oldSubKey);\n // Clear them all:\n toClear.forEach(oldSubSubKey => {\n const oldKey = oldSubSubKey.slice(0, -(specialKey.length + 1));\n const clearKey = `${key}/${oldSubKey}/${oldKey}`\n // log.debug('flat->atomic: clear', clearKey);\n this._enqueue(clearKey, null);\n });\n });\n\n // Check atomic to flat\n const published = this.publishedMessages.get();\n visitAncestor(published, path.slice(0, -1), (subObj, prefix) => {\n const oldVal = subObj[specialKey];\n if (oldVal && _.isObject(oldVal)) {\n log.debug('atomic->flat', {oldVal});\n // A parent topic has been published. We are going from atomic to\n // separate values: need to transform existing sub-document to flat\n // values.\n\n // Remove the old published (atomic) message:\n const prefixTopic = pathToTopic(prefix);\n this._enqueue(prefixTopic, null);\n\n // Now re-add as separate flat messages\n const flat = toFlatObject(oldVal);\n _.each(flat, (flatValue, flatKey) => {\n const oldFlatKey = `${prefixTopic}${flatKey}`;\n this._enqueue(oldFlatKey, flatValue);\n })\n }\n });\n\n /* We need to first wait until all of the above messages are out;\n otherwise replacing an atomic `/a = {c: 1}` with `/a/c = 2` would create\n a race condition where it is not clear which message, the replacement\n c = 1 or the new c = 2, would be sent last (and hence retained). That's\n why we use a publishing queue in this class.\n */\n this._enqueue(key, value);\n return true;\n });\n }\n\n /** Run all registered hooks before disconnecting */\n beforeDisconnect() {\n this.beforeDisconnectHooks.forEach(fn => fn(this));\n }\n\n /** Register a new hook to be called before disconnecting */\n onBeforeDisconnect(fn) {\n this.beforeDisconnectHooks.push(fn);\n }\n\n /* --------------------------------------------------------------------------\n * Remote Procedure Calls (RPC)\n */\n\n /* Handle RPC requests */\n async handleRPCRequest(topic, json) {\n log.debug('handling RPC request for', topic, json);\n const handler = this.rpcHandlers[topic];\n const result = handler(json.args);\n\n const responseTopic = `${topic.replace('/request', '/response')}/${json.id}`;\n\n if (result instanceof Promise) {\n result.then( resultValue => this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result: resultValue }),\n {retain: false, qos: 2}));\n } else {\n this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result }),\n {retain: false, qos: 2});\n }\n }\n\n /* Handle RPC response */\n handleRPCResponse(topic, json) {\n log.debug('handle RPC response', topic, json);\n this.rpcCallbacks[topic](json.result);\n delete this.rpcCallbacks[topic];\n this.mqtt.unsubscribe(topic);\n }\n\n /** Register an RPC request handler. Example:\n * ```js\n * mqttSync.register('/mySquare', arg => {\n * log.debug('running /mySquare with args', arg);\n * return arg * arg;\n * });\n * ```\n * Note that the command topic needs to be in the capabilities namespace like\n * any other topic. In robot capabilities, as usual, these can start in `/`\n * because the local mqtt bridge operated by the robot agent will place all\n * topics in their respective namespace. In the cloud and on the web you will\n * need to use the respective namespace, i.e.,\n * `/orgId/deviceId/@scope/capName/capVersion/`.\n *\n * #### Async/Await\n * Yes, you can make the handler `async` and use `await` inside of it. This\n * will be handled correctly, i.e., MqttSync will await the result of the\n * handler before responding to the RPC request client.\n */\n register(command, handler) {\n log.debug('registering RPC handler for', command);\n const requestTopic = `${command}/request`;\n\n this.rpcHandlers[requestTopic] = handler;\n this.mqtt.subscribe(requestTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC topic ${requestTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC topic ${requestTopic}`);\n }\n });\n }\n\n /** Make an RPC request. Example:\n * ```js\n * mqttSync.call('/mySquare', 11, result => {\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * });\n * ```\n * Alternative you can omit the callback and use async/await:\n * ```js\n * const result = await mqttSync.call('/mySquare', 11);\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * ```\n * See the note about namespaces in `register`.\n *\n * Note: It is your responsibility to only call methods that exist (have been\n * registered). Calling a non-existent command just hangs.\n */\n call(command, args, callback = undefined) {\n const id = getRandomId();\n\n const responseTopic = `${command}/response/${id}`;\n this.mqtt.subscribe(responseTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC response topic ${responseTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC response topic ${responseTopic}`);\n }\n });\n\n const requestTopic = `${command}/request`\n log.debug('calling RPC', requestTopic);\n this.mqtt.publish(requestTopic, JSON.stringify({ id, args }),\n {retain: false, qos: 2});\n\n if (callback) {\n this.rpcCallbacks[responseTopic] = callback;\n } else {\n return new Promise((resolve, reject) => {\n this.rpcCallbacks[responseTopic] = resolve;\n });\n }\n }\n}\n\nmodule.exports = MqttSync;\n", "export * from './client/shared.jsx';\nexport * from './client/hooks.jsx';\nexport * from './client/client';\n", "import React, { useState, useEffect, useMemo, useRef } from 'react';\nimport { Button, Accordion, AccordionContext, Card, Badge }\n from 'react-bootstrap';\nimport ReactWebComponent from './react-web-component';\n\nimport { parseCookie, decodeJWT } from './client';\nimport { useCapability } from './hooks';\n\nconst styles = {\n badge: {\n width: '4em'\n },\n code: {\n color: '#700',\n borderLeft: '3px solid #aaa',\n padding: '0.5em 0px 0.5em 2em',\n backgroundColor: '#f0f0f0',\n borderRadius: '4px',\n marginTop: '0.5em',\n },\n inlineCode: {\n color: '#700',\n margin: '0px 0.5em 0px 0.5em',\n }\n};\n\nconst levelBadges = [\n <Badge bg=\"success\" style={styles.badge}>OK</Badge>,\n <Badge bg=\"warning\" style={styles.badge}>Warn</Badge>,\n <Badge bg=\"danger\" style={styles.badge}>Error</Badge>,\n <Badge bg=\"secondary\" style={styles.badge}>Stale</Badge>,\n];\n\n/* The right badge for the level */\nexport const LevelBadge = ({level}) => levelBadges[level] || <span>{level}</span>;\n\n/** Reusable component for showing code */\nexport const Code = ({children}) => <pre style={styles.code}>\n {children}\n</pre>;\n\nexport const InlineCode = ({children}) => <tt style={styles.inlineCode}>\n {children}\n</tt>;\n\n\nconst intervals = {};\n\nexport const TimerContext = React.createContext({});\nexport const Timer = ({duration, onTimeout, onStart, setOnDisconnect, children}) => {\n duration = duration || 60;\n const [timer, setTimer] = useState(duration);\n const [running, setRunning] = useState(false);\n const id = useMemo(() => Math.random().toString(36).slice(2), []);\n\n const stop = () => {\n console.log('stopping timer for', id);\n onTimeout && setTimeout(onTimeout, 1);\n clearInterval(intervals[id]);\n intervals[id] = null;\n setRunning(false);\n };\n\n const startTimer = () => {\n const interval = intervals[id];\n console.log(interval, intervals, timer);\n if (!interval && timer > 0) {\n setRunning(true);\n intervals[id] = setInterval(() =>\n setTimer(t => {\n if (--t > 0) {\n return t;\n } else {\n stop();\n }\n }), 1000);\n onStart && setTimeout(onStart, 1);\n }\n\n return stop;\n };\n\n useEffect(() => { timer > 0 && !running && startTimer() }, [timer]);\n\n useEffect(() => stop, []);\n\n setOnDisconnect && setOnDisconnect(() => {\n // call on disconnect of the web component\n stop()\n });\n\n const reset = () => setTimer(duration);\n\n return <TimerContext.Provider value={{reset, duration, timer}}>\n {timer > 0 ? <div>\n {children}\n {timer < 60 && <div>Timeout in: {timer} seconds</div>}\n </div> :\n <div>Timed out. <Button onClick={reset}>\n Resume\n </Button>\n </div>}\n </TimerContext.Provider>;\n};\n\n\n/** Dynamically load and use the Transitive web component specified in the JWT.\n* Embedding Transitive components this way also enables the use of functional\n* and object properties, which get lost when using the custom element (Web\n* Component) because HTML attributes are strings.\n* Example:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* myconfig={{a: 1, b: 2}}\n* onData={(data) => setData(data)}\n* onclick={() => { console.log('custom click handler'); }}\n* />\n* ```\n*\n* Always loads the capability specified in the JWT and will default to the\n* main component for that JWT (`-device` or `-fleet`). To specify a secondary\n* component offered by the capability specify `component`, e.g., to load\n* `webrtc-video-supervisor` instead of `webrtc-video-device`, provide a device\n* JWT for webrtc-video and use:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* component='webrtc-video-supervisor'\n* auto=\"true\"\n* />\n* ```\n*/\nexport const TransitiveCapability = ({\n jwt, host = 'transitiverobotics.com', ssl = true, ...config\n }) => {\n\n const assertPresent = (value, name) => {\n if (!value) throw new Error(`JWT is missing ${name}`);\n };\n\n const {id, device, capability} = decodeJWT(jwt);\n // Throw an error when any of the above payload is missing\n assertPresent(id, 'id');\n assertPresent(device, 'device');\n assertPresent(capability, 'capability');\n\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n const component = config.component || name;\n\n const { loaded } = useCapability({\n capability,\n name,\n userId: id || config.userId, // accept both id and userId, see #492\n deviceId: device,\n host,\n ssl\n });\n\n const ref = useRef();\n // Attach functional and object properties to the component when ready and\n // on change\n useEffect(() => {\n ref.current?.instance?.setState(s =>\n ({ ...s, id, jwt, host, ssl, ...config }));\n }, [ref.current, loaded, id, jwt, host, ssl, ...Object.values(config)]);\n\n // Disrupt the reactive chain of the MutationObserver to the customElement,\n // so we are not competing with it for updating the props.\n const propClone = useMemo(() => ({id, jwt, host, ssl, ...config}), []);\n\n if (!loaded) return <div>Loading {name}</div>;\n return React.createElement(component, {...propClone, ref});\n };\n\n\n/** A simple error boundary. Usage:\n* ```jsx\n* <ErrorBoundary message=\"Something went wrong\">\n* <SomeFlakyComponent />\n* </ErrorBoundary>\n* ```\n*/\nexport class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n hasError: false,\n messages: [],\n };\n }\n\n static getDerivedStateFromError(error) {\n return { hasError: true };\n }\n\n componentDidCatch(error, errorInfo) {\n console.warn('ErrorBoundary caught:', error, errorInfo);\n this.setState(({messages}) => ({messages: [...messages, error.message]}));\n }\n\n render() {\n return (this.state.hasError ? <div>\n Error: {this.props.message || this.state.messages?.join(', ')\n || 'Something went wrong here.'}\n </div>\n : this.props.children);\n }\n};\n\n\nexport const CapabilityContext = React.createContext({});\n\n/* Only used internally: the actual context provider, given the loaded module */\nconst LoadedCapabilityContextProvider = (props) => {\n const {children, jwt, id, host, ssl, loadedModule} = props;\n\n const context = loadedModule.provideContext?.({\n jwt, id, host, ssl, appReact: React\n });\n\n return <CapabilityContext.Provider value={{ ...context }}>\n {children}\n </CapabilityContext.Provider>;\n};\n\n/**\n* Context provider for capabilities. Use this to access the front-end API\n* provided by some capabilities. Example:\n* ```jsx\n* <CapabilityContextProvider jwt={jwt}>\n* <MyROSComponent />\n* </CapabilityContextProvider>\n* ```\n* where `jwt` is a JWT for a capability that exposes a front-end API. Then use\n* `useContext` in `MyROSComponent` to get the exposed data and functions, e.g.:\n* ```jsx\n* const MyROSComponent = () => {\n* const { ready, subscribe, data } = useContext(CapabilityContext);\n* // When ready, subscribe to the `/odom` topic in ROS1\n* useEffect(() => { ready && subscribe(1, '/odom'); }, [ready]);\n* return <pre>{JSON.stringify(data, true, 2)}</pre>;\n* }\n* ```\n* Where `ready`, `subscribe`, and `data` are reactive variables and functions\n* exposed by the capability of the provided JWT. In this example, the latest\n* message from the subscribed ROS topics will be available in the capabilities\n* namespace in `data`.\n* @param {object} props\n*/\nexport const CapabilityContextProvider =\n ({children, jwt, host = undefined, ssl = undefined}) => {\n\n const {id, device, capability} = decodeJWT(jwt);\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n\n const {loaded, loadedModule} = useCapability({\n capability,\n name,\n userId: id,\n deviceId: device,\n appReact: React,\n host,\n ssl\n });\n\n if (!loadedModule) return <div>Loading {capability}</div>;\n return <LoadedCapabilityContextProvider {...{jwt, id, host, ssl, loadedModule}}>\n {children}\n </LoadedCapabilityContextProvider>;\n };\n\n\n/* whether or not the given react component allows refs, i.e., is either\n * a functional component wrapped with forwardRef or a class component */\nconst componentPermitsRefs = (Component) =>\n (Component.$$typeof == Symbol.for('react.forward_ref'))\n || Component.prototype?.render;\n\n\n/** Create a WebComponent from the given react component and name that is\n* reactive to all attributes. Used in web capabilities. Example:\n* ```js\n* createWebComponent(Diagnostics, 'health-monitoring-device', TR_PKG_VERSION);\n* ```\n*/\nexport const createWebComponent = (Component, name, version = '0.0.0',\n options = {}) => {\n\n // Only create a ref if the component accepts it. This avoids an ugly\n // error in the console when trying to give a ref to a non-forwardRef-wrapped\n // functional component.\n const compRef = componentPermitsRefs(Component) ? React.createRef() : null;\n\n class Wrapper extends React.Component {\n\n onDisconnect = null;\n state = {};\n\n componentDidMount() {\n this.props._element.instance = this;\n this.webComponentConstructed(this.props._element);\n this.props._element.callLifeCycleHook('connectedCallback');\n }\n\n /* function used by `Component` to register a onDisconnect handler */\n setOnDisconnect(fn) {\n this.onDisconnect = fn;\n }\n\n webComponentConstructed(instance) {\n // Observe all changes to attributes and update React state from it\n const observer = new MutationObserver((mutationRecords) => {\n const update = {};\n mutationRecords.forEach(({attributeName}) => {\n update[attributeName] = instance.getAttribute(attributeName);\n });\n this.setState(old => ({...old, ...update}));\n }).observe(instance, { attributes: true });\n }\n\n webComponentDisconnected() {\n // This ensures that the react component unmounts and all useEffect\n // cleanups are called.\n this.setState({_disconnected: true});\n try {\n this.onDisconnect && this.onDisconnect();\n } catch (e) {\n console.log('Error during onDisconnect of web-component', e);\n }\n }\n\n /* method exposed to the wrapped component via prop that allows setting\n * the \"config\" state variable inside the wrapper (not the component\n * itself). This config is retrieved by the portal for inclusion in the\n * embedding instructions. */\n setConfig(config) {\n this.setState({config});\n }\n\n render() {\n const stylesheets = options.stylesheets || [\n // 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css'\n // Bootstrap 5.3.2 css scoped to `.transitive-bs-root`:\n 'https://cdn.jsdelivr.net/gh/transitiverobotics/transitive-utils@0.8.3/web/css/bootstrap_transitive-bs-root.min.css'\n ];\n\n return <div id={`cap-${name}-${version}`}\n className={options.className || 'transitive-bs-root'}>\n <style>\n {stylesheets.map(url => `@import url(${url});`)}\n </style>\n\n {!this.state._disconnected &&\n <Component ref={compRef}\n {...this.props}\n // Important to keep state *after* props for reactivity to work\n {...this.state}\n setOnDisconnect={this.setOnDisconnect.bind(this)}\n setConfig={this.setConfig.bind(this)}\n />}\n </div>;\n }\n };\n\n return ReactWebComponent.create(Wrapper, name, options.shadowDOM || false,\n compRef);\n };\n", "// It is OK to use paths outside of this package because webpack will bundle them\nexport * from '../../common/common.js';\nexport * from '../../common/datacache';\nimport MS from '../../common/MqttSync.js';\nexport const MqttSync = MS;\n\n// moved to common\n// export const decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n\n/** parse document cookies */\nexport const parseCookie = str =>\n str.split(';')\n .map(v => v.split('='))\n .reduce((acc, v) => {\n acc[decodeURIComponent(v[0].trim())] =\n v[1] && decodeURIComponent(v[1].trim());\n return acc;\n }, {});\n\n/** get or post (if body given) json */\nexport const fetchJson = (url, callback, options = {}) => {\n fetch(url, {\n method: options.method || (options.body ? 'post' : 'get'),\n mode: 'cors',\n cache: 'no-cache',\n // Maybe we'll need this (when embedding)?\n // credentials: 'same-origin', // include, *same-origin, omit\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers\n },\n redirect: 'follow',\n referrerPolicy: 'no-referrer',\n body: options.body ? JSON.stringify(options.body) : undefined\n }).then(res => {\n const error = !res.ok &&\n `fetching ${url} failed: ${res.status} ${res.statusText}`;\n res.json()\n .then(data => callback(error, data))\n .catch(err => {\n throw new Error(err);\n });\n }).catch((error) => callback(`error: ${error}`));\n};\n", "import React, { useState, useEffect, useMemo } from 'react';\nimport _ from 'lodash';\n// import mqtt1 from 'mqtt';\nimport mqtt from 'mqtt/dist/mqtt.esm';\n\nimport { decodeJWT, getLogger, clone, pathToTopic, mergeVersions, topicToPath }\n from './client';\nconst MqttSync = require('../../common/MqttSync');\n\nconst log = getLogger('utils-web/hooks');\nlog.setLevel('info');\n\nconst RECONNECT_PERIOD_DEFAULT = 1000; // default time until mqtt retries connecting\nconst RECONNECT_PERIOD_MAX = 20000; // max retry time (after dynamic backoff)\n\n/** Hook for using MqttSync in React.\n* @returns {object} An object `{data, mqttSync, ready, StatusComponent, status}`\n* where:\n* `data` is a reactive data source in React containing all the data received by\n* mqttsync,\n* `mqttSync` is the MqttSync object itself,\n* `ready` indicates when mqttSync is ready to be used (connected and received\n* successfully subscribed to mqtt system heartbeats)\n*/\nexport const useMqttSync = ({jwt, id, mqttUrl, appReact}) => {\n const { useState, useRef, useEffect } = appReact || React;\n\n const [status, setStatus] = useState('connecting');\n const [mqttSync, setMqttSync] = useState();\n const [data, setData] = useState({});\n // True once the subscription to the system heartbeat has been granted.\n const [heartbeatGranted, setHeartbeatGranted] = useState(false);\n\n useEffect(() => {\n const payload = decodeJWT(jwt);\n\n // pre-check validity of JWT, don't use if expired\n const { validity, iat } = payload;\n if (!validity || !iat || (iat + validity) * 1e3 < Date.now()) {\n const error = 'The provided JWT is invalid or expired.';\n log.warn(error, payload);\n setStatus(`error: ${error}`);\n return;\n }\n\n /** Implement dynamic backoff when we fail to connect. */\n let reconnectPeriod = RECONNECT_PERIOD_DEFAULT; // default to start with\n const transformWsUrl = (url, options, client) => {\n options.reconnectPeriod = reconnectPeriod;\n return url;\n }\n\n log.debug('(re-)create mqtt client');\n const client = mqtt.connect(mqttUrl, {\n username: JSON.stringify({id, payload}),\n password: jwt,\n transformWsUrl\n });\n\n // Increase backoff with each close (since we can't actually detect auth\n // errors); stop reconnecting if JWT is invalid by now.\n client.on('close', () => {\n reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX);\n\n if ((iat + validity) * 1e3 < Date.now()) {\n const error = 'MQTT connection closed and the JWT is expired by now. Not reconnecting.';\n log.warn(error, payload);\n setStatus(`error: ${error}`);\n // give up, do not try to reconnect; user needs to provide a fresh JWT.\n client.end();\n } else {\n const msg = `reconnect in ${reconnectPeriod / 1000} s`;\n log.info(msg);\n setStatus(msg);\n }\n });\n\n // reset to default after a successful connection\n client.on('connect', () => {\n reconnectPeriod = RECONNECT_PERIOD_DEFAULT;\n log.debug('MQTT (re-)connected');\n setStatus('connected');\n });\n\n client.once('connect', () => {\n const mqttSyncClient = new MqttSync({\n mqttClient: client,\n ignoreRetain: true,\n onHeartbeatGranted: () => setHeartbeatGranted(true)\n });\n setMqttSync(mqttSyncClient);\n\n // Update data on change. Note: need to clone object to force reaction\n mqttSyncClient.data.subscribe(_.throttle(() =>\n setData(clone(mqttSyncClient.data.get())), 50));\n });\n\n client.on('error', (error) => {\n log.error(error);\n setStatus(`error: ${error}`);\n });\n\n return () => {\n log.info('cleaning up useMQTTSync');\n if (mqttSync && mqttSync.beforeDisconnect) {\n mqttSync.beforeDisconnect();\n mqttSync.waitForHeartbeatOnce(() => client.end());\n } else {\n client.end();\n }\n };\n }, [jwt, id]);\n\n return {\n status,\n // ready: status == 'connected',\n ready: heartbeatGranted,\n StatusComponent: () => <div>{status}</div>,\n mqttSync, // Note: mqttSync.data is not reactive.\n data, // This is a reactive data-source (to use meteor terminology).\n };\n};\n\n/** Hook for using Transitive in React. Connects to MQTT, establishes sync, and\n* exposes reactive `data` state variable. */\nexport const useTransitive =\n ({jwt, id, capability, versionNS, appReact,\n host = 'transitiverobotics.com', ssl = true }) => {\n\n const [scope, capabilityName] = capability.split('/');\n\n const { device } = decodeJWT(jwt);\n const prefixPath = [id, device, scope, capabilityName];\n const prefix = pathToTopic(prefixPath);\n const prefixPathVersion = [...prefixPath, versionNS];\n const prefixVersion = pathToTopic(prefixPathVersion);\n\n const mqttUrl = `${ssl && JSON.parse(ssl) ? 'wss' : 'ws'}://mqtt.${host}`;\n const fromMqttSync = useMqttSync({ jwt, id, mqttUrl, appReact });\n\n return {...fromMqttSync, device, prefixPath, prefix, prefixPathVersion,\n prefixVersion};\n };\n\n\n/** Subscribe to MqttSync topics using the provided JWT. This will\n* automatically find which version of the capability named in the JWT is running\n* on the device of the JWT and get the data for that version.\n*\n* Example usage (with webrtc-video):\n*\n* ```js\n* const { agentStatus, topicData } = useTopics({ jwt, topics: [\n* '/options/videoSource',\n* '/stats/+/log/'\n* ]});\n* ```\n*\n* @param {object} options An object containing:\n* `JWT`: A list of subtopics of the capability named in the JWT.\n* `topics`: A list of subtopics of the capability named in the JWT.\n* @returns {object} An object `{data, mqttSync, ready, agentStatus, topicData}`\n* where:\n* `agentStatus` is the `status` field of the running robot agent, including\n* heartbeat and runningPackages, and\n* `topicData` is the data for the selected topics of the capability\n*/\nexport const useTopics = ({jwt, host = 'transitiverobotics.com', ssl = true,\n topics = [], appReact}) => {\n\n const { useState, useEffect } = appReact || React;\n\n // We need to make sure we don't resubscribe (below) when this function\n // is called with the same content of `topics` but a different object.\n const [topicList, setTopicList] = useState();\n !_.isEqual(topicList, topics) && setTopicList(topics);\n\n const {device, id, capability} = decodeJWT(jwt);\n if (device == '_fleet') {\n log.warn('useTopics only works for device JWTs, not _fleet ones');\n return;\n }\n\n const agentPrefix = `/${id}/${device}/@transitive-robotics/_robot-agent/+/status`;\n\n const {mqttSync, data, status, ready, StatusComponent} =\n useMqttSync({jwt, id, mqttUrl: `ws${ssl ? 's' : ''}://mqtt.${host}`, appReact});\n\n useEffect(() => {\n if (ready) {\n mqttSync.subscribe(agentPrefix, (err) => err && console.warn(err));\n }\n }, [mqttSync, ready]);\n\n const agentStatus = mergeVersions(\n data[id]?.[device]['@transitive-robotics']['_robot-agent'], 'status').status;\n const runningPackages = agentStatus?.runningPackages;\n\n const [scope, capName] = capability.split('/');\n const versions = runningPackages?.[scope]?.[capName];\n const runningVersion = versions && Object.values(versions).filter(Boolean)[0];\n const prefix = `/${id}/${device}/${capability}/${runningVersion}`;\n\n useEffect(() => {\n log.debug('topics', topics);\n if (runningVersion) {\n topics.forEach(topic => {\n log.debug(`subscribing to ${prefix}${topic}`);\n mqttSync.subscribe(`${prefix}${topic}`,\n (err) => err && log.warn(err));\n });\n }\n }, [topicList, runningVersion, mqttSync]);\n\n const topicData = _.get(data, topicToPath(prefix));\n // log.debug(data, agentStatus, topicData);\n\n return {data: data?.[id]?.[device], mqttSync, agentStatus, topicData};\n };\n\n\nconst listeners = {};\nconst loadedModules = {};\n/** Hook to load a Transitive capability. Besides loading the custom element,\n* this hook also returns any functions and objects the component exports in\n* `loadedModule`. Example:\n* ```js\n* const {loaded, loadedModule} = useCapability({\n* capability: '@transitive-robotics/terminal',\n* name: 'mock-device',\n* userId: 'user123',\n* deviceId: 'd_mydevice123',\n* });\n* ```\n*/\nexport const useCapability = ({ capability, name, userId, deviceId,\n host = 'transitiverobotics.com', ssl = true, appReact\n }) => {\n const { useState, useEffect } = appReact || React;\n\n const [returns, setReturns] = useState({ loaded: false });\n\n // called when loaded\n const done = (message, theModule) => {\n log.debug(`custom component ${name}: ${message}`);\n loadedModules[name] = theModule;\n setReturns(x => ({...x, loadedModule: theModule, loaded: !!theModule}));\n };\n\n /** set the returns for all listeners */\n const notifyListeners = (...args) => listeners[name].forEach(l => l(...args));\n\n useEffect(() => {\n log.debug(`loading custom component ${name}`);\n\n if (loadedModules[name]) {\n return done('already loaded', loadedModules[name]);\n }\n if (listeners[name]) {\n log.debug('already loading');\n // get notified when loading completes\n listeners[name].push(done);\n return;\n }\n listeners[name] = [done];\n\n const baseUrl = `http${ssl ? 's' : ''}://portal.${host}`;\n const params = new URLSearchParams({ userId, deviceId });\n // filename without extension as we'll try multiple\n const fileBasename = `${baseUrl}/running/${capability}/dist/${name}`;\n\n /* Since some users use webpack and webpack is stupid, we need to use\n this magic comment for it to ignore these (remote) requests, see:\n https://webpack.js.org/api/module-methods/#webpackignore. */\n import(/* webpackIgnore: true */\n `${fileBasename}.esm.js?${params.toString()}`).then(\n esm => notifyListeners('loaded esm', esm),\n error => {\n log.warn(`No ESM module found for ${name}, loading iife`, error);\n import(/* webpackIgnore: true */\n `${fileBasename}.js?${params.toString()}`).then(\n iife => notifyListeners('loaded iife', iife),\n error => log.error(`Failed to load ${name} iife`, error));\n });\n }, [capability, name, userId, deviceId]);\n\n return returns;\n };\n\n\n"],
5
+ "mappings": "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",
6
+ "names": ["module", "module", "attribute", "module", "React", "styles", "module", "_", "topicToPath", "pathToTopic", "module", "module", "_", "topicToPath", "pathToTopic", "getLogger", "clone", "decodeJWT", "prefix", "mergeVersions", "module", "_", "topicToPath", "pathToTopic", "module", "module", "_", "topicToPath", "pathToTopic", "getLogger", "mergeVersions", "log", "clone", "MqttSync", "value", "err", "import_react", "MS", "MqttSync", "useState", "useRef", "useEffect", "React", "client", "mqtt", "_", "error", "React", "name", "React", "ReactWebComponent"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transitive-sdk/utils-web",
3
- "version": "0.14.4",
3
+ "version": "0.14.6",
4
4
  "description": "Web utils for the Transitive framework",
5
5
  "homepage": "https://transitiverobotics.com",
6
6
  "repository": {