@trillboards/edge-sdk 0.2.3 → 0.2.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/README.md +4 -3
- package/deploy/docker/Dockerfile.cloud-sense +117 -0
- package/deploy/docker/Dockerfile.cpu +30 -21
- package/deploy/docker/Dockerfile.cuda +30 -21
- package/deploy/docker/Dockerfile.openvino +30 -20
- package/deploy/docker/README.md +9 -4
- package/deploy/docker/connector-entrypoint.sh +122 -0
- package/deploy/helm/README.md +1 -1
- package/deploy/k8s/daemonset.yaml +1 -1
- package/deploy/macos/README.md +161 -0
- package/deploy/macos/TrillboardsSetupApp.m +603 -0
- package/deploy/macos/build-macos-pkg.sh +588 -0
- package/deploy/macos/com.trillboards.edge.plist +62 -0
- package/deploy/macos/com.trillboards.litertlm.plist +45 -0
- package/deploy/macos/pair.command +519 -0
- package/deploy/macos/scripts/ensure-litertlm.sh +62 -0
- package/deploy/macos/scripts/postinstall +153 -0
- package/deploy/macos/scripts/setup-litertlm.sh +272 -0
- package/deploy/macos/test-install-pair.sh +383 -0
- package/deploy/macos/test-setup-litertlm-reinstall.sh +109 -0
- package/deploy/systemd/install.sh +25 -15
- package/deploy/systemd/trillboards-edge.service +4 -1
- package/deploy/windows/README.md +70 -0
- package/deploy/windows/build-windows.ps1 +225 -0
- package/deploy/windows/bundle-windows-installer.ps1 +153 -0
- package/deploy/windows/check-feeds.js +26 -0
- package/deploy/windows/e2e/fixtures/person.jpg +0 -0
- package/deploy/windows/e2e/test-local-sense.ps1 +185 -0
- package/deploy/windows/install-update.ps1 +101 -0
- package/deploy/windows/installer.nsi +138 -0
- package/deploy/windows/register-litertlm-task.ps1 +42 -0
- package/deploy/windows/register-task.ps1 +44 -0
- package/deploy/windows/run-connector.ps1 +69 -0
- package/deploy/windows/setup-litertlm.ps1 +361 -0
- package/deploy/windows/stop-existing.ps1 +72 -0
- package/deploy/windows/trillboards-edge-task.vbs +25 -0
- package/deploy/windows/trillboards-edge.cmd +33 -0
- package/deploy/windows/trillboards-pair.cmd +276 -0
- package/deploy/windows/trillboards-setup.ps1 +456 -0
- package/deploy/windows/trillboards-setup.vbs +13 -0
- package/dist/AudienceAnalyzeClient.d.ts +136 -0
- package/dist/AudienceAnalyzeClient.d.ts.map +1 -0
- package/dist/AudienceAnalyzeClient.js +246 -0
- package/dist/AudienceAnalyzeClient.js.map +1 -0
- package/dist/ChannelProber.d.ts +150 -0
- package/dist/ChannelProber.d.ts.map +1 -0
- package/dist/ChannelProber.js +887 -0
- package/dist/ChannelProber.js.map +1 -0
- package/dist/CloudEscalationPolicy.d.ts +143 -0
- package/dist/CloudEscalationPolicy.d.ts.map +1 -0
- package/dist/CloudEscalationPolicy.js +137 -0
- package/dist/CloudEscalationPolicy.js.map +1 -0
- package/dist/CloudSensingManager.d.ts +533 -0
- package/dist/CloudSensingManager.d.ts.map +1 -0
- package/dist/CloudSensingManager.js +1254 -0
- package/dist/CloudSensingManager.js.map +1 -0
- package/dist/DiscoveryReportClient.d.ts +66 -0
- package/dist/DiscoveryReportClient.d.ts.map +1 -0
- package/dist/DiscoveryReportClient.js +85 -0
- package/dist/DiscoveryReportClient.js.map +1 -0
- package/dist/EdgeAgent.d.ts +12 -2
- package/dist/EdgeAgent.d.ts.map +1 -1
- package/dist/EdgeAgent.js +122 -65
- package/dist/EdgeAgent.js.map +1 -1
- package/dist/LiteRtVlmProvider.d.ts +193 -0
- package/dist/LiteRtVlmProvider.d.ts.map +1 -0
- package/dist/LiteRtVlmProvider.js +436 -0
- package/dist/LiteRtVlmProvider.js.map +1 -0
- package/dist/MosaicSource.d.ts +108 -0
- package/dist/MosaicSource.d.ts.map +1 -0
- package/dist/MosaicSource.js +274 -0
- package/dist/MosaicSource.js.map +1 -0
- package/dist/OnvifClient.d.ts +83 -0
- package/dist/OnvifClient.d.ts.map +1 -0
- package/dist/OnvifClient.js +209 -0
- package/dist/OnvifClient.js.map +1 -0
- package/dist/PairClient.d.ts +106 -0
- package/dist/PairClient.d.ts.map +1 -0
- package/dist/PairClient.js +186 -0
- package/dist/PairClient.js.map +1 -0
- package/dist/RecorderAddressRecovery.d.ts +53 -0
- package/dist/RecorderAddressRecovery.d.ts.map +1 -0
- package/dist/RecorderAddressRecovery.js +359 -0
- package/dist/RecorderAddressRecovery.js.map +1 -0
- package/dist/SceneChangeDetector.d.ts +291 -0
- package/dist/SceneChangeDetector.d.ts.map +1 -0
- package/dist/SceneChangeDetector.js +682 -0
- package/dist/SceneChangeDetector.js.map +1 -0
- package/dist/SensingProfileClient.d.ts +59 -0
- package/dist/SensingProfileClient.d.ts.map +1 -0
- package/dist/SensingProfileClient.js +78 -0
- package/dist/SensingProfileClient.js.map +1 -0
- package/dist/SetupSessionClient.d.ts +114 -0
- package/dist/SetupSessionClient.d.ts.map +1 -0
- package/dist/SetupSessionClient.js +95 -0
- package/dist/SetupSessionClient.js.map +1 -0
- package/dist/VlmAdmissionGate.d.ts +126 -0
- package/dist/VlmAdmissionGate.d.ts.map +1 -0
- package/dist/VlmAdmissionGate.js +166 -0
- package/dist/VlmAdmissionGate.js.map +1 -0
- package/dist/autoSense.d.ts +216 -0
- package/dist/autoSense.d.ts.map +1 -0
- package/dist/autoSense.js +521 -0
- package/dist/autoSense.js.map +1 -0
- package/dist/cli.d.ts +27 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +511 -21
- package/dist/cli.js.map +1 -1
- package/dist/combinedSense.d.ts +128 -0
- package/dist/combinedSense.d.ts.map +1 -0
- package/dist/combinedSense.js +261 -0
- package/dist/combinedSense.js.map +1 -0
- package/dist/config.d.ts +351 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +99 -2
- package/dist/config.js.map +1 -1
- package/dist/connectorCadence.d.ts +135 -0
- package/dist/connectorCadence.d.ts.map +1 -0
- package/dist/connectorCadence.js +151 -0
- package/dist/connectorCadence.js.map +1 -0
- package/dist/dataDir.d.ts +33 -0
- package/dist/dataDir.d.ts.map +1 -0
- package/dist/dataDir.js +76 -0
- package/dist/dataDir.js.map +1 -0
- package/dist/deployedCadence.d.ts +167 -0
- package/dist/deployedCadence.d.ts.map +1 -0
- package/dist/deployedCadence.js +209 -0
- package/dist/deployedCadence.js.map +1 -0
- package/dist/deployedCadenceSource.d.ts +48 -0
- package/dist/deployedCadenceSource.d.ts.map +1 -0
- package/dist/deployedCadenceSource.js +74 -0
- package/dist/deployedCadenceSource.js.map +1 -0
- package/dist/diagnose.d.ts +1 -1
- package/dist/diagnose.d.ts.map +1 -1
- package/dist/diagnose.js +13 -12
- package/dist/diagnose.js.map +1 -1
- package/dist/discovery.d.ts +131 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +499 -0
- package/dist/discovery.js.map +1 -0
- package/dist/gemmaModelOta.d.ts +118 -0
- package/dist/gemmaModelOta.d.ts.map +1 -0
- package/dist/gemmaModelOta.js +291 -0
- package/dist/gemmaModelOta.js.map +1 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +41 -18
- package/dist/init.js.map +1 -1
- package/dist/keepAwake.d.ts +33 -0
- package/dist/keepAwake.d.ts.map +1 -0
- package/dist/keepAwake.js +54 -0
- package/dist/keepAwake.js.map +1 -0
- package/dist/legacyRecorderProfile.d.ts +20 -0
- package/dist/legacyRecorderProfile.d.ts.map +1 -0
- package/dist/legacyRecorderProfile.js +27 -0
- package/dist/legacyRecorderProfile.js.map +1 -0
- package/dist/localInferenceSchema.d.ts +132 -0
- package/dist/localInferenceSchema.d.ts.map +1 -0
- package/dist/localInferenceSchema.js +274 -0
- package/dist/localInferenceSchema.js.map +1 -0
- package/dist/localSenseE2eHarness.d.ts +101 -0
- package/dist/localSenseE2eHarness.d.ts.map +1 -0
- package/dist/localSenseE2eHarness.js +279 -0
- package/dist/localSenseE2eHarness.js.map +1 -0
- package/dist/localSensing.d.ts +268 -0
- package/dist/localSensing.d.ts.map +1 -0
- package/dist/localSensing.js +492 -0
- package/dist/localSensing.js.map +1 -0
- package/dist/modelIntegrity.d.ts +59 -0
- package/dist/modelIntegrity.d.ts.map +1 -0
- package/dist/modelIntegrity.js +165 -0
- package/dist/modelIntegrity.js.map +1 -0
- package/dist/pairVerify.d.ts +100 -0
- package/dist/pairVerify.d.ts.map +1 -0
- package/dist/pairVerify.js +296 -0
- package/dist/pairVerify.js.map +1 -0
- package/dist/qrScanner.d.ts +33 -0
- package/dist/qrScanner.d.ts.map +1 -0
- package/dist/qrScanner.js +103 -0
- package/dist/qrScanner.js.map +1 -0
- package/dist/runtimePaths.d.ts +10 -0
- package/dist/runtimePaths.d.ts.map +1 -0
- package/dist/runtimePaths.js +79 -0
- package/dist/runtimePaths.js.map +1 -0
- package/dist/sensingRunMode.d.ts +68 -0
- package/dist/sensingRunMode.d.ts.map +1 -0
- package/dist/sensingRunMode.js +346 -0
- package/dist/sensingRunMode.js.map +1 -0
- package/dist/setupMode.d.ts +98 -0
- package/dist/setupMode.d.ts.map +1 -0
- package/dist/setupMode.js +828 -0
- package/dist/setupMode.js.map +1 -0
- package/dist/setupProgress.d.ts +31 -0
- package/dist/setupProgress.d.ts.map +1 -0
- package/dist/setupProgress.js +173 -0
- package/dist/setupProgress.js.map +1 -0
- package/package.json +13 -4
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.defaultHttpGetter = exports.AutoSenseSupervisor = void 0;
|
|
37
|
+
exports.probeLiteRtLmHealth = probeLiteRtLmHealth;
|
|
38
|
+
exports.runAutoSense = runAutoSense;
|
|
39
|
+
const http = __importStar(require("http"));
|
|
40
|
+
const https = __importStar(require("https"));
|
|
41
|
+
const url_1 = require("url");
|
|
42
|
+
const config_1 = require("./config");
|
|
43
|
+
const sensingRunMode_1 = require("./sensingRunMode");
|
|
44
|
+
const gemmaModelOta_1 = require("./gemmaModelOta");
|
|
45
|
+
/**
|
|
46
|
+
* `auto-sense` — the ONE dispatching entrypoint for the BYO-CCTV connector that
|
|
47
|
+
* prefers ON-DEVICE local sensing (LiteRT-LM serving Gemma). Cloud inference is
|
|
48
|
+
* available only when the operator explicitly enables it.
|
|
49
|
+
*
|
|
50
|
+
* A fresh install may start before its model download finishes, so this probes
|
|
51
|
+
* `litert-lm serve` health with a SHORT timeout and:
|
|
52
|
+
* - healthy → runs the EXISTING local-sense path (no Vertex cost)
|
|
53
|
+
* - unhealthy/unreachable → waits and keeps probing without uploading frames
|
|
54
|
+
* - unhealthy + allowCloudFallback=true → runs the cloud-sense path
|
|
55
|
+
*
|
|
56
|
+
* It introduces NO new providers and NO duplicated sensing logic — the local
|
|
57
|
+
* and cloud run modes are reused verbatim. This module only owns the SELECTION.
|
|
58
|
+
*/
|
|
59
|
+
const DEFAULT_LITERT_LM_BASE_URL = 'http://localhost:9379';
|
|
60
|
+
/** Default model the local-sense path runs (must match config.localSensing.model). */
|
|
61
|
+
const DEFAULT_LITERT_LM_MODEL = 'gemma-4-E2B-it.litertlm';
|
|
62
|
+
/**
|
|
63
|
+
* Probe timeout. SHORT on purpose: on a box with no litert-lm the connect
|
|
64
|
+
* either refuses fast (ECONNREFUSED) or hangs, and readiness checks should not
|
|
65
|
+
* stall the connector behind a long wait.
|
|
66
|
+
*/
|
|
67
|
+
const DEFAULT_PROBE_TIMEOUT_MS = 2000;
|
|
68
|
+
/**
|
|
69
|
+
* Startup re-probe budget. A fresh install races litert-lm warmup/model-download
|
|
70
|
+
* (e.g. Windows `setup-litertlm.ps1` runs detached while the scheduled task can
|
|
71
|
+
* start right after pairing). A single probe at boot would pick cloud and never
|
|
72
|
+
* re-probe, stranding the box on cloud until a manual restart. So at startup we
|
|
73
|
+
* re-probe a few times before entering the steady waiting state. Default 4
|
|
74
|
+
* attempts.
|
|
75
|
+
*/
|
|
76
|
+
const DEFAULT_STARTUP_PROBE_ATTEMPTS = 4;
|
|
77
|
+
/** Delay between startup re-probes (ms). Default 5s → ~15s warmup window. */
|
|
78
|
+
const DEFAULT_STARTUP_PROBE_BACKOFF_MS = 5000;
|
|
79
|
+
/**
|
|
80
|
+
* Steady-state background re-probe interval (ms). AFTER auto-sense picks a mode it
|
|
81
|
+
* keeps probing on this cadence so it can start local inference once a fresh
|
|
82
|
+
* install's litert-lm finishes warming up. Explicit cloud-fallback installs also
|
|
83
|
+
* use it to upgrade cloud→local and recover local→cloud. Default 60s.
|
|
84
|
+
*/
|
|
85
|
+
const DEFAULT_HEALTH_RECHECK_INTERVAL_MS = 60000;
|
|
86
|
+
/** Floor for the re-probe interval (ms) so a mis-set tiny value can't hammer the serve. */
|
|
87
|
+
const MIN_HEALTH_RECHECK_INTERVAL_MS = 15000;
|
|
88
|
+
/**
|
|
89
|
+
* Anti-thrash: consecutive UNHEALTHY background re-probes required before a
|
|
90
|
+
* LOCAL→CLOUD fallback (a single flapping bad probe must not toggle the active
|
|
91
|
+
* manager). The reverse cloud→local upgrade is immediate. Default 2.
|
|
92
|
+
*/
|
|
93
|
+
const DEFAULT_LOCAL_UNHEALTHY_CHECKS_BEFORE_FALLBACK = 2;
|
|
94
|
+
/**
|
|
95
|
+
* Probe `litert-lm serve` for reachability + readiness via `GET {base}/v1/models`
|
|
96
|
+
* (the OpenAI-compatible model list — cheap, present on a healthy serve, and a
|
|
97
|
+
* de-facto health endpoint). A 2xx with a parseable model list THAT INCLUDES THE
|
|
98
|
+
* MODEL the local-sense path will actually use is "healthy"; anything else
|
|
99
|
+
* (connection refused, timeout, non-2xx, empty/garbage body, OR a serve hosting
|
|
100
|
+
* a DIFFERENT model than configured) is "unhealthy" so the caller degrades to
|
|
101
|
+
* cloud.
|
|
102
|
+
*
|
|
103
|
+
* Why match the model (not just "non-empty list"): the local path posts inference
|
|
104
|
+
* to `config.localSensing.model` (default gemma-4-E2B-it.litertlm). A serve that
|
|
105
|
+
* is up but hosting a DIFFERENT model id would make auto-sense pick local and
|
|
106
|
+
* then fail EVERY frame — exactly the hard-fail this entrypoint exists to avoid.
|
|
107
|
+
* So we require the expected model to be present. (`expectedModel` omitted → fall
|
|
108
|
+
* back to "any non-empty list", e.g. for a pure reachability check.)
|
|
109
|
+
*
|
|
110
|
+
* Built-in http/https only (no extra dependency → survives bundling into the
|
|
111
|
+
* self-contained connector; trivially mockable in tests). Never throws.
|
|
112
|
+
*/
|
|
113
|
+
async function probeLiteRtLmHealth(baseUrl = DEFAULT_LITERT_LM_BASE_URL, opts = {}) {
|
|
114
|
+
const base = (baseUrl || DEFAULT_LITERT_LM_BASE_URL).replace(/\/+$/, '');
|
|
115
|
+
const url = `${base}/v1/models`;
|
|
116
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
117
|
+
const getter = opts.httpGetter ?? exports.defaultHttpGetter;
|
|
118
|
+
const expectedModel = opts.expectedModel?.trim() || undefined;
|
|
119
|
+
const startedAt = Date.now();
|
|
120
|
+
let result;
|
|
121
|
+
try {
|
|
122
|
+
result = await getter(url, { timeoutMs });
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
reason: `litert-lm unreachable at ${url} (${err.message})`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const latencyMs = Date.now() - startedAt;
|
|
131
|
+
if (result.statusCode < 200 || result.statusCode >= 300) {
|
|
132
|
+
return {
|
|
133
|
+
ok: false,
|
|
134
|
+
reason: `litert-lm at ${url} returned HTTP ${result.statusCode}`,
|
|
135
|
+
latencyMs,
|
|
136
|
+
statusCode: result.statusCode,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// A healthy serve answers /v1/models with `{ data: [ { id, ... } ] }`. Collect
|
|
140
|
+
// the model ids so we can require BOTH a non-empty list AND (when asked) the
|
|
141
|
+
// specific model the local path will use.
|
|
142
|
+
let modelIds = null;
|
|
143
|
+
try {
|
|
144
|
+
const parsed = JSON.parse(result.body);
|
|
145
|
+
if (Array.isArray(parsed?.data)) {
|
|
146
|
+
modelIds = parsed.data
|
|
147
|
+
.map((m) => (m && typeof m.id === 'string' ? m.id : null))
|
|
148
|
+
.filter((id) => id !== null);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
modelIds = null;
|
|
153
|
+
}
|
|
154
|
+
if (modelIds === null) {
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
reason: `litert-lm at ${url} returned an unparseable model list`,
|
|
158
|
+
latencyMs,
|
|
159
|
+
statusCode: result.statusCode,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (modelIds.length === 0) {
|
|
163
|
+
return {
|
|
164
|
+
ok: false,
|
|
165
|
+
reason: `litert-lm at ${url} is up but has no model imported`,
|
|
166
|
+
latencyMs,
|
|
167
|
+
statusCode: result.statusCode,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// The serve is up with model(s), but if it isn't hosting the one we'll infer
|
|
171
|
+
// against, local would fail every frame — so treat that as unhealthy → cloud.
|
|
172
|
+
if (expectedModel && !modelIds.includes(expectedModel)) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
reason: `litert-lm at ${url} is up but does not host model "${expectedModel}" ` +
|
|
176
|
+
`(has: ${modelIds.join(', ')})`,
|
|
177
|
+
latencyMs,
|
|
178
|
+
statusCode: result.statusCode,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
ok: true,
|
|
183
|
+
reason: `litert-lm healthy at ${url} (` +
|
|
184
|
+
(expectedModel ? `model "${expectedModel}" present, ` : `${modelIds.length} model(s), `) +
|
|
185
|
+
`${latencyMs}ms)`,
|
|
186
|
+
latencyMs,
|
|
187
|
+
statusCode: result.statusCode,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* The `auto-sense` SUPERVISOR. Instead of probing once and then blocking forever
|
|
192
|
+
* on a single manager (the old behavior — mode FIXED for the whole process run,
|
|
193
|
+
* "restart to re-probe"), it OWNS the sensing lifecycle so the connector always
|
|
194
|
+
* prefers on-device Gemma and switches automatically with NO restart:
|
|
195
|
+
*
|
|
196
|
+
* - startInitial(): bounded startup re-probe → start the chosen path's REAL
|
|
197
|
+
* manager directly when litert-lm is healthy; otherwise wait locally unless
|
|
198
|
+
* cloud fallback was explicitly enabled.
|
|
199
|
+
* - beginRechecks(): a steady-state background re-probe loop on recheckIntervalMs.
|
|
200
|
+
* - recheck(): one tick — AUTO-UPGRADE cloud→local the instant local is ready
|
|
201
|
+
* (fixes the fresh-install race with zero restart). Explicit cloud-fallback
|
|
202
|
+
* installs may also recover local→cloud after K unhealthy probes.
|
|
203
|
+
* - shutdown(): stop the active manager + clear the timer (SIGINT/SIGTERM).
|
|
204
|
+
*
|
|
205
|
+
* At most ONE switch per tick; a re-entrancy guard + the K-debounce mean a
|
|
206
|
+
* flapping health signal can never rapidly toggle managers.
|
|
207
|
+
*/
|
|
208
|
+
class AutoSenseSupervisor {
|
|
209
|
+
constructor(deps) {
|
|
210
|
+
this.deps = deps;
|
|
211
|
+
this.mode = null;
|
|
212
|
+
this.active = null;
|
|
213
|
+
// Build each mode's manager once and reuse the instance across switches (a
|
|
214
|
+
// stop()→start() cycle re-runs the SAME real manager). `undefined` = not built
|
|
215
|
+
// yet; `null` = built but no feeds (fatal — cached so we don't rebuild).
|
|
216
|
+
this.localManager = undefined;
|
|
217
|
+
this.cloudManager = undefined;
|
|
218
|
+
this.consecutiveUnhealthy = 0;
|
|
219
|
+
this.timer = null;
|
|
220
|
+
this.switching = false;
|
|
221
|
+
this.stopped = false;
|
|
222
|
+
}
|
|
223
|
+
/** The active mode (null until startInitial). For tests/observability. */
|
|
224
|
+
get currentMode() {
|
|
225
|
+
return this.mode;
|
|
226
|
+
}
|
|
227
|
+
getManager(mode) {
|
|
228
|
+
if (mode === 'local') {
|
|
229
|
+
if (this.localManager === undefined)
|
|
230
|
+
this.localManager = this.deps.buildLocalManager();
|
|
231
|
+
return this.localManager;
|
|
232
|
+
}
|
|
233
|
+
if (this.cloudManager === undefined)
|
|
234
|
+
this.cloudManager = this.deps.buildCloudManager();
|
|
235
|
+
return this.cloudManager;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Initial probe (bounded startup re-probe loop for the fresh-install warmup
|
|
239
|
+
* race) → start the chosen path's manager directly. Returns false (after
|
|
240
|
+
* onNoFeeds) when the chosen mode has no feeds configured.
|
|
241
|
+
*/
|
|
242
|
+
async startInitial() {
|
|
243
|
+
this.deps.log(`[auto-sense] probing on-device LiteRT-LM at ${this.deps.litertLmBaseUrl} for model ` +
|
|
244
|
+
`"${this.deps.expectedModel}" (timeout ${this.deps.probeTimeoutMs}ms, up to ` +
|
|
245
|
+
`${this.deps.startupAttempts} attempt(s))…`);
|
|
246
|
+
let health = { ok: false, reason: 'no probe attempt made' };
|
|
247
|
+
for (let attempt = 1; attempt <= this.deps.startupAttempts; attempt += 1) {
|
|
248
|
+
health = await this.deps.probe();
|
|
249
|
+
if (health.ok)
|
|
250
|
+
break;
|
|
251
|
+
if (attempt < this.deps.startupAttempts) {
|
|
252
|
+
this.deps.log(`[auto-sense] LiteRT-LM not ready (attempt ${attempt}/${this.deps.startupAttempts}): ` +
|
|
253
|
+
`${health.reason} — retrying in ${this.deps.startupBackoffMs}ms`);
|
|
254
|
+
if (this.deps.startupBackoffMs > 0)
|
|
255
|
+
await this.deps.sleep(this.deps.startupBackoffMs);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (health.ok) {
|
|
259
|
+
this.deps.log(`[auto-sense] LOCAL on-device sensing selected — ${health.reason}`);
|
|
260
|
+
return this.activate('local');
|
|
261
|
+
}
|
|
262
|
+
if (this.deps.allowCloudFallback) {
|
|
263
|
+
this.deps.log(`[auto-sense] CLOUD sensing selected by explicit fallback policy (local VLM not usable after ` +
|
|
264
|
+
`${this.deps.startupAttempts} attempt(s)) — ${health.reason}. Will AUTO-UPGRADE to LOCAL ` +
|
|
265
|
+
`with no restart once LiteRT-LM is ready (re-probing every ${this.deps.recheckIntervalMs}ms).`);
|
|
266
|
+
return this.activate('cloud');
|
|
267
|
+
}
|
|
268
|
+
// Validate feeds before entering the wait loop so a bad/empty config still
|
|
269
|
+
// fails immediately instead of looking like a model download in progress.
|
|
270
|
+
if (!this.getManager('local')) {
|
|
271
|
+
this.deps.onNoFeeds();
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
this.mode = 'waiting';
|
|
275
|
+
this.deps.log(`[auto-sense] LOCAL AI is not ready yet — ${health.reason}. Cloud inference is disabled by ` +
|
|
276
|
+
`default; waiting for LiteRT-LM and re-probing every ${this.deps.recheckIntervalMs}ms.`);
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
/** Build + start a mode's manager and make it active. False ⇒ no feeds. */
|
|
280
|
+
async activate(mode) {
|
|
281
|
+
const manager = this.getManager(mode);
|
|
282
|
+
if (!manager) {
|
|
283
|
+
this.deps.onNoFeeds();
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
await manager.start();
|
|
287
|
+
this.active = manager;
|
|
288
|
+
this.mode = mode;
|
|
289
|
+
this.consecutiveUnhealthy = 0;
|
|
290
|
+
if (mode === 'local')
|
|
291
|
+
this.deps.onLocalActivated?.();
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
/** Start the steady-state background re-probe loop. */
|
|
295
|
+
beginRechecks() {
|
|
296
|
+
this.scheduleNextRecheck();
|
|
297
|
+
}
|
|
298
|
+
scheduleNextRecheck() {
|
|
299
|
+
if (this.stopped)
|
|
300
|
+
return;
|
|
301
|
+
// Re-arming timeout (schedule the NEXT tick only after this one settles) so
|
|
302
|
+
// a slow probe/switch can never overlap the next re-probe.
|
|
303
|
+
this.timer = this.deps.setTimer(() => {
|
|
304
|
+
this.recheck()
|
|
305
|
+
.catch((err) => this.deps.log(`[auto-sense] re-probe tick failed: ${err instanceof Error ? err.message : err}`))
|
|
306
|
+
.finally(() => this.scheduleNextRecheck());
|
|
307
|
+
}, this.deps.recheckIntervalMs);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* One background re-probe tick.
|
|
311
|
+
* - While WAITING: a healthy probe starts local sensing immediately.
|
|
312
|
+
* - On CLOUD: any healthy probe → AUTO-UPGRADE to local immediately (running
|
|
313
|
+
* on cloud while local is ready is pure waste; the K-debounce on the return
|
|
314
|
+
* path bounds any toggling, so this is safe on the first healthy probe).
|
|
315
|
+
* - On LOCAL: a healthy probe resets the debounce; an unhealthy probe
|
|
316
|
+
* increments it, and only after K CONSECUTIVE unhealthy probes do we
|
|
317
|
+
* AUTO-RECOVER to cloud only when explicit fallback is enabled.
|
|
318
|
+
* At most one switch per tick; re-entrancy guarded.
|
|
319
|
+
*/
|
|
320
|
+
async recheck() {
|
|
321
|
+
if (this.stopped || this.switching)
|
|
322
|
+
return;
|
|
323
|
+
const health = await this.deps.probe();
|
|
324
|
+
if (this.stopped)
|
|
325
|
+
return;
|
|
326
|
+
if (this.mode === 'waiting') {
|
|
327
|
+
if (health.ok) {
|
|
328
|
+
this.deps.log('[auto-sense] LOCAL AI is ready — starting on-device sensing');
|
|
329
|
+
await this.switchTo('local');
|
|
330
|
+
}
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (this.mode === 'cloud') {
|
|
334
|
+
if (health.ok) {
|
|
335
|
+
this.deps.log('[auto-sense] upgrading CLOUD->LOCAL (LiteRT-LM now ready)');
|
|
336
|
+
await this.switchTo('local');
|
|
337
|
+
}
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (this.mode === 'local') {
|
|
341
|
+
if (health.ok) {
|
|
342
|
+
this.consecutiveUnhealthy = 0;
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
this.consecutiveUnhealthy += 1;
|
|
346
|
+
if (this.consecutiveUnhealthy >= this.deps.unhealthyChecksBeforeFallback) {
|
|
347
|
+
if (this.deps.allowCloudFallback) {
|
|
348
|
+
this.deps.log('[auto-sense] falling back LOCAL->CLOUD (explicit policy; LiteRT-LM unhealthy)');
|
|
349
|
+
await this.switchTo('cloud');
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
this.deps.log(`[auto-sense] LOCAL AI health check failed — ${health.reason}. ` +
|
|
353
|
+
'Cloud inference remains disabled; local sensing will recover in place.');
|
|
354
|
+
this.consecutiveUnhealthy = 0;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/** Stop the active manager, start the target — old.stop() BEFORE new.start(). */
|
|
360
|
+
async switchTo(mode) {
|
|
361
|
+
if (this.mode === mode || this.switching)
|
|
362
|
+
return;
|
|
363
|
+
const next = this.getManager(mode);
|
|
364
|
+
if (!next) {
|
|
365
|
+
// Can't happen mid-run (both modes resolve the SAME static feeds), but
|
|
366
|
+
// never tear down the working manager for one we can't start.
|
|
367
|
+
this.deps.log(`[auto-sense] cannot switch to ${mode} sensing (no camera feeds) — staying on ${this.mode}`);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
this.switching = true;
|
|
371
|
+
try {
|
|
372
|
+
if (this.active)
|
|
373
|
+
await this.active.stop();
|
|
374
|
+
await next.start();
|
|
375
|
+
this.active = next;
|
|
376
|
+
this.mode = mode;
|
|
377
|
+
this.consecutiveUnhealthy = 0;
|
|
378
|
+
if (mode === 'local')
|
|
379
|
+
this.deps.onLocalActivated?.();
|
|
380
|
+
}
|
|
381
|
+
finally {
|
|
382
|
+
this.switching = false;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/** SIGINT/SIGTERM: stop the active manager + clear the re-probe timer. Idempotent. */
|
|
386
|
+
async shutdown() {
|
|
387
|
+
if (this.stopped)
|
|
388
|
+
return;
|
|
389
|
+
this.stopped = true;
|
|
390
|
+
if (this.timer != null) {
|
|
391
|
+
this.deps.clearTimer(this.timer);
|
|
392
|
+
this.timer = null;
|
|
393
|
+
}
|
|
394
|
+
if (this.active) {
|
|
395
|
+
try {
|
|
396
|
+
await this.active.stop();
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
// best-effort
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
exports.AutoSenseSupervisor = AutoSenseSupervisor;
|
|
405
|
+
function defaultRegisterShutdown(handler) {
|
|
406
|
+
process.on('SIGINT', handler);
|
|
407
|
+
process.on('SIGTERM', handler);
|
|
408
|
+
}
|
|
409
|
+
/** Never resolves — keeps the connector process alive until SIGINT/SIGTERM. */
|
|
410
|
+
function blockForever() {
|
|
411
|
+
return new Promise(() => { });
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* `auto-sense` entrypoint: resolve probe + manager inputs from config, then run
|
|
415
|
+
* the AutoSenseSupervisor (probe → start the chosen REAL manager → keep
|
|
416
|
+
* re-probing → auto-upgrade/auto-recover with NO restart). Blocks until
|
|
417
|
+
* SIGINT/SIGTERM (the supervisor's re-probe timer keeps the event loop alive).
|
|
418
|
+
*
|
|
419
|
+
* The probe target is the operator's configured `localSensing.litertLmBaseUrl`
|
|
420
|
+
* (default http://localhost:9379) so a non-standard serve host is honored, and
|
|
421
|
+
* the probe requires the configured `localSensing.model` to be present so we
|
|
422
|
+
* never pick local against a serve hosting the wrong model.
|
|
423
|
+
*
|
|
424
|
+
* Config is REQUIRED to build the sensing managers, so it's loaded up front and a
|
|
425
|
+
* genuine config error propagates to main() (prints + exits 1) — the same net
|
|
426
|
+
* result as before, where the chosen run mode re-loaded the config and reported it.
|
|
427
|
+
*
|
|
428
|
+
* The explicit `local-sense` / `cloud-sense` entrypoints stay non-switching; only
|
|
429
|
+
* `auto-sense` is supervised.
|
|
430
|
+
*/
|
|
431
|
+
async function runAutoSense(args, deps = {}) {
|
|
432
|
+
const log = deps.log ?? ((m) => console.log(m));
|
|
433
|
+
const load = deps.loadConfig ?? config_1.loadConfig;
|
|
434
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
435
|
+
const configIdx = args.indexOf('--config');
|
|
436
|
+
const configPath = configIdx >= 0 && args[configIdx + 1] ? args[configIdx + 1] : 'trillboards.config.json';
|
|
437
|
+
const config = load(configPath);
|
|
438
|
+
const litertLmBaseUrl = config.localSensing?.litertLmBaseUrl || DEFAULT_LITERT_LM_BASE_URL;
|
|
439
|
+
const probeTimeoutMs = config.localSensing?.healthProbeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
440
|
+
const expectedModel = config.localSensing?.model || DEFAULT_LITERT_LM_MODEL;
|
|
441
|
+
const startupAttempts = Math.max(1, config.localSensing?.healthProbeStartupAttempts ?? DEFAULT_STARTUP_PROBE_ATTEMPTS);
|
|
442
|
+
const startupBackoffMs = config.localSensing?.healthProbeStartupBackoffMs ?? DEFAULT_STARTUP_PROBE_BACKOFF_MS;
|
|
443
|
+
const recheckIntervalMs = Math.max(MIN_HEALTH_RECHECK_INTERVAL_MS, config.localSensing?.healthRecheckIntervalMs ?? DEFAULT_HEALTH_RECHECK_INTERVAL_MS);
|
|
444
|
+
const unhealthyChecksBeforeFallback = Math.max(1, config.localSensing?.localUnhealthyChecksBeforeFallback ??
|
|
445
|
+
DEFAULT_LOCAL_UNHEALTHY_CHECKS_BEFORE_FALLBACK);
|
|
446
|
+
const allowCloudFallback = config.localSensing?.allowCloudFallback === true;
|
|
447
|
+
const probe = deps.probe
|
|
448
|
+
? () => deps.probe(litertLmBaseUrl, probeTimeoutMs, expectedModel)
|
|
449
|
+
: () => probeLiteRtLmHealth(litertLmBaseUrl, { timeoutMs: probeTimeoutMs, expectedModel });
|
|
450
|
+
let gemmaOta = null;
|
|
451
|
+
let gemmaOtaStarted = false;
|
|
452
|
+
const startModelOtaOnce = () => {
|
|
453
|
+
if (gemmaOtaStarted)
|
|
454
|
+
return;
|
|
455
|
+
gemmaOtaStarted = true;
|
|
456
|
+
gemmaOta = (deps.startModelOta ?? gemmaModelOta_1.startGemmaModelOta)(config);
|
|
457
|
+
};
|
|
458
|
+
const supervisor = new AutoSenseSupervisor({
|
|
459
|
+
probe,
|
|
460
|
+
buildLocalManager: deps.buildLocalManager ?? (() => (0, sensingRunMode_1.buildLocalSensingManager)(config, undefined, { configPath })),
|
|
461
|
+
buildCloudManager: deps.buildCloudManager ?? (() => (0, sensingRunMode_1.buildCloudSensingManager)(config, undefined, { configPath })),
|
|
462
|
+
log,
|
|
463
|
+
sleep,
|
|
464
|
+
setTimer: deps.setTimer ?? ((cb, ms) => setTimeout(cb, ms)),
|
|
465
|
+
clearTimer: deps.clearTimer ?? ((h) => clearTimeout(h)),
|
|
466
|
+
onNoFeeds: deps.onNoFeeds ?? (() => process.exit(1)),
|
|
467
|
+
onLocalActivated: startModelOtaOnce,
|
|
468
|
+
startupAttempts,
|
|
469
|
+
startupBackoffMs,
|
|
470
|
+
recheckIntervalMs,
|
|
471
|
+
unhealthyChecksBeforeFallback,
|
|
472
|
+
allowCloudFallback,
|
|
473
|
+
litertLmBaseUrl,
|
|
474
|
+
expectedModel,
|
|
475
|
+
probeTimeoutMs,
|
|
476
|
+
});
|
|
477
|
+
// Clean shutdown: stop the OTA watcher, the active manager, + the re-probe timer.
|
|
478
|
+
const register = deps.registerShutdown ?? defaultRegisterShutdown;
|
|
479
|
+
register(async () => {
|
|
480
|
+
gemmaOta?.stop();
|
|
481
|
+
await supervisor.shutdown();
|
|
482
|
+
process.exit(0);
|
|
483
|
+
});
|
|
484
|
+
const started = await supervisor.startInitial();
|
|
485
|
+
if (!started)
|
|
486
|
+
return; // onNoFeeds already fired (default: process.exit(1))
|
|
487
|
+
supervisor.beginRechecks();
|
|
488
|
+
// Keep the process running until SIGINT/SIGTERM (tests inject a resolved waiter).
|
|
489
|
+
await (deps.waitForShutdown ?? blockForever)();
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Default transport using Node's built-in http/https. No third-party deps so it
|
|
493
|
+
* survives bundling into the self-contained connector. Mirrors the framing
|
|
494
|
+
* tolerance of LiteRtVlmProvider's poster: litert-lm serve emits non-strict HTTP
|
|
495
|
+
* framing (bare LF on the status line) that Node's strict parser rejects, and
|
|
496
|
+
* the connector talks to a LOCAL, trusted serve, so we tolerate it here too —
|
|
497
|
+
* otherwise a healthy serve would look "unreachable" and we'd wrongly pick cloud.
|
|
498
|
+
*/
|
|
499
|
+
const defaultHttpGetter = (url, options) => {
|
|
500
|
+
return new Promise((resolve, reject) => {
|
|
501
|
+
let parsed;
|
|
502
|
+
try {
|
|
503
|
+
parsed = new url_1.URL(url);
|
|
504
|
+
}
|
|
505
|
+
catch (err) {
|
|
506
|
+
reject(new Error(`Invalid LiteRT-LM URL: ${err.message}`));
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
const mod = parsed.protocol === 'https:' ? https : http;
|
|
510
|
+
const req = mod.request(url, { method: 'GET', timeout: options.timeoutMs, insecureHTTPParser: true }, (res) => {
|
|
511
|
+
const chunks = [];
|
|
512
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
513
|
+
res.on('end', () => resolve({ statusCode: res.statusCode || 0, body: Buffer.concat(chunks).toString('utf-8') }));
|
|
514
|
+
});
|
|
515
|
+
req.on('error', (err) => reject(err));
|
|
516
|
+
req.on('timeout', () => req.destroy(new Error(`probe timed out after ${options.timeoutMs}ms`)));
|
|
517
|
+
req.end();
|
|
518
|
+
});
|
|
519
|
+
};
|
|
520
|
+
exports.defaultHttpGetter = defaultHttpGetter;
|
|
521
|
+
//# sourceMappingURL=autoSense.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autoSense.js","sourceRoot":"","sources":["../src/autoSense.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* True if a filesystem error is a PERMISSION failure (EACCES/EPERM), or its
|
|
4
|
+
* message says so. This is the signature of the paired-config write failing
|
|
5
|
+
* because ~/Library/Application Support/Trillboards is owned by another account
|
|
6
|
+
* — which happens when the `.pkg` was installed with admin rights and its
|
|
7
|
+
* postinstall ran as root, creating that dir ROOT-OWNED. It is NOT a bad or
|
|
8
|
+
* expired claim code, so it must never be reported as one.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isPermissionError(err: unknown): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The operator-facing remediation when the paired config can't be written
|
|
13
|
+
* because its directory is owned by another account. Names the REAL cause and
|
|
14
|
+
* the exact one-line fix — deliberately NOT "double-check the code" (pairing
|
|
15
|
+
* already SUCCEEDED; only the local save failed). Mirrors the guidance in
|
|
16
|
+
* deploy/macos/pair.command so the GUI and headless paths say the same thing.
|
|
17
|
+
*/
|
|
18
|
+
export declare function configWritePermissionMessage(resolvedConfigPath: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Persist the paired config, translating a PERMISSION failure into the clear
|
|
21
|
+
* remediation above (and exiting non-zero) instead of letting a raw EACCES
|
|
22
|
+
* bubble up as an opaque "Fatal error" that the GUI then mislabels "check the
|
|
23
|
+
* code". Any OTHER write error is re-thrown unchanged (surfaced as "Fatal
|
|
24
|
+
* error: …"). The writer is injectable for tests (mirrors PairClient's poster).
|
|
25
|
+
*/
|
|
26
|
+
export declare function writePairedConfig(resolvedConfigPath: string, serialized: string, writeFile?: (p: string, data: string, opts: {
|
|
27
|
+
mode: number;
|
|
28
|
+
}) => void): void;
|
|
3
29
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA2WA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAW/E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,kBAAkB,EAAE,MAAM,EAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,KAAK,IAC/B,GAChC,IAAI,CAWN"}
|