matterbridge 3.3.3-dev-20251014-44bcdc0 → 3.3.3-dev-20251015-19d1be8

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/CHANGELOG.md CHANGED
@@ -25,9 +25,20 @@ Advantages:
25
25
 
26
26
  ## [3.3.3] - Not released
27
27
 
28
+ ### Added
29
+
30
+ - [thread]: Added timestamp to WorkerMessage.
31
+ - [macOS]: Added the [plist configuration guide](README-MACOS-PLIST.md).
32
+
28
33
  ### Changed
29
34
 
30
35
  - [package]: Updated dependencies.
36
+ - [frontend]: Bumped `frontend` version to 3.2.2.
37
+ - [frontend]: Added update check on start.
38
+ - [frontend]: Added icon to update dev in the Header and removed the yellow badges.
39
+ - [frontend]: Added icon to update plugin latest and dev and removed the yellow badges.
40
+ - [frontend]: Added plugin Path in the Name Tooltip.
41
+ - [history]: Added external and array buffers to the history chart.
31
42
 
32
43
  <a href="https://www.buymeacoffee.com/luligugithub">
33
44
  <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
@@ -0,0 +1,242 @@
1
+ # <img src="frontend/public/matterbridge.svg" alt="Matterbridge Logo" width="64px" height="64px">&nbsp;&nbsp;&nbsp;Matterbridge launchctl configuration (macOS)
2
+
3
+ [![npm version](https://img.shields.io/npm/v/matterbridge.svg)](https://www.npmjs.com/package/matterbridge)
4
+ [![npm downloads](https://img.shields.io/npm/dt/matterbridge.svg)](https://www.npmjs.com/package/matterbridge)
5
+ [![Docker Version](https://img.shields.io/docker/v/luligu/matterbridge?label=docker%20version&sort=semver)](https://hub.docker.com/r/luligu/matterbridge)
6
+ [![Docker Pulls](https://img.shields.io/docker/pulls/luligu/matterbridge.svg)](https://hub.docker.com/r/luligu/matterbridge)
7
+ ![Node.js CI](https://github.com/Luligu/matterbridge/actions/workflows/build.yml/badge.svg)
8
+ ![CodeQL](https://github.com/Luligu/matterbridge/actions/workflows/codeql.yml/badge.svg)
9
+ [![codecov](https://codecov.io/gh/Luligu/matterbridge/branch/main/graph/badge.svg)](https://codecov.io/gh/Luligu/matterbridge)
10
+
11
+ [![power by](https://img.shields.io/badge/powered%20by-matter--history-blue)](https://www.npmjs.com/package/matter-history)
12
+ [![power by](https://img.shields.io/badge/powered%20by-node--ansi--logger-blue)](https://www.npmjs.com/package/node-ansi-logger)
13
+ [![power by](https://img.shields.io/badge/powered%20by-node--persist--manager-blue)](https://www.npmjs.com/package/node-persist-manager)
14
+
15
+ ---
16
+
17
+ # Advanced configuration
18
+
19
+ ## Run matterbridge as system service with launchctl (macOS) and its own global node_modules directory
20
+
21
+ ### Optional: cleanup all previous setups
22
+
23
+ ```bash
24
+ sudo rm -rf ~/Matterbridge
25
+ sudo rm -rf ~/.matterbridge
26
+ sudo rm -rf ~/.mattercert
27
+ sudo rm -rf /usr/local/etc/matterbridge
28
+ sudo rm -f /Library/LaunchDaemons/matterbridge.plist
29
+ sudo rm -f /var/log/matterbridge.log /var/log/matterbridge.err
30
+ sudo npm uninstall matterbridge -g
31
+ ```
32
+
33
+ ### Verify node setup
34
+
35
+ ```bash
36
+ node -v
37
+ npm -v
38
+ ```
39
+
40
+ It should output something like:
41
+
42
+ ```
43
+ v22.20.0
44
+ 10.9.3
45
+ ```
46
+
47
+ ### Check node path
48
+
49
+ ```bash
50
+ which node
51
+ ```
52
+
53
+ It should output something like:
54
+
55
+ ```
56
+ /usr/local/bin/node
57
+ ```
58
+
59
+ In this case you will need in the step below to replace **_MYNODEPATH_** with /usr/local/bin
60
+
61
+ ### First create the Matterbridge directories
62
+
63
+ This will create the required directories if they don't exist and install matterbridge in the matterbridge global node_modules directory
64
+
65
+ ```bash
66
+ sudo mkdir -p /usr/local/etc/matterbridge
67
+ sudo mkdir -p /usr/local/etc/matterbridge/.npm-global
68
+ sudo mkdir -p /usr/local/etc/matterbridge/Matterbridge
69
+ sudo mkdir -p /usr/local/etc/matterbridge/.matterbridge
70
+ sudo mkdir -p /usr/local/etc/matterbridge/.mattercert
71
+ sudo chown -R root:wheel /usr/local/etc/matterbridge
72
+ sudo chown -R root:wheel /usr/local/etc/matterbridge/.npm-global
73
+ sudo chmod -R 755 /usr/local/etc/matterbridge/.npm-global
74
+ sudo NPM_CONFIG_PREFIX=/usr/local/etc/matterbridge/.npm-global npm install -g matterbridge --omit=dev
75
+ ```
76
+
77
+ ### Then create a system launchctl configuration file for Matterbridge
78
+
79
+ - create a launchctl configuration file for Matterbridge
80
+
81
+ ```bash
82
+ sudo nano /Library/LaunchDaemons/matterbridge.plist
83
+ ```
84
+
85
+ - add the following to the file, replacing **_MYNODEPATH_** with the path found in the step before:
86
+
87
+ ```
88
+ <?xml version="1.0" encoding="UTF-8"?>
89
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
90
+ <plist version="1.0">
91
+ <dict>
92
+ <key>EnvironmentVariables</key>
93
+ <dict>
94
+ <key>PATH</key>
95
+ <string>/usr/local/etc/matterbridge/.npm-global/bin:MYNODEPATH</string>
96
+ <key>NPM_CONFIG_PREFIX</key>
97
+ <string>/usr/local/etc/matterbridge/.npm-global</string>
98
+ <key>HOME</key>
99
+ <string>/var/root</string>
100
+ <key>NODE_PATH</key>
101
+ <string>/usr/local/etc/matterbridge/.npm-global/lib/node_modules</string>
102
+ </dict>
103
+ <key>KeepAlive</key>
104
+ <true/>
105
+ <key>Label</key>
106
+ <string>matterbridge</string>
107
+ <key>ProgramArguments</key>
108
+ <array>
109
+ <string>/usr/local/etc/matterbridge/.npm-global/bin/matterbridge</string>
110
+ <string>--homedir</string>
111
+ <string>/usr/local/etc/matterbridge</string>
112
+ <string>--service</string>
113
+ <string>--nosudo</string>
114
+ </array>
115
+ <key>RunAtLoad</key>
116
+ <true/>
117
+ <key>StandardErrorPath</key>
118
+ <string>/var/log/matterbridge.err</string>
119
+ <key>StandardOutPath</key>
120
+ <string>/var/log/matterbridge.log</string>
121
+ <key>WorkingDirectory</key>
122
+ <string>/usr/local/etc/matterbridge</string>
123
+ </dict>
124
+ </plist>
125
+ ```
126
+
127
+ - stop matterbridge
128
+
129
+ ```bash
130
+ sudo launchctl bootout system/matterbridge
131
+ ```
132
+
133
+ - check the plist
134
+
135
+ ```bash
136
+ sudo chown root:wheel /Library/LaunchDaemons/matterbridge.plist
137
+ sudo chmod 644 /Library/LaunchDaemons/matterbridge.plist
138
+ sudo plutil -lint /Library/LaunchDaemons/matterbridge.plist
139
+ sudo plutil -convert xml1 /Library/LaunchDaemons/matterbridge.plist
140
+ ```
141
+
142
+ - bootstrap matterbridge and enable it
143
+
144
+ ```bash
145
+ sudo rm -f /var/log/matterbridge.log /var/log/matterbridge.err
146
+ sudo launchctl bootstrap system /Library/LaunchDaemons/matterbridge.plist
147
+ sudo launchctl enable system/matterbridge
148
+ ```
149
+
150
+ ### Start Matterbridge
151
+
152
+ ```bash
153
+ sudo launchctl kickstart -k system/matterbridge
154
+ ```
155
+
156
+ ### Stop Matterbridge
157
+
158
+ ```bash
159
+ sudo launchctl bootout system/matterbridge
160
+ ```
161
+
162
+ ### Restart Matterbridge
163
+
164
+ ```bash
165
+ sudo launchctl kickstart -k system/matterbridge
166
+ ```
167
+
168
+ ### Show Matterbridge status
169
+
170
+ ```bash
171
+ sudo launchctl print system/matterbridge
172
+ ```
173
+
174
+ ### Show Matterbridge status (only essentials)
175
+
176
+ ```bash
177
+ sudo launchctl print system/matterbridge | grep -E "pid|state"
178
+ ```
179
+
180
+ ### Enable Matterbridge to start automatically on boot
181
+
182
+ ```bash
183
+ sudo launchctl enable system/matterbridge
184
+ ```
185
+
186
+ ### Disable Matterbridge from starting automatically on boot
187
+
188
+ ```bash
189
+ sudo launchctl disable system/matterbridge
190
+ ```
191
+
192
+ ### View the log of Matterbridge in real time (this will show the log with colors)
193
+
194
+ ```bash
195
+ sudo tail -n 1000 -f /var/log/matterbridge.log /var/log/matterbridge.err
196
+ ```
197
+
198
+ ### Automatically rotate logs (every 5 days or at 100 MB, keep 5 compressed backups)
199
+
200
+ ```bash
201
+ sudo tee /etc/newsyslog.d/matterbridge.conf <<'EOF'
202
+ /var/log/matterbridge.log root:wheel 640 5 102400 5 Z
203
+ /var/log/matterbridge.err root:wheel 640 5 102400 5 Z
204
+ EOF
205
+ sudo newsyslog -v
206
+ ```
207
+
208
+ ### Optional: remove the password prompt for sudo
209
+
210
+ ```bash
211
+ sudo EDITOR=nano visudo
212
+ ```
213
+
214
+ Add this line at the end of the file (replace USER with your macOS username):
215
+
216
+ ```
217
+ USER ALL=(ALL) NOPASSWD: ALL
218
+ ```
219
+
220
+ Save and validate syntax:
221
+
222
+ ```bash
223
+ sudo visudo -c
224
+ ```
225
+
226
+ ### Optional: ask for password only each 60 minutes
227
+
228
+ ```bash
229
+ sudo EDITOR=nano visudo
230
+ ```
231
+
232
+ Add (or edit) this line anywhere in the file:
233
+
234
+ ```
235
+ Defaults timestamp_timeout = 60
236
+ ```
237
+
238
+ Save and validate syntax:
239
+
240
+ ```bash
241
+ sudo visudo -c
242
+ ```
package/README-SERVICE.md CHANGED
@@ -169,7 +169,7 @@ sudo systemctl restart systemd-journald
169
169
  Run the following command to verify if you can install Matterbridge globally without being prompted for a password:
170
170
 
171
171
  ```bash
172
- sudo npm install -g matterbridge
172
+ sudo npm install -g matterbridge --omit=dev
173
173
  ```
174
174
 
175
175
  If you are not prompted for a password, no further action is required.
@@ -210,3 +210,9 @@ save the file and reload the settings with:
210
210
  sudo chmod 0440 /etc/sudoers.d/matterbridge
211
211
  sudo visudo -c
212
212
  ```
213
+
214
+ Verify if you can install Matterbridge globally without being prompted for a password:
215
+
216
+ ```bash
217
+ sudo npm install -g matterbridge --omit=dev
218
+ ```
package/README.md CHANGED
@@ -84,7 +84,7 @@ Since Matter is designed as "a universal IPv6-based communication protocol for s
84
84
 
85
85
  Avoid using VLAN and firewall blocking the communications between the controllers and Matterbridge.
86
86
 
87
- To pair matterbridge, you need a matter enabled controller (Apple Home, Smart Things, Google Home, Alexa, Hose Assistant etc.).
87
+ To pair matterbridge, you need a matter enabled controller (Apple Home, Smart Things, Google Home, Alexa, Home Assistant etc.).
88
88
 
89
89
  ## Installation
90
90
 
@@ -172,6 +172,10 @@ Config editor:
172
172
 
173
173
  [Service configurations](README-SERVICE.md)
174
174
 
175
+ ### Run matterbridge as a system service with launchctl (macOS only)
176
+
177
+ [Launchctl configurations](README-MACOS-PLIST.md)
178
+
175
179
  ### Run matterbridge with docker and docker compose
176
180
 
177
181
  [Docker configurations](README-DOCKER.md)
@@ -180,10 +184,6 @@ Config editor:
180
184
 
181
185
  [Podman configurations](README-PODMAN.md)
182
186
 
183
- ### Run matterbridge as a service on macOS with mb-service (by [Michael Ahern](https://github.com/michaelahern))
184
-
185
- [Matterbridge Service Command for macOS](https://github.com/michaelahern/mb-service)
186
-
187
187
  ### Run matterbridge with nginx
188
188
 
189
189
  [Nginx configurations](README-NGINX.md)
@@ -2,7 +2,7 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
2
2
  console.log('\u001B[32mCli history loaded.\u001B[40;0m');
3
3
  import { writeFileSync } from 'node:fs';
4
4
  import path from 'node:path';
5
- export const historySize = 4320;
5
+ export const historySize = 2880;
6
6
  export let historyIndex = 0;
7
7
  export function setHistoryIndex(index) {
8
8
  if (!Number.isFinite(index) || !Number.isSafeInteger(index)) {
@@ -70,10 +70,12 @@ export function generateHistoryPage(options = {}) {
70
70
  peakArrayBuffers,
71
71
  };
72
72
  const html = `<!DOCTYPE html>
73
- <html lang="en">
73
+ <html lang="en" translate="no">
74
74
  <head>
75
75
  <meta charset="UTF-8" />
76
76
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
77
+ <meta name="google" content="notranslate" />
78
+ <meta http-equiv="Content-Language" content="en" />
77
79
  <title>${escapeHtml(pageTitle)}</title>
78
80
  <link rel="preconnect" href="https://fonts.googleapis.com" />
79
81
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@@ -251,6 +253,11 @@ export function generateHistoryPage(options = {}) {
251
253
  <canvas id="memoryChart"></canvas>
252
254
  </section>
253
255
 
256
+ <section class="card">
257
+ <h2>External and Array Buffers (MB)</h2>
258
+ <canvas id="extArrayChart"></canvas>
259
+ </section>
260
+
254
261
  <section class="card">
255
262
  <h2>Samples</h2>
256
263
  <div class="table-wrapper">
@@ -371,6 +378,31 @@ export function generateHistoryPage(options = {}) {
371
378
  }, 0);
372
379
  const memoryMaxYAxis = Number.isFinite(memoryMaxMb) && memoryMaxMb > 0 ? memoryMaxMb * 1.05 : undefined;
373
380
 
381
+ // Compute External/ArrayBuffers chart dynamic min/max
382
+ const extArrayMinMb = HISTORY_DATA.reduce(function (acc, entry) {
383
+ const values = [entry.external, entry.arrayBuffers].map(bytesToMb);
384
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
385
+ const minEntry = finiteValues.length ? Math.min.apply(Math, finiteValues) : acc;
386
+ return Math.min(acc, minEntry);
387
+ }, Number.POSITIVE_INFINITY);
388
+
389
+ const extArrayMinYAxis = Number.isFinite(extArrayMinMb) && extArrayMinMb > 0
390
+ ? Math.max(0, extArrayMinMb - extArrayMinMb * 0.1)
391
+ : 0;
392
+
393
+ const extArrayMaxMb = HISTORY_DATA.reduce(function (acc, entry) {
394
+ const values = [
395
+ entry.external,
396
+ entry.arrayBuffers,
397
+ entry.peakExternal,
398
+ entry.peakArrayBuffers,
399
+ ].map(bytesToMb);
400
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
401
+ const maxEntry = finiteValues.length ? Math.max.apply(Math, finiteValues) : acc;
402
+ return Math.max(acc, maxEntry);
403
+ }, 0);
404
+ const extArrayMaxYAxis = Number.isFinite(extArrayMaxMb) && extArrayMaxMb > 0 ? extArrayMaxMb * 1.05 : undefined;
405
+
374
406
  renderCharts();
375
407
 
376
408
  function renderCharts() {
@@ -386,7 +418,14 @@ export function generateHistoryPage(options = {}) {
386
418
  return Number.isFinite(entry.cpu) ? Number(entry.cpu.toFixed(2)) : 0;
387
419
  }),
388
420
  color: '#38bdf8',
389
- fill: 'rgba(56, 189, 248, 0.18)'
421
+ fill: 'rgba(56, 189, 248, 0.18)',
422
+ markPeaks: true,
423
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
424
+ if (Number.isFinite(entry.peakCpu)) return entry.peakCpu;
425
+ if (Number.isFinite(entry.cpu)) return entry.cpu;
426
+ return Number.NEGATIVE_INFINITY;
427
+ }),
428
+ markerRadius: 2.5
390
429
  },
391
430
  {
392
431
  label: 'Host Peak CPU %',
@@ -413,7 +452,14 @@ export function generateHistoryPage(options = {}) {
413
452
  return Number.isFinite(entry.processCpu) ? Number(entry.processCpu.toFixed(2)) : 0;
414
453
  }),
415
454
  color: '#a855f7',
416
- fill: 'rgba(168, 85, 247, 0.18)'
455
+ fill: 'rgba(168, 85, 247, 0.18)',
456
+ markPeaks: true,
457
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
458
+ if (Number.isFinite(entry.peakProcessCpu)) return entry.peakProcessCpu;
459
+ if (Number.isFinite(entry.processCpu)) return entry.processCpu;
460
+ return Number.NEGATIVE_INFINITY;
461
+ }),
462
+ markerRadius: 2.5
417
463
  },
418
464
  {
419
465
  label: 'Process Peak CPU %',
@@ -444,17 +490,38 @@ export function generateHistoryPage(options = {}) {
444
490
  label: 'RSS (MB)',
445
491
  values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.rss); }),
446
492
  color: '#34d399',
447
- fill: 'rgba(52, 211, 153, 0.18)'
493
+ fill: 'rgba(52, 211, 153, 0.18)',
494
+ markPeaks: true,
495
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
496
+ if (Number.isFinite(entry.peakRss)) return entry.peakRss;
497
+ if (Number.isFinite(entry.rss)) return entry.rss;
498
+ return Number.NEGATIVE_INFINITY;
499
+ }),
500
+ markerRadius: 2.5
448
501
  },
449
502
  {
450
503
  label: 'Heap Total (MB)',
451
504
  values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.heapTotal); }),
452
- color: '#fb923c'
505
+ color: '#fb923c',
506
+ markPeaks: true,
507
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
508
+ if (Number.isFinite(entry.peakHeapTotal)) return entry.peakHeapTotal;
509
+ if (Number.isFinite(entry.heapTotal)) return entry.heapTotal;
510
+ return Number.NEGATIVE_INFINITY;
511
+ }),
512
+ markerRadius: 2.5
453
513
  },
454
514
  {
455
515
  label: 'Heap Used (MB)',
456
516
  values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.heapUsed); }),
457
- color: '#f472b6'
517
+ color: '#f472b6',
518
+ markPeaks: true,
519
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
520
+ if (Number.isFinite(entry.peakHeapUsed)) return entry.peakHeapUsed;
521
+ if (Number.isFinite(entry.heapUsed)) return entry.heapUsed;
522
+ return Number.NEGATIVE_INFINITY;
523
+ }),
524
+ markerRadius: 2.5
458
525
  }
459
526
  ],
460
527
  minY: memoryMinYAxis,
@@ -463,6 +530,43 @@ export function generateHistoryPage(options = {}) {
463
530
  return value.toFixed(0) + ' MB';
464
531
  }
465
532
  });
533
+
534
+ // External and Array Buffers chart
535
+ renderLineChart('extArrayChart', {
536
+ labels: labels,
537
+ datasets: [
538
+ {
539
+ label: 'External (MB)',
540
+ values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.external); }),
541
+ color: '#60a5fa',
542
+ fill: 'rgba(96, 165, 250, 0.18)',
543
+ markPeaks: true,
544
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
545
+ if (Number.isFinite(entry.peakExternal)) return entry.peakExternal;
546
+ if (Number.isFinite(entry.external)) return entry.external;
547
+ return Number.NEGATIVE_INFINITY;
548
+ }),
549
+ markerRadius: 2.5
550
+ },
551
+ {
552
+ label: 'Array Buffers (MB)',
553
+ values: HISTORY_DATA.map(function (entry) { return bytesToMb(entry.arrayBuffers); }),
554
+ color: '#22d3ee',
555
+ markPeaks: true,
556
+ markerPeakValues: HISTORY_DATA.map(function (entry) {
557
+ if (Number.isFinite(entry.peakArrayBuffers)) return entry.peakArrayBuffers;
558
+ if (Number.isFinite(entry.arrayBuffers)) return entry.arrayBuffers;
559
+ return Number.NEGATIVE_INFINITY;
560
+ }),
561
+ markerRadius: 2.5
562
+ }
563
+ ],
564
+ minY: extArrayMinYAxis,
565
+ maxY: extArrayMaxYAxis,
566
+ yFormatter: function (value) {
567
+ return value.toFixed(0) + ' MB';
568
+ }
569
+ });
466
570
  }
467
571
 
468
572
  draw();
@@ -634,6 +738,29 @@ export function generateHistoryPage(options = {}) {
634
738
  });
635
739
  ctx.stroke();
636
740
  ctx.setLineDash([]);
741
+
742
+ // Draw new-peak markers if enabled
743
+ if (dataset.markPeaks) {
744
+ let runningMax = -Infinity;
745
+ const radius = Number.isFinite(dataset.markerRadius) ? dataset.markerRadius : 2.5;
746
+ ctx.save();
747
+ ctx.fillStyle = dataset.markerColor || dataset.color;
748
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.85)';
749
+ ctx.lineWidth = 1;
750
+ const peakSeries = Array.isArray(dataset.markerPeakValues) ? dataset.markerPeakValues : dataset.values;
751
+ peakSeries.forEach(function (value, idx) {
752
+ if (!Number.isFinite(value)) return;
753
+ if (value > runningMax) {
754
+ runningMax = value;
755
+ const p = points[idx];
756
+ ctx.beginPath();
757
+ ctx.arc(p.x, p.y, radius, 0, Math.PI * 2);
758
+ ctx.fill();
759
+ ctx.stroke();
760
+ }
761
+ });
762
+ ctx.restore();
763
+ }
637
764
  });
638
765
 
639
766
  ctx.setTransform(1, 0, 0, 1, 0, 0);
@@ -1 +1 @@
1
- body{font-family:Roboto,sans-serif}[frontend-theme=classic]{--main-bg-color: #c4c2c2;--main-text-color: black;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: #4d4d4d;--main-log-color: var(--main-text-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: #26292d;--main-menu-bg-color: #e2e2e2;--main-menu-hover-color: #959595;--main-label-color: var(--main-grey-color);--primary-color: #009a00;--secondary-color: #92771f;--header-bg-color: var(--primary-color);--header-text-color: white;--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: #ddd;--table-text-color: black;--table-even-bg-color: #bdbdbd;--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #5f8c9e;--table-selected-bg-color: #5f8c9e;--div-bg-color: #adadad;--div-text-color: black;--div-shadow-color: #888;--div-border-color: rgb(139, 139, 139);--div-border-radius: 0px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: black;background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=dark]{--main-bg-color: #26292d;--main-text-color: #ffffff;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: var(--main-light-color);--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-light-color);--main-menu-bg-color: var(--main-bg-color);--main-menu-hover-color: var(--div-bg-color);--main-label-color: var(--main-grey-color);--primary-color: #1976d2;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--primary-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: var(--main-bg-color);--table-selected-bg-color: var(--main-bg-color);--div-bg-color: #1b1d21;--div-text-color: var(--main-light-color);--div-shadow-color: #34373d;--div-border-color: #1b1d21;--div-border-radius: 5px;--div-title-bg-color: #1b1d21;--div-title-text-color: var(--primary-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=light]{--main-bg-color: #f0f0f0;--main-text-color: #212121;--main-grey-color: #616161;--main-light-color: #363636;--main-icon-color: #7a7a7a;--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-text-color);--main-menu-bg-color: var(--div-bg-color);--main-menu-hover-color: #85c0d8;--main-label-color: var(--main-grey-color);--primary-color: #2196f3;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--div-text-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #85c0d8;--table-selected-bg-color: #85c0d8;--div-bg-color: #ffffff;--div-text-color: #212121;--div-shadow-color: #bfbfbf;--div-border-color: var(--div-bg-color);--div-border-radius: 5px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: var(--div-text-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-track{background:"inherit"}html,.thin-scroll{scrollbar-width:thin;scrollbar-color:var(--primary-color) var(--div-bg-color)}.thin-scroll::-webkit-scrollbar{width:5px;height:5px}.thin-scroll::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}.tooltip-container{position:relative;display:inline-block;z-index:10}.tooltip-text{visibility:hidden;background-color:var(--ttip-bg-color);color:var(--ttip-text-color);text-align:center;padding:5px;border-radius:6px;position:absolute;z-index:10;bottom:calc(100% + 10px);left:50%;margin-left:-60px;opacity:0;transition:opacity .3s;font-size:12px}.tooltip-container:hover{cursor:pointer;z-index:10}.tooltip-container:hover .tooltip-text{visibility:visible;opacity:1;z-index:10}.status-enabled{background-color:green;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-disabled{background-color:red;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-information{background-color:#9e9e9e;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-warning{background-color:#e9db18;color:#000;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-sponsor{background-color:#b6409c;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-blue{background-color:#5f8c9e;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:20px;margin:0;padding:0;height:40px}.sub-header{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:20px;margin:0;padding:0;height:40px}nav{display:flex;align-items:center}.nav-link{margin:0 10px;font-size:20px;text-decoration:none;color:var(--main-icon-color);transition:color .3s ease}.nav-link:hover{color:var(--primary-color)}table{border-collapse:collapse;width:100%;table-layout:auto}thead{position:sticky;top:0;border:1px solid var(--table-border-color);z-index:10}thead th{border:1px solid var(--table-border-color);padding:5px 10px;color:var(--header-text-color);background:var(--header-bg-color);text-align:left;z-index:10}tbody td{border:1px solid var(--table-border-color);margin:0;padding:5px 10px;text-align:left;font-size:14px}tbody tr:hover{color:var(--table-text-color);background-color:var(--table-hover-bg-color)}.table-content-even{color:var(--table-text-color);background-color:var(--table-even-bg-color)}.table-content-odd{color:var(--table-text-color);background-color:var(--table-odd-bg-color)}.table-content-selected{color:var(--table-text-color);background-color:var(--table-selected-bg-color)}h3{margin:0}.MbfScreen{display:flex;flex-direction:column;width:calc(100vw - 40px);height:calc(100vh - 40px);gap:20px;margin:0;padding:20px;background-color:var(--main-bg-color)}.MbfPageDiv{display:flex;flex-direction:column;height:100%;width:100%;margin:0;padding:0;gap:20px}.MbfWindowDiv{display:flex;flex-direction:column;box-shadow:5px 5px 10px var(--div-shadow-color);border:1px solid var(--table-border-color);border-radius:var(--div-border-radius);box-sizing:border-box;background-color:var(--div-bg-color)}.MbfWindowDivTable{display:flex;flex-direction:column;flex:1 1 auto;margin:-1px;padding:0;gap:0;overflow:auto;display:block}.MbfWindowHeaderFooterIcons{display:flex;flex-direction:row;margin:0;padding:0 10px;gap:10px}.MbfWindowHeader{display:flex;flex-direction:row;align-items:center;width:100%;border-bottom:1px solid var(--table-border-color);color:var(--header-text-color);background-color:var(--header-bg-color);margin:0;padding:0;box-sizing:border-box}.MbfWindowHeaderText{color:var(--header-text-color);font-weight:700;margin:0;padding:5px 10px}.MbfWindowFooter{display:flex;flex-direction:row;align-items:center;justify-content:center;color:var(--footer-text-color);background-color:var(--footer-bg-color);margin:0;padding:0}.MbfWindowFooterText{color:var(--footer-text-color);background-color:var(--footer-bg-color);font-weight:700;text-align:center;margin:0;padding:5px 10px}.MbfWindowBody{display:flex;flex:1 1 auto;margin:0;padding:10px;gap:10px}.MbfWindowBodyColumn{display:flex;flex-direction:column;flex:1 1 auto;width:100%;margin:0;padding:10px 0;gap:0px;overflow:auto}.MbfWindowBodyRow{display:flex;flex-direction:row;flex:1 1 auto;height:100%;margin:0;padding:0 10px;gap:0px;overflow:auto}.configSubmitButton{display:flex;flex-direction:row;justify-content:center;width:auto;margin:20px}.configSubmitButton button{width:auto}@media (max-width: 1300px){.MbfScreen{width:1300px;height:1024px}.xxxheader{flex-direction:column;align-items:start;justify-content:start}.xxxsub-header{align-items:start;justify-content:start}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
1
+ body{font-family:Roboto,sans-serif}[frontend-theme=classic]{--main-bg-color: #c4c2c2;--main-text-color: black;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: #4d4d4d;--main-log-color: var(--main-text-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: #26292d;--main-menu-bg-color: #e2e2e2;--main-menu-hover-color: #959595;--main-label-color: var(--main-grey-color);--primary-color: #009a00;--secondary-color: #92771f;--header-bg-color: var(--primary-color);--header-text-color: white;--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: #ddd;--table-text-color: black;--table-even-bg-color: #bdbdbd;--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #5f8c9e;--table-selected-bg-color: #5f8c9e;--div-bg-color: #adadad;--div-text-color: black;--div-shadow-color: #888;--div-border-color: rgb(139, 139, 139);--div-border-radius: 0px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: black;background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=dark]{--main-bg-color: #26292d;--main-text-color: #ffffff;--main-grey-color: #616161;--main-light-color: #959595;--main-icon-color: var(--main-light-color);--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-light-color);--main-menu-bg-color: var(--main-bg-color);--main-menu-hover-color: var(--div-bg-color);--main-label-color: var(--main-grey-color);--primary-color: #1976d2;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--primary-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: var(--main-bg-color);--table-selected-bg-color: var(--main-bg-color);--div-bg-color: #1b1d21;--div-text-color: var(--main-light-color);--div-shadow-color: #34373d;--div-border-color: #1b1d21;--div-border-radius: 5px;--div-title-bg-color: #1b1d21;--div-title-text-color: var(--primary-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}[frontend-theme=light]{--main-bg-color: #f0f0f0;--main-text-color: #212121;--main-grey-color: #616161;--main-light-color: #363636;--main-icon-color: #7a7a7a;--main-log-color: var(--main-light-color);--main-button-color: #ffffff;--main-button-bg-color: var(--primary-color);--main-menu-color: var(--main-text-color);--main-menu-bg-color: var(--div-bg-color);--main-menu-hover-color: #85c0d8;--main-label-color: var(--main-grey-color);--primary-color: #2196f3;--secondary-color: #a58827;--header-bg-color: var(--div-bg-color);--header-text-color: var(--div-text-color);--footer-bg-color: var(--div-bg-color);--footer-text-color: var(--div-text-color);--ttip-bg-color: #555;--ttip-text-color: #fff;--table-border-color: var(--div-bg-color);--table-text-color: var(--main-light-color);--table-even-bg-color: var(--div-bg-color);--table-odd-bg-color: var(--div-bg-color);--table-hover-bg-color: #85c0d8;--table-selected-bg-color: #85c0d8;--div-bg-color: #ffffff;--div-text-color: #212121;--div-shadow-color: #bfbfbf;--div-border-color: var(--div-bg-color);--div-border-radius: 5px;--div-title-bg-color: var(--div-bg-color);--div-title-text-color: var(--div-text-color);background-color:var(--main-bg-color);color:var(--main-text-color);font-family:Roboto,Helvetica,Arial,sans-serif}::-webkit-scrollbar{width:10px}::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-thumb:hover{background:var(--primary-color);border-radius:5px}::-webkit-scrollbar-track{background:"inherit"}html,.thin-scroll{scrollbar-width:thin;scrollbar-color:var(--primary-color) var(--div-bg-color)}.thin-scroll::-webkit-scrollbar{width:5px;height:5px}.thin-scroll::-webkit-scrollbar-thumb{background:var(--primary-color);border-radius:5px}.tooltip-container{position:relative;display:inline-block;z-index:10}.tooltip-text{visibility:hidden;background-color:var(--ttip-bg-color);color:var(--ttip-text-color);text-align:center;padding:5px;border-radius:6px;position:absolute;z-index:10;bottom:calc(100% + 10px);left:50%;margin-left:-60px;opacity:0;transition:opacity .3s;font-size:12px}.tooltip-container:hover{cursor:pointer;z-index:10}.tooltip-container:hover .tooltip-text{visibility:visible;opacity:1;z-index:10}.status-enabled{background-color:green;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-disabled{background-color:red;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-information{background-color:#9e9e9e;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-warning{background-color:#e9db18;color:#000;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-sponsor{background-color:#b6409c;color:#fff;padding:2px 10px;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.status-blue{background-color:#5f8c9e;color:#fff;padding:.2rem;border-radius:.25rem;text-align:center;font-size:12px;cursor:pointer;box-shadow:2px 2px 2px #0003}.header{display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:20px;margin:0;padding:0;height:40px}.sub-header{flex:0 0 auto;display:flex;flex-direction:row;align-items:center;gap:20px;margin:0;padding:0;height:40px}nav{display:flex;align-items:center;gap:10px}.nav-link{margin:0;font-size:20px;text-decoration:none;color:var(--main-icon-color);transition:color .3s ease}.nav-link:hover{color:var(--primary-color)}table{border-collapse:collapse;width:100%;table-layout:auto}thead{position:sticky;top:0;border:1px solid var(--table-border-color);z-index:10}thead th{border:1px solid var(--table-border-color);padding:5px 10px;color:var(--header-text-color);background:var(--header-bg-color);text-align:left;z-index:10}tbody td{border:1px solid var(--table-border-color);margin:0;padding:5px 10px;text-align:left;font-size:14px}tbody tr:hover{color:var(--table-text-color);background-color:var(--table-hover-bg-color)}.table-content-even{color:var(--table-text-color);background-color:var(--table-even-bg-color)}.table-content-odd{color:var(--table-text-color);background-color:var(--table-odd-bg-color)}.table-content-selected{color:var(--table-text-color);background-color:var(--table-selected-bg-color)}h3{margin:0}.MbfScreen{display:flex;flex-direction:column;width:calc(100vw - 40px);height:calc(100vh - 40px);gap:20px;margin:0;padding:20px;background-color:var(--main-bg-color)}.MbfPageDiv{display:flex;flex-direction:column;height:100%;width:100%;margin:0;padding:0;gap:20px}.MbfWindowDiv{display:flex;flex-direction:column;box-shadow:5px 5px 10px var(--div-shadow-color);border:1px solid var(--table-border-color);border-radius:var(--div-border-radius);box-sizing:border-box;background-color:var(--div-bg-color)}.MbfWindowDivTable{display:flex;flex-direction:column;flex:1 1 auto;margin:-1px;padding:0;gap:0;overflow:auto;display:block}.MbfWindowHeaderFooterIcons{display:flex;flex-direction:row;margin:0;padding:0 10px;gap:10px}.MbfWindowHeader{display:flex;flex-direction:row;align-items:center;width:100%;border-bottom:1px solid var(--table-border-color);color:var(--header-text-color);background-color:var(--header-bg-color);margin:0;padding:0;box-sizing:border-box}.MbfWindowHeaderText{color:var(--header-text-color);font-weight:700;margin:0;padding:5px 10px}.MbfWindowFooter{display:flex;flex-direction:row;align-items:center;justify-content:center;color:var(--footer-text-color);background-color:var(--footer-bg-color);margin:0;padding:0}.MbfWindowFooterText{color:var(--footer-text-color);background-color:var(--footer-bg-color);font-weight:700;text-align:center;margin:0;padding:5px 10px}.MbfWindowBody{display:flex;flex:1 1 auto;margin:0;padding:10px;gap:10px}.MbfWindowBodyColumn{display:flex;flex-direction:column;flex:1 1 auto;width:100%;margin:0;padding:10px 0;gap:0px;overflow:auto}.MbfWindowBodyRow{display:flex;flex-direction:row;flex:1 1 auto;height:100%;margin:0;padding:0 10px;gap:0px;overflow:auto}.configSubmitButton{display:flex;flex-direction:row;justify-content:center;width:auto;margin:20px}.configSubmitButton button{width:auto}@media (max-width: 1300px){.MbfScreen{width:1300px;height:1024px}.xxxheader{flex-direction:column;align-items:start;justify-content:start}.xxxsub-header{align-items:start;justify-content:start}}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}