@trillboards/edge-sdk 0.1.0
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/configs/backpackster.json +32 -0
- package/configs/generic-linux.json +31 -0
- package/configs/windows-dooh.json +35 -0
- package/deploy/docker/.dockerignore +4 -0
- package/deploy/docker/Dockerfile +31 -0
- package/deploy/docker/config.json +21 -0
- package/deploy/docker/package.json +9 -0
- package/deploy/systemd/install.sh +68 -0
- package/deploy/systemd/trillboards-edge.service +42 -0
- package/deploy/windows/install-service.ps1 +95 -0
- package/dist/EdgeAgent.d.ts +39 -0
- package/dist/EdgeAgent.d.ts.map +1 -0
- package/dist/EdgeAgent.js +418 -0
- package/dist/EdgeAgent.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +217 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +97 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiBaseUrl": "https://api.trillboards.com",
|
|
3
|
+
"deviceToken": "REPLACE_WITH_YOUR_TOKEN",
|
|
4
|
+
"screenId": "REPLACE_WITH_SCREEN_ID",
|
|
5
|
+
"venueType": "mobile_ooh",
|
|
6
|
+
"platform": "linux",
|
|
7
|
+
"camera": {
|
|
8
|
+
"enabled": true,
|
|
9
|
+
"deviceId": "/dev/video0",
|
|
10
|
+
"width": 640,
|
|
11
|
+
"height": 480,
|
|
12
|
+
"fps": 5
|
|
13
|
+
},
|
|
14
|
+
"audio": {
|
|
15
|
+
"enabled": false
|
|
16
|
+
},
|
|
17
|
+
"models": {
|
|
18
|
+
"dir": "/opt/trillboards/models",
|
|
19
|
+
"executionProvider": "openvino"
|
|
20
|
+
},
|
|
21
|
+
"kiosk": {
|
|
22
|
+
"enabled": false
|
|
23
|
+
},
|
|
24
|
+
"cloud": {
|
|
25
|
+
"enabled": false
|
|
26
|
+
},
|
|
27
|
+
"federated": {
|
|
28
|
+
"enabled": true
|
|
29
|
+
},
|
|
30
|
+
"dataDir": "/var/lib/trillboards",
|
|
31
|
+
"logLevel": "info"
|
|
32
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiBaseUrl": "https://api.trillboards.com",
|
|
3
|
+
"deviceToken": "REPLACE_WITH_YOUR_TOKEN",
|
|
4
|
+
"screenId": "REPLACE_WITH_SCREEN_ID",
|
|
5
|
+
"venueType": "retail",
|
|
6
|
+
"camera": {
|
|
7
|
+
"enabled": true,
|
|
8
|
+
"deviceId": "/dev/video0",
|
|
9
|
+
"width": 640,
|
|
10
|
+
"height": 480,
|
|
11
|
+
"fps": 5
|
|
12
|
+
},
|
|
13
|
+
"audio": {
|
|
14
|
+
"enabled": true
|
|
15
|
+
},
|
|
16
|
+
"models": {
|
|
17
|
+
"dir": "./models",
|
|
18
|
+
"executionProvider": "cpu"
|
|
19
|
+
},
|
|
20
|
+
"kiosk": {
|
|
21
|
+
"enabled": true,
|
|
22
|
+
"url": "https://screen.trillboards.com"
|
|
23
|
+
},
|
|
24
|
+
"cloud": {
|
|
25
|
+
"enabled": false
|
|
26
|
+
},
|
|
27
|
+
"federated": {
|
|
28
|
+
"enabled": false
|
|
29
|
+
},
|
|
30
|
+
"logLevel": "info"
|
|
31
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiBaseUrl": "https://api.trillboards.com",
|
|
3
|
+
"deviceToken": "REPLACE_WITH_YOUR_TOKEN",
|
|
4
|
+
"screenId": "REPLACE_WITH_SCREEN_ID",
|
|
5
|
+
"venueType": "roadside_billboard",
|
|
6
|
+
"platform": "windows",
|
|
7
|
+
"camera": {
|
|
8
|
+
"enabled": true,
|
|
9
|
+
"rtspUrl": "rtsp://admin:password@192.168.1.100:554/stream1",
|
|
10
|
+
"width": 1280,
|
|
11
|
+
"height": 720,
|
|
12
|
+
"fps": 3
|
|
13
|
+
},
|
|
14
|
+
"audio": {
|
|
15
|
+
"enabled": false
|
|
16
|
+
},
|
|
17
|
+
"models": {
|
|
18
|
+
"dir": "C:\\trillboards\\models",
|
|
19
|
+
"executionProvider": "directml"
|
|
20
|
+
},
|
|
21
|
+
"kiosk": {
|
|
22
|
+
"enabled": true,
|
|
23
|
+
"url": "https://screen.trillboards.com",
|
|
24
|
+
"chromiumPath": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
|
|
25
|
+
},
|
|
26
|
+
"cloud": {
|
|
27
|
+
"enabled": true,
|
|
28
|
+
"geminiApiKey": "REPLACE_WITH_GEMINI_KEY"
|
|
29
|
+
},
|
|
30
|
+
"federated": {
|
|
31
|
+
"enabled": false
|
|
32
|
+
},
|
|
33
|
+
"dataDir": "C:\\ProgramData\\trillboards",
|
|
34
|
+
"logLevel": "info"
|
|
35
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
FROM node:20-slim AS base
|
|
2
|
+
|
|
3
|
+
# Install ffmpeg for camera/audio capture
|
|
4
|
+
RUN apt-get update && \
|
|
5
|
+
apt-get install -y --no-install-recommends ffmpeg v4l-utils pulseaudio-utils && \
|
|
6
|
+
rm -rf /var/lib/apt/lists/*
|
|
7
|
+
|
|
8
|
+
WORKDIR /opt/trillboards
|
|
9
|
+
|
|
10
|
+
# Install SDK
|
|
11
|
+
COPY package.json ./
|
|
12
|
+
RUN npm install --omit=dev
|
|
13
|
+
|
|
14
|
+
# Download models
|
|
15
|
+
RUN npx trillboards-edge download-models --dir /opt/trillboards/models || true
|
|
16
|
+
|
|
17
|
+
# Copy config (override at runtime with -v)
|
|
18
|
+
COPY config.json ./trillboards.config.json
|
|
19
|
+
|
|
20
|
+
# Non-root user
|
|
21
|
+
RUN useradd --system --no-create-home trillboards && \
|
|
22
|
+
mkdir -p /var/lib/trillboards && \
|
|
23
|
+
chown -R trillboards:trillboards /opt/trillboards /var/lib/trillboards
|
|
24
|
+
|
|
25
|
+
USER trillboards
|
|
26
|
+
|
|
27
|
+
# Health check
|
|
28
|
+
HEALTHCHECK --interval=30s --timeout=5s \
|
|
29
|
+
CMD node -e "process.exit(0)"
|
|
30
|
+
|
|
31
|
+
ENTRYPOINT ["npx", "trillboards-edge", "start", "--config", "trillboards.config.json"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiBaseUrl": "https://api.trillboards.com",
|
|
3
|
+
"deviceToken": "REPLACE_WITH_YOUR_TOKEN",
|
|
4
|
+
"screenId": "REPLACE_WITH_SCREEN_ID",
|
|
5
|
+
"camera": {
|
|
6
|
+
"enabled": true,
|
|
7
|
+
"deviceId": "/dev/video0"
|
|
8
|
+
},
|
|
9
|
+
"audio": {
|
|
10
|
+
"enabled": false
|
|
11
|
+
},
|
|
12
|
+
"models": {
|
|
13
|
+
"dir": "/opt/trillboards/models",
|
|
14
|
+
"executionProvider": "cpu"
|
|
15
|
+
},
|
|
16
|
+
"kiosk": {
|
|
17
|
+
"enabled": false
|
|
18
|
+
},
|
|
19
|
+
"dataDir": "/var/lib/trillboards",
|
|
20
|
+
"logLevel": "info"
|
|
21
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
echo "=== Trillboards Edge AI SDK — Linux Install ==="
|
|
5
|
+
echo ""
|
|
6
|
+
|
|
7
|
+
# Check Node.js
|
|
8
|
+
if ! command -v node &>/dev/null; then
|
|
9
|
+
echo "Error: Node.js >= 18 is required."
|
|
10
|
+
echo "Install: curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
NODE_VER=$(node -v | sed 's/v//' | cut -d. -f1)
|
|
15
|
+
if [ "$NODE_VER" -lt 18 ]; then
|
|
16
|
+
echo "Error: Node.js >= 18 required (found v$(node -v))"
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Check ffmpeg
|
|
21
|
+
if ! command -v ffmpeg &>/dev/null; then
|
|
22
|
+
echo "Installing ffmpeg..."
|
|
23
|
+
sudo apt-get update -qq && sudo apt-get install -y -qq ffmpeg
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Create user and directories
|
|
27
|
+
echo "Creating trillboards user and directories..."
|
|
28
|
+
sudo useradd --system --home-dir /opt/trillboards --shell /usr/sbin/nologin trillboards 2>/dev/null || true
|
|
29
|
+
sudo mkdir -p /opt/trillboards /var/lib/trillboards /etc/trillboards
|
|
30
|
+
sudo chown -R trillboards:trillboards /opt/trillboards /var/lib/trillboards
|
|
31
|
+
|
|
32
|
+
# Install SDK
|
|
33
|
+
echo "Installing @trillboards/edge-sdk..."
|
|
34
|
+
cd /opt/trillboards
|
|
35
|
+
sudo -u trillboards npm init -y --silent 2>/dev/null
|
|
36
|
+
sudo -u trillboards npm install @trillboards/edge-sdk @trillboards/edge-platform-linux
|
|
37
|
+
|
|
38
|
+
# Download models
|
|
39
|
+
echo "Downloading ONNX models..."
|
|
40
|
+
sudo -u trillboards mkdir -p /opt/trillboards/models
|
|
41
|
+
sudo -u trillboards npx trillboards-edge download-models --dir /opt/trillboards/models
|
|
42
|
+
|
|
43
|
+
# Install config template
|
|
44
|
+
if [ ! -f /etc/trillboards/config.json ]; then
|
|
45
|
+
echo "Installing config template..."
|
|
46
|
+
sudo cp node_modules/@trillboards/edge-sdk/configs/generic-linux.json /etc/trillboards/config.json
|
|
47
|
+
sudo chown trillboards:trillboards /etc/trillboards/config.json
|
|
48
|
+
echo ""
|
|
49
|
+
echo " *** IMPORTANT: Edit /etc/trillboards/config.json ***"
|
|
50
|
+
echo " Set your deviceToken and screenId from the Trillboards dashboard."
|
|
51
|
+
echo ""
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Install systemd service
|
|
55
|
+
echo "Installing systemd service..."
|
|
56
|
+
sudo cp node_modules/@trillboards/edge-sdk/deploy/systemd/trillboards-edge.service /etc/systemd/system/
|
|
57
|
+
sudo systemctl daemon-reload
|
|
58
|
+
sudo systemctl enable trillboards-edge
|
|
59
|
+
|
|
60
|
+
echo ""
|
|
61
|
+
echo "=== Installation Complete ==="
|
|
62
|
+
echo ""
|
|
63
|
+
echo "Next steps:"
|
|
64
|
+
echo " 1. Edit /etc/trillboards/config.json with your device token"
|
|
65
|
+
echo " 2. Start: sudo systemctl start trillboards-edge"
|
|
66
|
+
echo " 3. Logs: sudo journalctl -u trillboards-edge -f"
|
|
67
|
+
echo " 4. Status: sudo systemctl status trillboards-edge"
|
|
68
|
+
echo ""
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=Trillboards Edge AI Agent
|
|
3
|
+
Documentation=https://github.com/trillboards/packages
|
|
4
|
+
After=network-online.target
|
|
5
|
+
Wants=network-online.target
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Type=simple
|
|
9
|
+
User=trillboards
|
|
10
|
+
Group=trillboards
|
|
11
|
+
WorkingDirectory=/opt/trillboards
|
|
12
|
+
ExecStartPre=/usr/bin/node -e "require('@trillboards/edge-sdk')"
|
|
13
|
+
ExecStart=/usr/bin/npx trillboards-edge start --config /etc/trillboards/config.json
|
|
14
|
+
Restart=always
|
|
15
|
+
RestartSec=10
|
|
16
|
+
StartLimitInterval=300
|
|
17
|
+
StartLimitBurst=5
|
|
18
|
+
StandardOutput=journal
|
|
19
|
+
StandardError=journal
|
|
20
|
+
SyslogIdentifier=trillboards-edge
|
|
21
|
+
|
|
22
|
+
# Security hardening
|
|
23
|
+
NoNewPrivileges=true
|
|
24
|
+
ProtectSystem=strict
|
|
25
|
+
ProtectHome=true
|
|
26
|
+
ReadWritePaths=/var/lib/trillboards /opt/trillboards/models
|
|
27
|
+
PrivateTmp=true
|
|
28
|
+
|
|
29
|
+
# Resource limits
|
|
30
|
+
MemoryMax=2G
|
|
31
|
+
CPUQuota=80%
|
|
32
|
+
|
|
33
|
+
# Camera/audio device access
|
|
34
|
+
SupplementaryGroups=video audio
|
|
35
|
+
|
|
36
|
+
# Environment
|
|
37
|
+
Environment=NODE_ENV=production
|
|
38
|
+
Environment=NODE_OPTIONS=--max-old-space-size=1536
|
|
39
|
+
EnvironmentFile=-/etc/trillboards/env
|
|
40
|
+
|
|
41
|
+
[Install]
|
|
42
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Trillboards Edge AI SDK — Windows Service Installer
|
|
2
|
+
# Run as Administrator: powershell -ExecutionPolicy Bypass -File install-service.ps1
|
|
3
|
+
|
|
4
|
+
$ErrorActionPreference = "Stop"
|
|
5
|
+
|
|
6
|
+
$ServiceName = "TrillboardsEdge"
|
|
7
|
+
$DisplayName = "Trillboards Edge AI Agent"
|
|
8
|
+
$InstallDir = "C:\trillboards"
|
|
9
|
+
$DataDir = "C:\ProgramData\trillboards"
|
|
10
|
+
$ConfigPath = "$InstallDir\config.json"
|
|
11
|
+
$ModelsDir = "$InstallDir\models"
|
|
12
|
+
|
|
13
|
+
Write-Host "=== Trillboards Edge AI SDK - Windows Install ===" -ForegroundColor Cyan
|
|
14
|
+
Write-Host ""
|
|
15
|
+
|
|
16
|
+
# Check Node.js
|
|
17
|
+
try {
|
|
18
|
+
$nodeVersion = (node -v) -replace 'v', ''
|
|
19
|
+
$major = [int]($nodeVersion.Split('.')[0])
|
|
20
|
+
if ($major -lt 18) {
|
|
21
|
+
throw "Node.js >= 18 required (found v$nodeVersion)"
|
|
22
|
+
}
|
|
23
|
+
Write-Host "Node.js $nodeVersion detected" -ForegroundColor Green
|
|
24
|
+
} catch {
|
|
25
|
+
Write-Host "Error: Node.js >= 18 is required." -ForegroundColor Red
|
|
26
|
+
Write-Host "Download from: https://nodejs.org/"
|
|
27
|
+
exit 1
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Create directories
|
|
31
|
+
Write-Host "Creating directories..."
|
|
32
|
+
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
|
|
33
|
+
New-Item -ItemType Directory -Force -Path $DataDir | Out-Null
|
|
34
|
+
New-Item -ItemType Directory -Force -Path $ModelsDir | Out-Null
|
|
35
|
+
|
|
36
|
+
# Install SDK
|
|
37
|
+
Write-Host "Installing @trillboards/edge-sdk..."
|
|
38
|
+
Push-Location $InstallDir
|
|
39
|
+
if (!(Test-Path "package.json")) {
|
|
40
|
+
npm init -y --silent 2>$null
|
|
41
|
+
}
|
|
42
|
+
npm install @trillboards/edge-sdk @trillboards/edge-platform-windows
|
|
43
|
+
Pop-Location
|
|
44
|
+
|
|
45
|
+
# Download models
|
|
46
|
+
Write-Host "Downloading ONNX models..."
|
|
47
|
+
Push-Location $InstallDir
|
|
48
|
+
npx trillboards-edge download-models --dir $ModelsDir
|
|
49
|
+
Pop-Location
|
|
50
|
+
|
|
51
|
+
# Install config template
|
|
52
|
+
if (!(Test-Path $ConfigPath)) {
|
|
53
|
+
Write-Host "Installing config template..."
|
|
54
|
+
Copy-Item "$InstallDir\node_modules\@trillboards\edge-sdk\configs\windows-dooh.json" $ConfigPath
|
|
55
|
+
Write-Host ""
|
|
56
|
+
Write-Host " *** IMPORTANT: Edit $ConfigPath ***" -ForegroundColor Yellow
|
|
57
|
+
Write-Host " Set your deviceToken and screenId from the Trillboards dashboard."
|
|
58
|
+
Write-Host ""
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Create Windows Service wrapper script
|
|
62
|
+
$WrapperScript = @"
|
|
63
|
+
const { exec } = require('child_process');
|
|
64
|
+
const path = require('path');
|
|
65
|
+
const svc = exec(
|
|
66
|
+
'node ' + path.join(__dirname, 'node_modules', '@trillboards', 'edge-sdk', 'dist', 'cli.js') + ' start --config ' + path.join(__dirname, 'config.json'),
|
|
67
|
+
{ cwd: __dirname }
|
|
68
|
+
);
|
|
69
|
+
svc.stdout.pipe(process.stdout);
|
|
70
|
+
svc.stderr.pipe(process.stderr);
|
|
71
|
+
svc.on('exit', (code) => process.exit(code || 0));
|
|
72
|
+
"@
|
|
73
|
+
Set-Content -Path "$InstallDir\service-wrapper.js" -Value $WrapperScript
|
|
74
|
+
|
|
75
|
+
# Register as Windows Service using sc.exe with NSSM or node-windows
|
|
76
|
+
# For simplicity, use a scheduled task that runs at startup
|
|
77
|
+
$Action = New-ScheduledTaskAction -Execute "node.exe" -Argument "$InstallDir\service-wrapper.js" -WorkingDirectory $InstallDir
|
|
78
|
+
$Trigger = New-ScheduledTaskTrigger -AtStartup
|
|
79
|
+
$Settings = New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
|
|
80
|
+
$Principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
|
81
|
+
|
|
82
|
+
# Remove existing task if present
|
|
83
|
+
Unregister-ScheduledTask -TaskName $ServiceName -Confirm:$false -ErrorAction SilentlyContinue
|
|
84
|
+
|
|
85
|
+
Register-ScheduledTask -TaskName $ServiceName -Action $Action -Trigger $Trigger -Settings $Settings -Principal $Principal -Description $DisplayName
|
|
86
|
+
|
|
87
|
+
Write-Host ""
|
|
88
|
+
Write-Host "=== Installation Complete ===" -ForegroundColor Green
|
|
89
|
+
Write-Host ""
|
|
90
|
+
Write-Host "Next steps:" -ForegroundColor Cyan
|
|
91
|
+
Write-Host " 1. Edit $ConfigPath with your device token"
|
|
92
|
+
Write-Host " 2. Start: Start-ScheduledTask -TaskName '$ServiceName'"
|
|
93
|
+
Write-Host " 3. Stop: Stop-ScheduledTask -TaskName '$ServiceName'"
|
|
94
|
+
Write-Host " 4. Logs: Get-Content $DataDir\agent.log -Tail 50 -Wait"
|
|
95
|
+
Write-Host ""
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import type { EdgeAgentConfig } from './config';
|
|
3
|
+
export declare class EdgeAgent extends EventEmitter {
|
|
4
|
+
private config;
|
|
5
|
+
private platform;
|
|
6
|
+
private camera;
|
|
7
|
+
private audio;
|
|
8
|
+
private socketManager;
|
|
9
|
+
private sensingService;
|
|
10
|
+
private telemetryScheduler;
|
|
11
|
+
private recoveryLadder;
|
|
12
|
+
private browserManager;
|
|
13
|
+
private federatedTrainer;
|
|
14
|
+
private healthRegistry;
|
|
15
|
+
private signalBuffer;
|
|
16
|
+
private running;
|
|
17
|
+
private signalHandlersRegistered;
|
|
18
|
+
private boundShutdownSigint;
|
|
19
|
+
private boundShutdownSigterm;
|
|
20
|
+
constructor(config: EdgeAgentConfig);
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
stop(): Promise<void>;
|
|
23
|
+
private shutdown;
|
|
24
|
+
/**
|
|
25
|
+
* Load the platform-specific adapter using require() so that optional
|
|
26
|
+
* dependencies fail gracefully at runtime when not installed.
|
|
27
|
+
*/
|
|
28
|
+
private loadPlatformAdapter;
|
|
29
|
+
/**
|
|
30
|
+
* Load the platform-specific camera provider using require() for optional deps.
|
|
31
|
+
*/
|
|
32
|
+
private loadCamera;
|
|
33
|
+
/**
|
|
34
|
+
* Load the platform-specific audio provider using require() for optional deps.
|
|
35
|
+
*/
|
|
36
|
+
private loadAudio;
|
|
37
|
+
private log;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=EdgeAgent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EdgeAgent.d.ts","sourceRoot":"","sources":["../src/EdgeAgent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AA6BtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,kBAAkB,CAAmC;IAC7D,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,wBAAwB,CAAS;IACzC,OAAO,CAAC,mBAAmB,CAA6B;IACxD,OAAO,CAAC,oBAAoB,CAA6B;gBAE7C,MAAM,EAAE,eAAe;IAK7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+NtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YA4Bb,QAAQ;IAMtB;;;OAGG;YACW,mBAAmB;IAwBjC;;OAEG;YACW,UAAU;IAoCxB;;OAEG;YACW,SAAS;IAsBvB,OAAO,CAAC,GAAG;CAgBZ"}
|