@ciphore/radiocli 0.2.2 → 0.2.3
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 +47 -1
- package/README.md +30 -0
- package/dist/agent/alarm-service.js +210 -0
- package/dist/agent/cli.js +193 -0
- package/dist/agent/headless-host.js +143 -0
- package/dist/agent/launcher.js +71 -0
- package/dist/agent/mcp-install.js +467 -0
- package/dist/agent/mcp-server.js +139 -0
- package/dist/agent/service.js +347 -0
- package/dist/agent/session.js +248 -0
- package/dist/alarms/cli.js +4 -1
- package/dist/alarms/runner.js +43 -26
- package/dist/cli.js +60 -3
- package/dist/player/player-controller.js +19 -0
- package/dist/providers/provider-manager.js +5 -0
- package/dist/providers/radio-browser.js +4 -0
- package/dist/setup.js +71 -2
- package/dist/storage/store.js +33 -1
- package/dist/types.js +6 -0
- package/dist/ui/AdaptiveContent.js +24 -9
- package/dist/ui/App.js +299 -18
- package/dist/ui/AppContent.js +4 -4
- package/dist/ui/components/StationList.js +3 -5
- package/dist/ui/components/VersionIndicator.js +19 -0
- package/dist/ui/page-footer.js +4 -2
- package/dist/ui/screen-items.js +40 -9
- package/dist/ui/screens/AlarmsScreen.js +2 -1
- package/dist/ui/screens/CountriesScreen.js +8 -5
- package/dist/ui/screens/HomeScreen.js +3 -1
- package/dist/ui/screens/SettingsScreen.js +70 -53
- package/dist/ui/use-alarm-tui.js +4 -0
- package/dist/ui/use-app-input.js +29 -3
- package/dist/ui/visualizers/gallop.js +118 -0
- package/dist/ui/visualizers/horse-stride.js +20 -0
- package/dist/ui/visualizers/receiver-style-registry.js +12 -2
- package/dist/ui/visualizers/receiver-visualizers.js +3 -0
- package/dist/ui/visualizers/retro-receivers.js +4 -0
- package/dist/ui/visualizers/terminal-receivers.js +57 -0
- package/dist/update-check.js +26 -7
- package/package.json +4 -1
package/dist/ui/screen-items.js
CHANGED
|
@@ -11,7 +11,9 @@ export const homeItems = [
|
|
|
11
11
|
];
|
|
12
12
|
export const settingsGroups = [
|
|
13
13
|
{
|
|
14
|
-
|
|
14
|
+
id: 'playback',
|
|
15
|
+
label: 'Playback & audio',
|
|
16
|
+
description: 'Output, volume, AirPlay, and startup behavior',
|
|
15
17
|
items: [
|
|
16
18
|
'Audio output',
|
|
17
19
|
'AirPlay receiver',
|
|
@@ -23,7 +25,9 @@ export const settingsGroups = [
|
|
|
23
25
|
]
|
|
24
26
|
},
|
|
25
27
|
{
|
|
26
|
-
|
|
28
|
+
id: 'appearance',
|
|
29
|
+
label: 'Appearance',
|
|
30
|
+
description: 'Colors, receiver style, motion, and terminal display',
|
|
27
31
|
items: [
|
|
28
32
|
'Cycle display color',
|
|
29
33
|
'Cycle receiver style',
|
|
@@ -34,22 +38,40 @@ export const settingsGroups = [
|
|
|
34
38
|
]
|
|
35
39
|
},
|
|
36
40
|
{
|
|
37
|
-
|
|
41
|
+
id: 'discovery',
|
|
42
|
+
label: 'Discovery & providers',
|
|
43
|
+
description: 'Location, station directories, privacy, and provider health',
|
|
38
44
|
items: [
|
|
39
45
|
'Toggle nearby location lookup',
|
|
40
46
|
'Toggle Radio Garden experimental adapter',
|
|
41
|
-
'Share favorite votes with Radio Browser'
|
|
47
|
+
'Share favorite votes with Radio Browser',
|
|
48
|
+
'Refresh provider health'
|
|
42
49
|
]
|
|
43
50
|
},
|
|
44
51
|
{
|
|
45
|
-
|
|
52
|
+
id: 'data',
|
|
53
|
+
label: 'Data & library',
|
|
54
|
+
description: 'Back up or restore preferences and saved stations',
|
|
46
55
|
items: [
|
|
47
56
|
'Export preferences and library',
|
|
48
57
|
'Import preferences and library'
|
|
49
58
|
]
|
|
50
59
|
},
|
|
51
60
|
{
|
|
61
|
+
id: 'agent',
|
|
62
|
+
label: 'Agent control & MCP',
|
|
63
|
+
description: 'Local agent access and MCP playback behavior',
|
|
64
|
+
items: [
|
|
65
|
+
'Allow local agent control',
|
|
66
|
+
'Install or repair MCP integrations',
|
|
67
|
+
'Open TUI for agent playback',
|
|
68
|
+
'Show Now Playing for agent playback'
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'media-keys',
|
|
52
73
|
label: 'Media keys',
|
|
74
|
+
description: 'Teach RadioCLI your keyboard playback controls',
|
|
53
75
|
items: [
|
|
54
76
|
'Learn previous media key',
|
|
55
77
|
'Learn play/pause media key',
|
|
@@ -58,14 +80,23 @@ export const settingsGroups = [
|
|
|
58
80
|
]
|
|
59
81
|
},
|
|
60
82
|
{
|
|
61
|
-
|
|
83
|
+
id: 'updates',
|
|
84
|
+
label: 'Updates',
|
|
85
|
+
description: 'Automatic launch checks, version status, and installation',
|
|
62
86
|
items: [
|
|
63
|
-
'
|
|
87
|
+
'Automatically check for updates',
|
|
64
88
|
'Check for updates'
|
|
65
89
|
]
|
|
66
90
|
}
|
|
67
91
|
];
|
|
68
92
|
export const settingsItems = settingsGroups.flatMap(group => group.items);
|
|
69
|
-
export
|
|
70
|
-
|
|
93
|
+
export const settingsRootItems = settingsGroups.map(group => group.label);
|
|
94
|
+
export function settingsGroup(page) {
|
|
95
|
+
return settingsGroups.find(group => group.id === page);
|
|
96
|
+
}
|
|
97
|
+
export function settingsItemsForPage(page) {
|
|
98
|
+
return page === 'root' ? settingsRootItems : settingsGroup(page)?.items ?? [];
|
|
99
|
+
}
|
|
100
|
+
export function settingsPageForRootItem(item) {
|
|
101
|
+
return settingsGroups.find(group => group.label === item)?.id;
|
|
71
102
|
}
|
|
@@ -76,12 +76,13 @@ export function AlarmRingingScreen({ sessions, alarms = [], selected, snoozeMinu
|
|
|
76
76
|
const accent = themeAccent(theme);
|
|
77
77
|
const session = sessions[selected];
|
|
78
78
|
const label = session ? alarms.find(alarm => alarm.id === session.status.alarmId)?.label : undefined;
|
|
79
|
+
const starting = session?.status.state === 'starting';
|
|
79
80
|
const { ascii } = useDisplay();
|
|
80
81
|
const a = (value) => ascii ? toAsciiSafe(value) : value;
|
|
81
82
|
const roomy = width >= 42 && height >= 12;
|
|
82
83
|
const clockText = session ? formatClock(new Date(session.status.scheduledAt)) : '';
|
|
83
84
|
const displayClock = roomy && !ascii ? fullwidthClock(clockText) : clockText;
|
|
84
|
-
return _jsxs(Box, { flexDirection: "column", height: height, width: width, overflow: "hidden", children: [_jsx(ScreenHeader, { title: "Alarm ringing", subtitle: sessions.length > 1 ? `${selected + 1} of ${sessions.length} active alarms` : 'Wake radio · playing now', theme: theme, width: width }), session ? _jsxs(Box, { flexDirection: "column", alignItems: "center", width: width, children: [_jsx(Text, { backgroundColor: accent, color: "black", bold: true, children: a(' ALARM ACTIVE ') }), _jsx(Box, { marginTop: roomy ? 1 : 0, children: _jsx(Text, { backgroundColor: roomy ? accent : undefined, color: roomy ? 'black' : accent, bold: true, children: a(roomy ? ` ${displayClock} ` : displayClock) }) }), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: roomy ? 1 : 0, width: width, children: [_jsx(Text, { color: accent, bold: true, children: a(truncate(label ? `${session.status.stationName} · ${label}` : session.status.stationName, width)) }), height >= 12 ? _jsx(Text, { color: textMuted, children: a(truncate(
|
|
85
|
+
return _jsxs(Box, { flexDirection: "column", height: height, width: width, overflow: "hidden", children: [_jsx(ScreenHeader, { title: "Alarm ringing", subtitle: sessions.length > 1 ? `${selected + 1} of ${sessions.length} active alarms` : starting ? 'Wake radio · preparing station' : 'Wake radio · playing now', theme: theme, width: width }), session ? _jsxs(Box, { flexDirection: "column", alignItems: "center", width: width, children: [_jsx(Text, { backgroundColor: accent, color: "black", bold: true, children: a(starting ? ' ALARM STARTING ' : ' ALARM ACTIVE ') }), _jsx(Box, { marginTop: roomy ? 1 : 0, children: _jsx(Text, { backgroundColor: roomy ? accent : undefined, color: roomy ? 'black' : accent, bold: true, children: a(roomy ? ` ${displayClock} ` : displayClock) }) }), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: roomy ? 1 : 0, width: width, children: [_jsx(Text, { color: accent, bold: true, children: a(truncate(label ? `${session.status.stationName} · ${label}` : session.status.stationName, width)) }), height >= 12 ? _jsx(Text, { color: textMuted, children: a(truncate(`${starting ? 'Preparing' : 'Started'} ${formatElapsed(session.status.startedAt)} ago · scheduled ${formatWhen(new Date(session.status.scheduledAt))}`, width)) }) : null] }), _jsxs(Box, { marginTop: 1, flexDirection: width >= 58 ? 'row' : 'column', alignItems: "center", children: [_jsx(Text, { backgroundColor: accent, color: "black", bold: true, children: a(starting ? ' ENTER WAIT FOR STATION ' : ' ENTER KEEP PLAYING ') }), width >= 58 ? _jsx(Text, { children: " " }) : null, _jsx(Text, { backgroundColor: accent, color: "black", bold: true, children: a(` SPACE SNOOZE ${snoozeMinutes} MIN `) })] }), height >= 14 ? _jsx(Text, { color: textMuted, children: a(starting ? 'Space snoozes before playback · b return' : 'Enter opens Playing · Space stops the radio until snooze ends · b return') }) : null, sessions.length > 1 && height >= 15 ? _jsx(Text, { color: textMuted, children: a(`↑/↓ choose active alarm · ${selected + 1}/${sessions.length}`) }) : null] }) : _jsx(Text, { color: textMuted, children: "The alarm session ended. Press b to return." })] });
|
|
85
86
|
}
|
|
86
87
|
function editorRows(draft) {
|
|
87
88
|
const next = draftNextOccurrence(draft);
|
|
@@ -4,16 +4,19 @@ import { Menu, Pointer } from '../components/Menu.js';
|
|
|
4
4
|
import { ScreenHeader } from '../components/ScreenHeader.js';
|
|
5
5
|
import { textMuted, themeAccent } from '../theme.js';
|
|
6
6
|
import { visibleWindow } from '../list-window.js';
|
|
7
|
-
import { displayWidth
|
|
8
|
-
|
|
7
|
+
import { displayWidth } from '../format.js';
|
|
8
|
+
import { AdaptiveMarquee } from '../components/AdaptiveMarquee.js';
|
|
9
|
+
export function CountriesScreen({ countries, selected, loading, filter, editingFilter, theme, pageSize, width, reduceMotion = false }) {
|
|
9
10
|
const window = visibleWindow(countries, selected, pageSize);
|
|
10
11
|
const rowWidth = Math.max(24, width - 2);
|
|
11
12
|
const countWidth = Math.max(12, Math.min(22, Math.max(...countries.map(country => `${country.stationCount.toLocaleString()} stations`.length), 12)));
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
// Keep the metadata column fixed while the viewport scrolls. Forty-two cells
|
|
14
|
+
// accommodates long directory names such as Lao People's Democratic Republic
|
|
15
|
+
// plus its country code, while narrow terminals still receive a bounded row.
|
|
16
|
+
const countryWidth = Math.min(42, Math.max(8, rowWidth - countWidth - 4));
|
|
14
17
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ScreenHeader, { title: "Countries", subtitle: editingFilter ? 'Filtering countries — type to narrow the list' : 'Browse the worldwide country directory', width: width, theme: theme, right: filter ? `filter: ${filter}` : undefined }), loading ? _jsx(Text, { color: textMuted, children: "Loading countries from Radio Browser\u2026" }) : null, !loading ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: textMuted, children: ["Showing ", countries.length ? window.start + 1 : 0, "-", window.end, " of ", countries.length] }), _jsx(Menu, { items: window.items, selected: selected - window.start, keyFor: country => country.code, render: (country, _index, active) => {
|
|
15
18
|
const code = ` (${country.code})`;
|
|
16
19
|
const nameWidth = Math.max(3, countryWidth - displayWidth(code));
|
|
17
|
-
return (_jsxs(Box, { height: 1, width: rowWidth, children: [_jsx(Pointer, { active: active }), _jsxs(Box, { width: countryWidth, children: [_jsx(Text, { color: active ? themeAccent(theme) : undefined, bold: active, children:
|
|
20
|
+
return (_jsxs(Box, { height: 1, width: rowWidth, children: [_jsx(Pointer, { active: active }), _jsxs(Box, { width: countryWidth, children: [_jsx(Text, { color: active ? themeAccent(theme) : undefined, bold: active, children: _jsx(AdaptiveMarquee, { text: country.name, width: nameWidth, active: active, reduceMotion: reduceMotion }) }), _jsx(Text, { color: textMuted, children: code })] }), _jsx(Box, { width: 2 }), _jsx(Box, { width: countWidth, children: _jsxs(Text, { color: textMuted, children: [country.stationCount.toLocaleString(), " stations"] }) })] }));
|
|
18
21
|
} })] })) : null] }));
|
|
19
22
|
}
|
|
@@ -4,6 +4,8 @@ import { Logo } from '../components/Logo.js';
|
|
|
4
4
|
import { Menu, Pointer } from '../components/Menu.js';
|
|
5
5
|
import { textMuted, themeAccent } from '../theme.js';
|
|
6
6
|
import { homeItems } from '../screen-items.js';
|
|
7
|
+
import { displayWidth } from '../format.js';
|
|
7
8
|
export function HomeScreen({ selected, theme, library }) {
|
|
8
|
-
|
|
9
|
+
const titleWidth = Math.max(...homeItems.map(item => displayWidth(item.label))) + 2;
|
|
10
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Logo, {}), _jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsx(Menu, { items: homeItems, selected: selected, keyFor: item => item.screen, render: (item, index, active) => (_jsxs(Box, { children: [_jsx(Pointer, { active: active }), _jsxs(Text, { color: textMuted, children: [index + 1, " "] }), _jsx(Box, { width: titleWidth, children: _jsx(Text, { color: active ? themeAccent(theme) : undefined, bold: active, children: item.label }) }), _jsxs(Text, { color: textMuted, children: [" ", item.detail] })] })) }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: textMuted, children: [library.recent.length, " recent \u00B7 ", library.favorites.length, " favorites \u00B7 ", library.imported.length, " imported"] }) })] }));
|
|
9
11
|
}
|
|
@@ -1,73 +1,68 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
+
import { defaultAgentControlSettings } from '../../types.js';
|
|
3
4
|
import { Menu, Pointer } from '../components/Menu.js';
|
|
4
5
|
import { ScreenHeader } from '../components/ScreenHeader.js';
|
|
5
6
|
import { truncate } from '../format.js';
|
|
6
|
-
import {
|
|
7
|
+
import { settingsGroup, settingsGroups, settingsItemsForPage } from '../screen-items.js';
|
|
7
8
|
import { textMuted, themeAccent } from '../theme.js';
|
|
8
9
|
import { playbackBackendCapabilities } from '../../player/backend-install.js';
|
|
9
10
|
import { airPlayReceiverSettingValue } from '../airplay-settings.js';
|
|
10
11
|
import { audioOutputLabel, audioOutputSettingValue } from '../audio-output.js';
|
|
11
12
|
import { updateStatusText } from '../../update-check.js';
|
|
12
|
-
export function SettingsScreen({ selected, settings, appVersion, updateCheck, storePath, playback, backends, airPlayDevices, providerHealth, theme, diagnostics, width, height }) {
|
|
13
|
+
export function SettingsScreen({ page = 'root', selected, settings, appVersion, updateCheck, storePath, playback, backends, airPlayDevices, providerHealth, theme, diagnostics, width, height }) {
|
|
13
14
|
const accent = themeAccent(theme);
|
|
14
15
|
const lineWidth = Math.max(32, width - 4);
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
16
|
+
const group = settingsGroup(page);
|
|
17
|
+
const pageItems = settingsItemsForPage(page);
|
|
18
|
+
const menuWindow = settingsMenuWindow(pageItems, selected, height);
|
|
19
|
+
const selectedItem = pageItems[selected];
|
|
20
|
+
const detail = page === 'root' && selectedItem !== 'Check for updates'
|
|
21
|
+
? settingsGroupsDescription(selectedItem)
|
|
22
|
+
: settingDetail({
|
|
23
|
+
item: selectedItem,
|
|
24
|
+
appVersion,
|
|
25
|
+
updateCheck,
|
|
26
|
+
storePath,
|
|
27
|
+
playback,
|
|
28
|
+
providerHealth,
|
|
29
|
+
diagnostics,
|
|
30
|
+
lineWidth
|
|
31
|
+
});
|
|
28
32
|
const valueGap = 3;
|
|
29
33
|
const labelWidth = Math.min(34, Math.max(20, lineWidth - valueGap - 24));
|
|
30
34
|
const valueWidth = Math.max(12, Math.min(34, lineWidth - labelWidth - valueGap - 2));
|
|
31
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ScreenHeader, { title: "Settings", subtitle:
|
|
32
|
-
const label = settingLabel(item
|
|
33
|
-
const value =
|
|
34
|
-
|
|
35
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ScreenHeader, { title: "Settings", subtitle: group ? `Settings › ${group.label}` : 'Choose a category', width: width, theme: theme }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsx(Menu, { items: menuWindow.items, selected: menuWindow.selectedOffset, keyFor: item => item, render: (item, _index, active) => {
|
|
36
|
+
const label = settingLabel(item, updateCheck, appVersion);
|
|
37
|
+
const value = page === 'root'
|
|
38
|
+
? settingsRootValue(item)
|
|
39
|
+
: settingValue(item, settings, diagnostics, backends, airPlayDevices, updateCheck, appVersion);
|
|
40
|
+
return (_jsxs(Box, { width: lineWidth, children: [_jsx(Pointer, { active: active }), _jsx(Box, { width: labelWidth, children: _jsx(Text, { color: active ? accent : undefined, bold: active, children: truncate(label, labelWidth) }) }), _jsx(Box, { width: valueGap }), _jsx(Box, { width: valueWidth, children: _jsx(Text, { color: value ? accent : textMuted, children: truncate(value ?? '', valueWidth) }) })] }));
|
|
35
41
|
} }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: textMuted, bold: true, children: "Selected" }), _jsx(Text, { color: textMuted, children: truncate(detail, lineWidth) })] })] }));
|
|
36
42
|
}
|
|
37
|
-
function settingsMenuWindow(selected, height) {
|
|
43
|
+
function settingsMenuWindow(items, selected, height) {
|
|
38
44
|
const reservedRows = 6;
|
|
39
45
|
const maxRows = height ? Math.max(5, height - reservedRows) : Number.POSITIVE_INFINITY;
|
|
40
|
-
const clampedSelected = Math.min(Math.max(selected, 0),
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
let previousSection = '';
|
|
45
|
-
settingsItems.forEach((item, index) => {
|
|
46
|
-
const section = settingsSectionFor(item);
|
|
47
|
-
let showSection = section !== previousSection;
|
|
48
|
-
let rowCost = 1 + (showSection ? 1 : 0);
|
|
49
|
-
if (page.length > 0 && pageRows + rowCost > maxRows) {
|
|
50
|
-
pages.push(page);
|
|
51
|
-
page = [];
|
|
52
|
-
pageRows = 0;
|
|
53
|
-
previousSection = '';
|
|
54
|
-
showSection = true;
|
|
55
|
-
rowCost = 2;
|
|
56
|
-
}
|
|
57
|
-
page.push({ item, section, showSection, index });
|
|
58
|
-
pageRows += rowCost;
|
|
59
|
-
previousSection = section;
|
|
60
|
-
});
|
|
61
|
-
if (page.length > 0) {
|
|
62
|
-
pages.push(page);
|
|
63
|
-
}
|
|
64
|
-
const selectedPage = pages.find(candidate => candidate.some(entry => entry.index === clampedSelected)) ?? pages[0] ?? [];
|
|
46
|
+
const clampedSelected = Math.min(Math.max(selected, 0), items.length - 1);
|
|
47
|
+
const pageSize = Number.isFinite(maxRows) ? Math.max(1, Math.floor(maxRows)) : items.length;
|
|
48
|
+
const pageStart = Math.floor(clampedSelected / pageSize) * pageSize;
|
|
49
|
+
const selectedPage = items.slice(pageStart, pageStart + pageSize);
|
|
65
50
|
return {
|
|
66
|
-
items: selectedPage,
|
|
67
|
-
selectedOffset:
|
|
51
|
+
items: [...selectedPage],
|
|
52
|
+
selectedOffset: clampedSelected - pageStart
|
|
68
53
|
};
|
|
69
54
|
}
|
|
70
|
-
|
|
55
|
+
function settingsRootValue(item) {
|
|
56
|
+
const group = settingsGroupByLabel(item);
|
|
57
|
+
return group ? `${group.items.length} settings ›` : undefined;
|
|
58
|
+
}
|
|
59
|
+
function settingsGroupByLabel(label) {
|
|
60
|
+
return settingsGroups.find(group => group.label === label);
|
|
61
|
+
}
|
|
62
|
+
function settingsGroupsDescription(label) {
|
|
63
|
+
return label ? settingsGroupByLabel(label)?.description ?? 'Press Enter to open this category.' : '';
|
|
64
|
+
}
|
|
65
|
+
export function settingValue(item, settings, diagnostics, backends, airPlayDevices, updateCheck, currentVersion) {
|
|
71
66
|
switch (item) {
|
|
72
67
|
case 'Cycle display color':
|
|
73
68
|
return settings.theme;
|
|
@@ -100,8 +95,18 @@ export function settingValue(item, settings, diagnostics, backends, airPlayDevic
|
|
|
100
95
|
return settings.reduceMotion ? 'on' : 'off';
|
|
101
96
|
case 'Mouse and trackpad scrolling':
|
|
102
97
|
return settings.mouseSupport === false ? 'off' : 'auto';
|
|
98
|
+
case 'Automatically check for updates':
|
|
99
|
+
return settings.automaticUpdateChecks === false ? 'off' : 'on';
|
|
100
|
+
case 'Allow local agent control':
|
|
101
|
+
return (settings.agentControl ?? defaultAgentControlSettings).enabled ? 'on' : 'off';
|
|
102
|
+
case 'Install or repair MCP integrations':
|
|
103
|
+
return 'run repair';
|
|
104
|
+
case 'Open TUI for agent playback':
|
|
105
|
+
return (settings.agentControl ?? defaultAgentControlSettings).openUiOnPlay ? 'on' : 'off';
|
|
106
|
+
case 'Show Now Playing for agent playback':
|
|
107
|
+
return (settings.agentControl ?? defaultAgentControlSettings).focusNowPlaying ? 'on' : 'off';
|
|
103
108
|
case 'Check for updates':
|
|
104
|
-
return updateStatusText(updateCheck);
|
|
109
|
+
return updateStatusText(updateCheck, currentVersion);
|
|
105
110
|
case 'Reset learned media keys':
|
|
106
111
|
return `prev ${settings.mediaKeys.previous.length} · play ${settings.mediaKeys.playPause.length} · next ${settings.mediaKeys.next.length}`;
|
|
107
112
|
case 'Export preferences and library':
|
|
@@ -112,9 +117,9 @@ export function settingValue(item, settings, diagnostics, backends, airPlayDevic
|
|
|
112
117
|
return undefined;
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
|
-
export function settingLabel(item, updateCheck) {
|
|
116
|
-
if (item === 'Check for updates'
|
|
117
|
-
return 'Install update';
|
|
120
|
+
export function settingLabel(item, updateCheck, currentVersion) {
|
|
121
|
+
if (item === 'Check for updates') {
|
|
122
|
+
return updateStatusText(updateCheck, currentVersion).endsWith('available') ? 'Install update' : 'Check now';
|
|
118
123
|
}
|
|
119
124
|
return settingDisplayLabels[item] ?? item;
|
|
120
125
|
}
|
|
@@ -135,7 +140,10 @@ function settingDetail(input) {
|
|
|
135
140
|
return health.length ? health.map(([provider, status]) => `${provider}: ${status}`).join(' · ') : 'Press Enter to check station providers.';
|
|
136
141
|
}
|
|
137
142
|
if (item === 'Check for updates') {
|
|
138
|
-
return `RadioCLI v${appVersion} · ${updateStatusText(updateCheck)}`;
|
|
143
|
+
return `RadioCLI v${appVersion} · ${updateStatusText(updateCheck, appVersion)}`;
|
|
144
|
+
}
|
|
145
|
+
if (item === 'Automatically check for updates') {
|
|
146
|
+
return 'When enabled, RadioCLI checks the registry once whenever the app launches.';
|
|
139
147
|
}
|
|
140
148
|
if (item === 'Export preferences and library' || item === 'Import preferences and library') {
|
|
141
149
|
return `Library file: ${truncate(storePath, Math.max(8, lineWidth - 14))}`;
|
|
@@ -149,5 +157,14 @@ function settingDetail(input) {
|
|
|
149
157
|
if (item === 'Reduce motion') {
|
|
150
158
|
return 'Freezes animated receiver displays for calmer, lower-power rendering.';
|
|
151
159
|
}
|
|
160
|
+
if (item === 'Allow local agent control') {
|
|
161
|
+
return 'Press Enter to set up or remove agent and Codex Voice control across detected clients.';
|
|
162
|
+
}
|
|
163
|
+
if (item === 'Install or repair MCP integrations') {
|
|
164
|
+
return 'Checks and repairs every detected client. Restart open Codex or agent clients afterward.';
|
|
165
|
+
}
|
|
166
|
+
if (item === 'Open TUI for agent playback') {
|
|
167
|
+
return 'Opt in to a separate terminal window. On macOS, the agent app must approve a one-time Automation prompt.';
|
|
168
|
+
}
|
|
152
169
|
return 'Press Enter to change this setting.';
|
|
153
170
|
}
|
package/dist/ui/use-alarm-tui.js
CHANGED
|
@@ -461,6 +461,10 @@ export function useAlarmTui(params) {
|
|
|
461
461
|
if (!active)
|
|
462
462
|
return false;
|
|
463
463
|
if (key.return) {
|
|
464
|
+
if (active.status.state === 'starting') {
|
|
465
|
+
setMessage(`Still preparing ${active.status.stationName}; handoff will be available once playback starts.`);
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
464
468
|
if (pendingActiveActionsRef.current.has(active.key)) {
|
|
465
469
|
setMessage(`An alarm control request is already pending for ${active.status.stationName}.`);
|
|
466
470
|
return true;
|
package/dist/ui/use-app-input.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { useInput } from 'ink';
|
|
3
|
-
import { homeItems,
|
|
3
|
+
import { homeItems, settingsItemsForPage, settingsPageForRootItem } from './screen-items.js';
|
|
4
4
|
import { applyTextInput, favoriteTarget, isEditableInput, isPlainPrintableInput, mediaTransportActionForInput, searchEditingArrowAction, shouldHandleKeyboardEvent, shouldToggleNearbyLocationShortcut } from './app-state.js';
|
|
5
5
|
import { parseTerminalMouseEvents, primaryMousePress, wheelScrollDelta } from './terminal-mouse.js';
|
|
6
6
|
import { completeCommand } from './help-content.js';
|
|
7
7
|
import { commitImmediateSelection } from './selection-state.js';
|
|
8
|
-
export function useAppInput({ adjustVolume, airPlayCode, canEnterAirPlayCode, cancelPendingAutoSkip, beginLearningTransportKey, capturingTransportAction, commandMode, commandText, confirmCtrlCExit, copyStationUrl, openStationHomepage, currentItemCount, cycleDisplayColor, cycleAudioOutput, cycleReceiverStyle, cycleSleepTimer, editingCountryFilter, editingSearch, executeCommand, filteredCountries, go, lastRawTransportAtRef, lastSubmittedSearchRef, loadCountry, openAdjacentTab, openAirPlayCode, openAirPlaySettings, openScreen, handleAlarmInput, openAlarmForStation, openActiveAlarms, playAdjacent, playStation, player, playingStation, recallSearchHistory, moveExploreCursor, moveExploreCursorToCell, refreshAirPlayTargets, refreshProviderHealth, resetLearnedTransportKeys, runSearch, saveLearnedTransportKey, screen, searchQuery, selectedRef, selectedStationForInput, selectAirPlayDeviceAt, setCapturingTransportAction, setAirPlayCode, setCommandMode, setCommandText, setCountryFilter, setEditingCountryFilter, setEditingSearch, setMessage, setSearchQuery, setSelected, setShowDiagnostics, submitAirPlayCode, settingsRef, shutdown, stdin, toggleFavorite, toggleMute, togglePause, toggleSetting, toggleNearbyLocation, toggleDirectoryVoting, toggleRadioGarden, toggleSkipBrokenStreams, updateFromSettings }) {
|
|
8
|
+
export function useAppInput({ adjustVolume, airPlayCode, canEnterAirPlayCode, cancelPendingAutoSkip, beginLearningTransportKey, capturingTransportAction, commandMode, commandText, confirmCtrlCExit, copyStationUrl, openStationHomepage, currentItemCount, cycleDisplayColor, cycleAudioOutput, cycleReceiverStyle, cycleSleepTimer, editingCountryFilter, editingSearch, executeCommand, filteredCountries, go, lastRawTransportAtRef, lastSubmittedSearchRef, loadCountry, openAdjacentTab, openAirPlayCode, openAirPlaySettings, openSettingsPage, closeSettingsPage, openScreen, handleAlarmInput, openAlarmForStation, openActiveAlarms, playAdjacent, playStation, player, playingStation, recallSearchHistory, moveExploreCursor, moveExploreCursorToCell, refreshAirPlayTargets, refreshProviderHealth, resetLearnedTransportKeys, repairMcpIntegrations, setAgentIntegrationEnabled, runSearch, saveLearnedTransportKey, screen, settingsPage, searchQuery, selectedRef, selectedStationForInput, selectAirPlayDeviceAt, setCapturingTransportAction, setAirPlayCode, setCommandMode, setCommandText, setCountryFilter, setEditingCountryFilter, setEditingSearch, setMessage, setSearchQuery, setSelected, setShowDiagnostics, submitAirPlayCode, settingsRef, shutdown, stdin, toggleFavorite, toggleMute, togglePause, toggleSetting, toggleAgentSetting, toggleNearbyLocation, toggleDirectoryVoting, toggleRadioGarden, toggleSkipBrokenStreams, updateFromSettings }) {
|
|
9
9
|
const commitSelection = (next) => {
|
|
10
10
|
commitImmediateSelection(selectedRef, setSelected, next, currentItemCount(screen));
|
|
11
11
|
};
|
|
@@ -338,6 +338,10 @@ export function useAppInput({ adjustVolume, airPlayCode, canEnterAirPlayCode, ca
|
|
|
338
338
|
go('settings');
|
|
339
339
|
return;
|
|
340
340
|
}
|
|
341
|
+
if ((input === 'b' || key.escape) && screen === 'settings') {
|
|
342
|
+
closeSettingsPage();
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
341
345
|
if (input === 'b' || key.escape) {
|
|
342
346
|
if (screen === 'stations') {
|
|
343
347
|
go('countries');
|
|
@@ -419,7 +423,14 @@ export function useAppInput({ adjustVolume, airPlayCode, canEnterAirPlayCode, ca
|
|
|
419
423
|
return;
|
|
420
424
|
}
|
|
421
425
|
if (screen === 'settings') {
|
|
422
|
-
const item =
|
|
426
|
+
const item = settingsItemsForPage(settingsPage)[selectedRef.current];
|
|
427
|
+
if (settingsPage === 'root') {
|
|
428
|
+
const targetPage = settingsPageForRootItem(item);
|
|
429
|
+
if (targetPage) {
|
|
430
|
+
openSettingsPage(targetPage);
|
|
431
|
+
}
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
423
434
|
if (item === 'Cycle display color') {
|
|
424
435
|
cycleDisplayColor();
|
|
425
436
|
}
|
|
@@ -468,6 +479,21 @@ export function useAppInput({ adjustVolume, airPlayCode, canEnterAirPlayCode, ca
|
|
|
468
479
|
else if (item === 'Mouse and trackpad scrolling') {
|
|
469
480
|
toggleSetting('mouseSupport');
|
|
470
481
|
}
|
|
482
|
+
else if (item === 'Automatically check for updates') {
|
|
483
|
+
toggleSetting('automaticUpdateChecks');
|
|
484
|
+
}
|
|
485
|
+
else if (item === 'Allow local agent control') {
|
|
486
|
+
void setAgentIntegrationEnabled();
|
|
487
|
+
}
|
|
488
|
+
else if (item === 'Install or repair MCP integrations') {
|
|
489
|
+
void repairMcpIntegrations();
|
|
490
|
+
}
|
|
491
|
+
else if (item === 'Open TUI for agent playback') {
|
|
492
|
+
toggleAgentSetting('openUiOnPlay');
|
|
493
|
+
}
|
|
494
|
+
else if (item === 'Show Now Playing for agent playback') {
|
|
495
|
+
toggleAgentSetting('focusNowPlaying');
|
|
496
|
+
}
|
|
471
497
|
else if (item === 'Export preferences and library') {
|
|
472
498
|
setCommandText('export ');
|
|
473
499
|
setCommandMode(true);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { themeAccent } from '../theme.js';
|
|
2
|
+
import { horseStrideFrames, horseStrideHeight, horseStrideWidth } from './horse-stride.js';
|
|
3
|
+
const frames = horseStrideFrames.map(frame => Buffer.from(frame, 'base64'));
|
|
4
|
+
const brailleBits = [[1, 8], [2, 16], [4, 32], [64, 128]];
|
|
5
|
+
/** One pose per receiver tick. The same scale and torso anchor are used for every pose. */
|
|
6
|
+
export function buildGallop(pulse, width, height, theme) {
|
|
7
|
+
const w = Math.max(1, Math.floor(width));
|
|
8
|
+
const h = Math.max(1, Math.floor(height));
|
|
9
|
+
const color = themeAccent(theme);
|
|
10
|
+
const frameIndex = ((Math.floor(pulse) % frames.length) + frames.length) % frames.length;
|
|
11
|
+
const frame = frames[frameIndex];
|
|
12
|
+
const usableW = w > 8 ? w - 4 : w;
|
|
13
|
+
const usableH = h > 4 ? h - 2 : h;
|
|
14
|
+
const scale = Math.min(usableW * 2 / horseStrideWidth, usableH * 4 / horseStrideHeight);
|
|
15
|
+
const dotsW = Math.max(1, Math.floor(horseStrideWidth * scale));
|
|
16
|
+
const dotsH = Math.max(1, Math.floor(horseStrideHeight * scale));
|
|
17
|
+
const left = Math.floor((w - Math.ceil(dotsW / 2)) / 2) * 2;
|
|
18
|
+
const top = Math.floor((h - Math.ceil(dotsH / 4)) / 2) * 4;
|
|
19
|
+
const masks = new Uint8Array(w * h);
|
|
20
|
+
for (let y = 0; y < dotsH; y++) {
|
|
21
|
+
const sy0 = Math.floor(y * horseStrideHeight / dotsH);
|
|
22
|
+
const sy1 = Math.ceil((y + 1) * horseStrideHeight / dotsH);
|
|
23
|
+
for (let x = 0; x < dotsW; x++) {
|
|
24
|
+
const sx0 = Math.floor(x * horseStrideWidth / dotsW);
|
|
25
|
+
const sx1 = Math.ceil((x + 1) * horseStrideWidth / dotsW);
|
|
26
|
+
let ink = 0;
|
|
27
|
+
for (let sy = sy0; sy < sy1; sy++)
|
|
28
|
+
for (let sx = sx0; sx < sx1; sx++) {
|
|
29
|
+
const bit = sy * horseStrideWidth + sx;
|
|
30
|
+
ink += (frame[bit >> 3] >> (bit & 7)) & 1;
|
|
31
|
+
}
|
|
32
|
+
// Area coverage keeps thin legs continuous as the terminal becomes smaller.
|
|
33
|
+
if (ink / ((sx1 - sx0) * (sy1 - sy0)) < 0.22)
|
|
34
|
+
continue;
|
|
35
|
+
const dx = left + x;
|
|
36
|
+
const dy = top + y;
|
|
37
|
+
const index = Math.floor(dy / 4) * w + Math.floor(dx / 2);
|
|
38
|
+
masks[index] |= brailleBits[dy % 4][dx % 2];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return Array.from({ length: h }, (_, y) => {
|
|
42
|
+
let text = '';
|
|
43
|
+
for (let x = 0; x < w; x++) {
|
|
44
|
+
const mask = masks[y * w + x];
|
|
45
|
+
text += mask === 0 ? ' ' : String.fromCharCode(0x2800 + mask);
|
|
46
|
+
}
|
|
47
|
+
// No background color: only the horse's ink is drawn over the receiver panel.
|
|
48
|
+
return { text, color, segments: [{ text, color }] };
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Lightly pare back thick stroke edges, keeping endpoints and junctions intact. */
|
|
52
|
+
export function buildGallopFine(pulse, width, height, theme) {
|
|
53
|
+
return thinGallopStrokes(buildGallop(pulse, width, height, theme), 0.14);
|
|
54
|
+
}
|
|
55
|
+
function thinGallopStrokes(original, reduction) {
|
|
56
|
+
const w = original[0].text.length;
|
|
57
|
+
const h = original.length;
|
|
58
|
+
const dw = w * 2;
|
|
59
|
+
const dh = h * 4;
|
|
60
|
+
const dots = new Uint8Array(dw * dh);
|
|
61
|
+
let inkCount = 0;
|
|
62
|
+
original.forEach((row, y) => {
|
|
63
|
+
[...row.text].forEach((glyph, x) => {
|
|
64
|
+
const mask = glyph === ' ' ? 0 : glyph.charCodeAt(0) - 0x2800;
|
|
65
|
+
for (let yy = 0; yy < 4; yy++)
|
|
66
|
+
for (let xx = 0; xx < 2; xx++) {
|
|
67
|
+
if (mask & brailleBits[yy][xx]) {
|
|
68
|
+
dots[(y * 4 + yy) * dw + x * 2 + xx] = 1;
|
|
69
|
+
inkCount++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
const neighbors = [-dw, -dw + 1, 1, dw + 1, dw, dw - 1, -1, -dw - 1];
|
|
75
|
+
const canThin = (index) => {
|
|
76
|
+
if (!dots[index])
|
|
77
|
+
return false;
|
|
78
|
+
const ring = neighbors.map(offset => dots[index + offset]);
|
|
79
|
+
const count = ring.reduce((total, dot) => total + dot, 0);
|
|
80
|
+
// Already-fine lines and endpoints stay untouched. A single connected arc of
|
|
81
|
+
// neighbors ensures removing this edge dot cannot split a leg or contour.
|
|
82
|
+
if (count < 3 || count > 6)
|
|
83
|
+
return false;
|
|
84
|
+
let transitions = 0;
|
|
85
|
+
for (let i = 0; i < 8; i++)
|
|
86
|
+
if (!ring[i] && ring[(i + 1) % 8])
|
|
87
|
+
transitions++;
|
|
88
|
+
return transitions === 1;
|
|
89
|
+
};
|
|
90
|
+
const candidates = [];
|
|
91
|
+
for (let y = 1; y < dh - 1; y++)
|
|
92
|
+
for (let x = 1; x < dw - 1; x++) {
|
|
93
|
+
const index = y * dw + x;
|
|
94
|
+
if (canThin(index))
|
|
95
|
+
candidates.push(index);
|
|
96
|
+
}
|
|
97
|
+
const budget = Math.min(candidates.length, Math.floor(inkCount * reduction));
|
|
98
|
+
for (let i = 0; i < budget; i++) {
|
|
99
|
+
// Spread the small reduction over the entire horse instead of thinning its
|
|
100
|
+
// head first. Recheck after each removal to preserve connected strokes.
|
|
101
|
+
const index = candidates[Math.floor(i * candidates.length / budget)];
|
|
102
|
+
if (canThin(index))
|
|
103
|
+
dots[index] = 0;
|
|
104
|
+
}
|
|
105
|
+
return original.map((row, y) => {
|
|
106
|
+
let text = '';
|
|
107
|
+
for (let x = 0; x < w; x++) {
|
|
108
|
+
let mask = 0;
|
|
109
|
+
for (let yy = 0; yy < 4; yy++)
|
|
110
|
+
for (let xx = 0; xx < 2; xx++) {
|
|
111
|
+
if (dots[(y * 4 + yy) * dw + x * 2 + xx])
|
|
112
|
+
mask |= brailleBits[yy][xx];
|
|
113
|
+
}
|
|
114
|
+
text += mask ? String.fromCharCode(0x2800 + mask) : ' ';
|
|
115
|
+
}
|
|
116
|
+
return { text, color: row.color, segments: [{ text, color: row.color }] };
|
|
117
|
+
});
|
|
118
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Fixed-canvas gallop poses derived from the user-provided horse line-art reference.
|
|
2
|
+
* Each base64 frame is a 128 × 80 one-bit ink mask, packed least-significant bit first.
|
|
3
|
+
* Background pixels are transparent; no video decoder or source file is needed at runtime.
|
|
4
|
+
*/
|
|
5
|
+
export const horseStrideWidth = 128;
|
|
6
|
+
export const horseStrideHeight = 80;
|
|
7
|
+
export const horseStrideFrames = [
|
|
8
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAOB9AAAAAAAAAAAAAAAAAADwMQAAAAAAAAAAAAAAAAAADzADAAAAAAAAAAAAAAAAwA8mBwAAAAAAAAAAAAAAAPCAAxwAAAAAAAAAAAAAAAA4wAE4AAAAAAAAAAAAAAAAmGcAcAAAAAAAAAAAAAAAAIg5APgAAAAAAAAAAAAAAAAMOGCAAQAAAAAAAAAAAAAABgxgIAMAAAAAAAAAAAAAgAMGYAAIAAAAAAAAAAAAAMABA2AAGAAAAAAAAAAAAADgxwPAABAAAAAAAAAAAAAA8OMA4A8QAAAAAAAAAAAAAPB8AGB+EAAAAAAAAAAAAADgHgAw4BAAAAAAAAAAAAAAwAcAEIARAAAAAAAAAID/AcABABgAAQAAAAAAAADw//9hgAAYAAAAAAAAAAAAeAD8AQABDAAAAAAAAAAAAB4AAAAAAAwAAAAAAAAAAAAHEAAAAAAMAAAAAAAAAACAAxAAAAAGDAAAAAAAAAAAgAEAAAAADAYAAAAAAAAAADgAAAAAABgGAAAAAAAAAMAfAAAAAAA4BgAAAAAAAAD/AwAAAAAAMAIAAAAAAADg/wMAAAAAAHAHAAAAAAAAMIBgAAAAAADwBwAAAAAAAAjwYADAAAAA8AcAAAAAAAAAOOAAwAAAAPAGAAAAAAAAAAjAEMAAAAD4DgAAAAAAAAAIwHGAAAAA/DwAAAAAAAAAAIBDgAAAAPwgAAAAAAAAAAAAB4AAAAB9AA8AAAAABgAAAB+AAACCfQAeAAAA5gwAAAB+gAAAxngAGAAAAIwBgAAA+MADAObw/zEAAAAYAIAAALCB/wB+YK8HAAAAcADAAADggf//f+AADgAAAMABYAAA4IP5f/DEAQwAAAAAPnAAAECDAQDAhwMYAAAAAD84AABAhgEAAB8HGAAAAIAfHwAAwIYAAAB8DtAAAAAA/QcAAMCGAAAA8BzQAAAAAPABAACAhAEAAMABsAEAAAAAAAAAgIYBAEyACbABAAAAAAAAAIAGAYDPwAlwAQAAAAAAAADAHgOA8/kAcAMAAAAAAAAAwD4cANt/APADAAAAAAAAAGD4+AC4PgDgAwAAAAAAAAAAwOcDcD4AwAMAAAAAAAAAwACfD+APAOAGAAAAAAAAAIACOAzgBwDgBwAAAAAAAAAAAuAYwAAAQAcAAAAAAAAAADbAOQAAAMAAAAAAAAAAAABmAHMAAADABQAAAAAAAAAAbADBAAAAAAcAAAAAAAAAANgAhwAAAAAGAAAAAAAAAACYAA4AAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAACACAAAAAAAAAAAAAAAAAABgAgAAAAAAAAAAAAAAAAAAYAYAAAAAAAAAAAAAAAAAAEAdAAAAAAAAAAAAAAAAAACANwAAAAAAAAAAAAAAAAAAgGMAAAAAAAAAAAAAAAAA4P//AwAAAAAAAAAAAAAAAOD//wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
9
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAACA/wAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAABgBgAAAAAAAAAAAAAAAAAA7BwAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAYA4AAAAAAAAAAAAAAAAABAAOABAAAAAAAAAAAAAABgMABwAwAAAAAAAAAAAABAABjAAAYAAAAAAAAAAAAAAAAMwMAMAAAAAAAAAAAAAAAAAMAAGAAAAAAAAAAAAAAAAADAADAAAAAAAAAAAAAAAMAAwAMgAAAAAAAAAAAAABx4AIB/YAAAAAAAAAAAAAAEHACA4GEAAAAAAAAAAAAAAAcAAIBjAAAAAAAAAAAAAIABAAAAQgAAAAAAAACA/wHAAAAAAAAAAAAAAAAAAMD/XwAAEAAAAAAAAAAAAAYA/AMAAhAAAAAAAAAAAIADAAAAAAYYAAAAAAAAAACAAQAAAAAMCAAAAAAAAAAA4AAAAAAADAwAAAAAAAAAAHwAAAAAABgMAAAAAAAAAAAeACAAAAAQBAAAAAAAAAAAGABgAAAAAAYAAAAAAAAAADgAYAAAAAACAAAAAAAAAAAAAEAAAAAAAwAAAAAAAAwAYADAAAAAgAcAAAAAAAAAAGAAwAAAAKAEAAAAAAAAAADAAIAAAAAgAAAAAAAAAAAA4AGAAAAAwAAAAAAAAAAAAKADgAEAA0AAAAAAAAAAAABgDwAAAAKAQAAAAAAAAAAAYB8AAAAG4EAAAAAAOAAAAMB4AAEABOEADwAAAPABAAHA8QMDAIzAAR4AAADAi4ABgIEDHwDMADwwAAAAwMDAAAADA///D3z8YAAAAIB5wAAAAwbi//vxuQMAAAAAH2AAAAMMAgDAf2AOAAAAAAAwAAADGwYAAPhjOAAAAMACHAAAgxkGAAAAR7ADAADA/w8AgIExBgAAAExgAwAAAP8HAIDBMAQAAAAMwAYAAAA8AADAcSAMAAAABIAMAAAAAAAA8DmwDAAAABaAGQAAAAAAAPAYsBkAAAAbgBkAAAAAAADwDKA3AACAG4ARAAAAAAAA4AzgcAAAxA2AOwAAAAAAAGAMgOMAgPUGAH8AAAAAAABgBgDPAeAfBgDsAAAAAAAAwAQAnAfwDQMAiAAAAAAAAMAEAHAOsI0BAPwBAAAAAADADADgHPC/AQCcAQAAAAAAgAwAwDkAMAAAOAMAAAAAAIANAIAzAAAAAPADAAAAAACAGQAAdwAAAACAAgAAAAAAgBkAAOwAAAAAAAAAAAAAAIA5AADuAQAAAAAAAAAAAACAOwAAvgMAAAAAAAAAAAAAwD8AAPwHAAAAAAAAAAAAAAA/AAD4BwAAAAAAAAAAAAAAfQAAAAAAAAAAAAAAAAAAAO4AAAAAAAAAAAAAAAAAAACEAQAAAAAAAAAAAAAAAAAA/AMAAAAAAAAAAAAAAAAAAPgDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
10
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAwMwAAAAAAAAAAAAAAAAAAPjNAQAAAAAAAAAAAAAAAAAcAAMAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAYAAADAAAAAAAAAAAAABAhjgACB4AAAAAAAAAAAAAcBAcAAwwAAAAAAAAAAAAAAAABwAMbAAAAAAAAAAAAAAA4AMADIAAAAAAAAAAAAAAAHgAAAyAAQAAAAAAAAAAAAAOAAAcAAMAAAAAAAAAAACAAwAA/gECAAAAAAAA8B8A4AEBAOQHAgAAAAAAAP7/D34AAwAAHgIAAAAAAIAPAA8PAAYAADgCAAAAAADAAQAAAAAEAAAQAgAAAAAAcAAAAAAAECAAAAAAAAAAAD4AAAAAABAwAAAAAAAAAIAfAAAAAAAAGAAAAAAAAACADwAAAAAAAAwAAAAAAAAAgA8AAAAAAAAMAAAAAAAAAAAEAAAAAAAABgAAAAAAAAAADgAAAAAAgAMAAAAAAAAAABoAAAAAAIACAAAAAAAAAAAbABAAAACAAgAAAAAAAAAAGwAQAAAAwAIAAAAAAAAAADEAEAAAAMACAAAAAAAAAIAxABAAAAAAAgAAAAAAAACAYQAYAAAM4AIAAAAAAAAQgOEAGAAAAMAHAAAAAAAACIDBAQgAAAAGBwAAAAAAAAyAAAd4AAAcAgwAAAAA4AAEwAAE/AMAPAL8AAAAAMADBuAABow/gH/44AAAAAAAA0NwwAUE8P/nTwABAAAAAABhPOAEBgAAgP8fBgAAAAAMYB5wBgMAAADAPwYAAAAACLgfOAYDAAAAgHMAAAAAADjPBx6GAQAAAADnAAAAAADnR0EHwwAAAAAAjAQAAAAA/mDxgeMAAAAAAJwEAAAAAACgeMBhAAAAAACYDQAAAAAAMB7gMQAAAAAA8A0AAAAAABgHYBEAAAAAAOANAAAAAACYA+ARAAAAAACACQAAAAAA4AHAEQAAAAAAADkAAAAAAHcAgAEAAAAAAAD4AAAAAPA7AIAzAAAAAACAiQEAAAD0HAAANgAAAAAAgAkDAAAAHw4AAGYAAAAAAMAPHgAAgAkHAADsAAAAAADA/XwAAMCgAwAA3AAAAAAA4P/5AQBg/AEAAJgBAAAAAGCHjwMAcHwAAACYAwAAAABABjcAAPAHAAAAMAcAAAAAwAIwAADAAAAAAHAGAAAAAIADAAAAAAAAAABwDgAAAACAAQAAAAAAAAAAwB8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAYwAAAAAAAAAAAAAAAAAAgP8AAAAAAAAAAAAAAAAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
11
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwH8AAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAA8H8DAAAAAAAAAAAAAAAAAH4ABwAAAAAAAAAAAAAAAIAPAAwAAAAAAAAAAAAAAATgAQAYAAAAAAAAAAAAAAAAPAAAMAAAAAAAAAAAAAAAAA8AIHgAAAAAAAAAAAAAAMADACDYAAAAAAAAAAAAAAD+AAAwkAEAAAAAAAAAAACADwAAOBADAAAAAAAAAAAAwAMAADgAAwAAAAAAAPwfAPABAABwAAYAAAAAAID/////AAAA/AMMAAAAAADAB4A/AAAAAAEPAAAAAAAA4AEAAAAADMABOAwAAAAAAH8AAAAAAADgAHAMAAAAAOAfAAAAAABgMABADAAAAIC7DwAAAAAAQBgAAAAAAADgzQ8AAAAAAMAcAAAAAAAA8AAOAAAAAACADwAAAAAAAHgADgAAAAAAgAcAAAAAAAA4AA4AAAAAAAADAAAAAAAACAAOAAAAAACAAQAAAAAAAAAADgAIAAAAgAEAAAAAAAAAAB4ADAAACIABAAAAAAAAAAAeAAwAAAiAAQAAAAAAAAAAvgAMAAAIgAEAAAAAAAAAAPYBBgAACIABAAAAAAAAAABmA38AADiIAQAAAAAAAAAAYoIPAAA/DAMAAAAAAAAAAGKA/wAAeAQGAAAAAAAgAABgwPADAGAEDAAAAAAAIwBgYMCA//PPBzgAAAAAQAYAOHBgAPD/w5/hAAAAAMAEAB4wcAAAAAD7gAEAAADAAAADODAAAAAA5wcDAAAAgAMABx0cAAAAAIY/BwAAAAB/gO8fDgAAAAAscQwAAAAAfsD3DwcAAAAAOOMAAAAAAADA+IMBAAAAADDCAwAAAAAAYN7AAAAAAABgBgMAAAAAAADHYAAAAAAAwAw2AAAAAAAww3AAAAAAAMANbgAAAAAAmMExAAAAAACADewAAAAA/syAEQAAAAAAgA/YAAAAAI9kgBkAAAAAAAAXmAEAAACHMwAbAAAAAAAAPrgDAAAAjjEAEwAAAAAAAHz4AwAAAJgYABIAAAAAAAD88AcAAADgHwA2AAAAAAAA+MEMAAAAwAcANgAAAAAAAPBDDAAAAAACAGwAAAAAAAAwwggAAAAAAADMAAAAAAAAYIAfAAAAAAAAiAEAAAAAAOAcFAAAAAAAAIwBAAAAAADAewAAAAAAAAC+AwAAAAAAgPcAAAAAAAAAPA8AAAAAAADGAQAAAAAAAEAdAAAAAAAA/gMAAAAAAADgPwAAAAAAAPwAAAAAAAAA4D8AAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
12
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwH8AAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAA8H8DAAAAAAAAAAAAAAAAAH4ABwAAAAAAAAAAAAAAAIAPAAwAAAAAAAAAAAAAAATgAQAYAAAAAAAAAAAAAAAAPAAAMAAAAAAAAAAAAAAAAA8AIHgAAAAAAAAAAAAAAMADACDYAAAAAAAAAAAAAAD+AAAwkAEAAAAAAAAAAACADwAAOBADAAAAAAAAAAAAwAMAADgAAwAAAAAAAPwfAPABAABwAAYAAAAAAID/////AAAA/AMMAAAAAADAB4A/AAAAAAEPAAAAAAAA4AEAAAAADMABOAwAAAAAAH8AAAAAAADgAHAMAAAAAOAfAAAAAABgMABADAAAAIC7DwAAAAAAQBgAAAAAAADgzQ8AAAAAAMAcAAAAAAAA8AAOAAAAAACADwAAAAAAAHgADgAAAAAAgAcAAAAAAAA4AA4AAAAAAAADAAAAAAAACAAOAAAAAACAAQAAAAAAAAAADgAIAAAAgAEAAAAAAAAAAB4ADAAACIABAAAAAAAAAAAeAAwAAAiAAQAAAAAAAAAAvgAMAAAIgAEAAAAAAAAAAPYBBgAACIABAAAAAAAAAABmA38AADiIAQAAAAAAAAAAYoIPAAA/DAMAAAAAAAAAAGKA/wAAeAQGAAAAAAAgAABgwPADAGAEDAAAAAAAIwBgYMCA//PPBzgAAAAAQAYAOHBgAPD/w5/hAAAAAMAEAB4wcAAAAAD7gAEAAADAAAADODAAAAAA5wcDAAAAgAMABx0cAAAAAIY/BwAAAAB/gO8fDgAAAAAscQwAAAAAfsD3DwcAAAAAOOMAAAAAAADA+IMBAAAAADDCAwAAAAAAYN7AAAAAAABgBgMAAAAAAADHYAAAAAAAwAw2AAAAAAAww3AAAAAAAMAMbgAAAAAAmMExAAAAAACADewAAAAA/syAEQAAAAAAgA/YAAAAAI9kgBkAAAAAAAAXmAEAAACHMwAbAAAAAAAAPrgDAAAAjjEAEwAAAAAAAHz4AwAAAJgYABIAAAAAAAD88AcAAADgHwA2AAAAAAAA+MEMAAAAwAcANgAAAAAAAPBDDAAAAAACAGwAAAAAAAAwwggAAAAAAADMAAAAAAAAYIAfAAAAAAAAiAEAAAAAAOAcFAAAAAAAAIwBAAAAAADAewAAAAAAAAC+AwAAAAAAgPcAAAAAAAAAPA8AAAAAAADGAQAAAAAAAEAdAAAAAAAA/gMAAAAAAADgPwAAAAAAAPwAAAAAAAAA4D8AAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
13
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+PgAAAAAAAAAAAAAAAAAA4DwAAAAAAAAAAAAAAAAAAMAtAAAAAAAAAAAAAAAAABj43wAAAAAAAAAAAAAAAAAMEMABAAAAAAAAAAAAAAAAwAGAAwAAAAAAAAAAAAAAwGAAAAcAAAAAAAAAAAAAAHA4AAAMAAAAAAAAAAAAAMAgDgAMDwAAAAAAAAAAAADwBwYADB8AAAAAAAAAAAAA8IcAAA42AAAAAAAAAAAAAAB8AAAOZAAAAAAAAAAAAAAADwAADmAAAAAAAAAA/AcAgAMAAA7AAAAAAAAAgP/+APABAAB/gAEAAAAAAPAB4P8/AACA4YEBAAAAAAA4AAjgAQAAAAAHAQAAAAAAHgAAAAAAAAAAjgEAAAAAgAsAAAAAAAAAAIwBAAAAAOAEAAAAAAAAGACIAQAAAAAABAAAAAAAQAwAAAAAAAAACAQAAAAAAMAMAAAAAAAAAA4GAAQAAACABgAAAAAAAAADBAAEAAAAgAMAAAAAAACAAQQABAAAAIABAAAAAAAAAAAAAAQAAAAAAQAAAAAAAAAAAAAGAAAAAAMAAAAAAACAAAAABgAAAAADAAAAAAAAEAAAAAMAAAAAAwAAAAAAABCAF4ADAAAAAAMAAAAAAAAA8A+AHwAAAIADAAAAAAAACBAM4B8AAADAAwAAAAAAAAwGDvA5AAAA4AIAAAAAAAAGGgc4cAAAOGAGAAAAAAAABpwDHMAHAPAADAAAAAAAAAf9AA4A/wzcARgAAAAAAICDv4AHAPD/HwcwAAAAAADDgz/gAQAADAyUYAAAAACg4cEHeAAAAACE8cMBAAAA8IDBDw4AAAAAhMCPAwAAAODP4AsBAAAAAMQABwcAAAAARnPDAQAAAABEABwOAAAAAIB/wwAAAAAAZABwDAAAAADAvAEAAAAAAGYA4AgAAAAA4I0ZAAAAAABmAIBjAAAAAHDQDAAAAAAAZgAAxwMAAAD4/wYAAAAAADYAANgPAAAA/HcDAAAAAAA2AABwHAAAAAC8AwAAAAAAHgAAwPEAAADAnAEAAAAAAB4AAIDvAwAA8McAAAAAAAAPAAAAjw8AALjjAAAAAAAADwAAAAgAAAAcfwAAAAAAgA8AAAD4AQAALD8AAAAAAIALAAAA8AEAAP4/AAAAAACADwAAAAAAAAB4AAAAAAAAwAwAAAAAAAAAAAAAAAAAAMAMAAAAAAAAAAAAAAAAAADADAAAAAAAAAAAAAAAAAAAgA8AAAAAAAAAAAAAAAAAAAA7AAAAAAAAAAAAAAAAAAAAcwAAAAAAAAAAAAAAAAAAAOMAAAAAAAAAAAAAAAAAAAD/AQAAAAAAAAAAAAAAAAAA/wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
14
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAfAAAAAAAAAAAAAAAAAADAHAAAAAAAAAAAAAAAAAAA4A8AAAAAAAAAAAAAAAAAIPhvAAAAAAAAAAAAAAAAAPAcwAAAAAAAAAAAAAAAAACAAIABAAAAAAAAAAAAAAAAAgAAAwAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAMAIYPAAAAAAAAAAAAAABwBgCHCwAAAAAAAAAAAAAAAAMAAxgAAAAAAAAAAAAAQIADAAcTAAAAAAAAAAAAAAD+AAAHIAAAAAAAAADwAQAAHgAAD2AAAAAAAAAA/x8AgAcAgHvAAAAAAAAAwAf4B8ABAIDhgQAAAAAAAHAAAOdvAAQAgIMAAAAAAIAfAAAAAAAMAADGAAAAAADwAwAAAAAAGAAAxAAAAAAAeAEAAAAAABgQAMQAAAAAAOAFAAAAAAAwGAAAAAAAACwgDAAAAAAAIAwAAAAAAAABAAQAAAAAAEAMAAAAAAAAAAAEAAAAAAAABgAAAAAAAAAADAAAAAAAAAYAAAAAAAAAAAwABAAAAIADAAAAAAAAQAAMAAAAAACAAQAAAAAAAAAADAAAAAAAgAEAAAAAAAAwAAwAAQAAAIABAAAAAAAAGOAPgAEAAACAAQAAAAAAYAzwDYABAAAAgAEAAAAAACAE8AbAHwAAAMAAAAAAAAAwBJADwAcAAADAAAAAAAAAMwH+ATAfAAAAQAAAAAAAABMBfgAA+AAAAAAAAAAAAACbAR8AAOAHAACIAAAAAAAA24EDwAEA/wNgjAAAAAAAAOuAAf4AAPD//4ABAAAAAIDvgMAfAAAA4PkDAQAAAADA98DgAAAAAGCYFwMAAAAA4HpgeAAAAABgDDwDAAAAAMA/YE4AAAAAcAd4BgAAAACADzBHAAAAAHAD+AYAAAAAAACYZwAAAAA4A+AMAAAAAAAAzmcAAAAAuAEAHAAAAAAAMMM7AAAAAIwAABgAAAAAAPjjPgAAAADMAIAxAAAAAAD8sQ4AAAAAbAAAMQAAAAAAPvwHAAAAADYAACYAAAAAAPf/AAAAAAAbAAAcAAAAAID/NwAAAAAACwAAOAAAAACADwAAAAAAgA0AAHAAAAAAAAAAAAAAAMAGAADgBgAAAAAAAAAAAABgBgAAwBwAAAAAAAAAAAAAcAMAAAA4AAAAAAAAAAAAADADAAAA8AAAAAAAAAAAAAAcAQAAAOMHAAAAAAAAAAAA+AEAAAA+PgAAAAAAAAAAALABAAAA+BAAAAAAAAAAAAAgAwAAAOAEAAAAAAAAAAAAYA8AAADABwAAAAAAAAAAAOAPAAAAAAAAAAAAAAAAAADgHQAAAAAAAAAAAAAAAAAA4D8AAAAAAAAAAAAAAAAAAOA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
15
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAMAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAAAC8HwAAAAAAAAAAAAAAAAAAxDcAAAAAAAAAAAAAAAAAAAxwAAAAAAAAAAAAAAAAAOAPwAAAAAAAAAAAAAAAAADfA4ABAAAAAAAAAAAAAAAA/wHBAwAAAAAAAAAAAAAAAP4A4QcAAAAAAAAAAAAAAAB8gMEGAAAAAAAAAAAAAAAAHoCBDQAAAAAAAAAAAAAAFA+AARgAAAAAAAAAAAAAAJwPgAMQAAAAAAAAAAAAAAD4B4APcAAAAAAAAAD/HwAA/AGAfWAAAAAAAADAv/8DAB8AwOBAAAAAAAAA4ADgf8APAOCAYQAAAAAAgD8AAPD/AQBgAGMAAAAAAPgfAAAASAAIMABgAAAAAAC/AQAAAAAAGDAAAAAAAADA9wkAAAAAABgYAAAAAAAAeDwIAAAAAAAwDAAAAAAAAA4GDAAAAAAAYAwAAAAAAAAAAAwAAAAAAGAGAAAAAAAAAAAMAAQAAABgBgAAAAAAAwAADAAGAAAAQAIAAAAAAAEAAAwAAgAAAMADAAAAAIABAAA8AAIAAADAAwAAAACAAAAALAADAAAAwAEAAAAAAAAAAG4AAwAAAMAAAAAAAAAAAMAHgAEAAADAAAAAAAAAAAD8A4A/AAAAwAAAAAAAAAAA/gHAPwAAAMAAAAAAAAAAgGAA8A8AAAJgAAAAAAAAAMAAAPgfAAAHcAAAAAAAAABgAIA/fAAABzgAAAAAACAAYOD/D/AHAI4fAAAAAAAgADD8/wCA/8fsCwAAAAAAYACIDwAAAPj//wgAAAAAAGAIjAEAAAAA/zkYAAAAAABgBocABgAAAOMwGAAAAAAAPOIxAAYAAABhYBgAAAAAACDsGAAGAACAM+AZAAAAAAAAfA7ABgAAwBjAGwAAAAAAADMHgAYAAOAcwBgAAAAAAIDrA0AGAABgDoAZAAAAAACA/QF4BgAAYAaAMwAAAAAAwF8AfAYAADADACMAAAAAAMAPAEwDAAAAAQAjAAAAAAAAAADeAwAADgAAZgAAAAAAAAAA4gAAAD8AAGQAAAAAAAAAAAIAAMAfAAAMAAAAAAAAAAACAADwDgAAaAAAAAAAAAAAAAAAMAYAABgAAAAAAAAAAAAAAD4DAAAQAAAAAAAAAAAAAAD/AQAAsAAAAAAAAAAAAACA9QAAALABAAAAAAAAAAAAgD0AAABgAwAAAAAAAAAAAMAPAAAAYAMAAAAAAAAAAADAAQAAAGAGAAAAAAAAAAAAAAAAAADgDAAAAAAAAAAAAAAAAAAA4A8AAAAAAAAAAAAAAAAAAIA7AAAAAAAAAAAAAAAAAAAA+wAAAAAAAAAAAAAAAAAAAN8BAAAAAAAAAAAAAAAAAAD+AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
16
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAADAAQAAAAAAAAAAAAAAAAAAfAcAAAAAAAAAAAAAAAAAAPwPAAAAAAAAAAAAAAAAAAAeGQAAAAAAAAAAAAAAAADgADAAAAAAAAAAAAAAAAAA8ABgAAAAAAAAAAAAAAAAAPAAwAAAAAAAAAAAAAAAAADwgOABAAAAAAAAAAAAAAAAfcDwAwAAAAAAAAAAAAAAAD/AYAcAAAAAAAAAAAAAAAAewMAGAAAAAAAAAAAAAADAAcAACAAAAAAAAAAAAAAA+AXAARgAAAAAAAAAAAAAAH4AwA8wAAAAAAAAAPgfAAAeAMA+IAAAAAAAAAA/OACABwBg4DAAAAAAAACAAwD/5wAAAMAxAAAAAAAAAAAY/G8AAACAMQAAAAAAAAwAEAAAAAAAABAAAAAAAMAPAAAAAAAAAAAAAAAAAADgAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAACAAAAAAAAAQAAAAAAAAAPggAAAAAACAGAAAAAIAHAAwIAAAAAAAAAgAAAADAAYADGAAAAAAAQAMAAAAA4ADwARgADAAAAAADAAAAAGAAeAAYAAwAAACAAQAAAAAwCAgAEAAMAAAAwAAAAAAAEAwAADAABgAAgAAAAAAAABAAAAA4AAYAAAAAAAAAAADQAgAAHAAPAAAAAAAAAAAAUAIAAA8APwAAADAAAAAAADACAP4AwD8AgAEwAAAAAAAQAAACAPB4AIABHAAAAAAAGAEAAAA+4AeAAwwAAAAAABgGAAPwH4D/AGMCAAAAAAB4AwAD/wEA8D9/AwAAAAAAvAMA4zEAAACABwMAAAAAAP4BAHMkAAAAgIcBAAAAAAB+AAAZbAAAAICGAAAAAAAAAAAAHWwAAADAxwAAAAAAAAAAgA1sAAAAwMcAAAAAAAAAAIAOzAAAAOBGAAAAAAAAAAAgBswAAABwZgAAAAAAAAAAOAfIAAAAGG8AAAAAAAAAAB8DiAEA+IdnAAAAAAAAAACPA5gBgPzDYwAAAAAAAABAhgGwAcAP/DMAAAAAAAAAQP8AsAHwxg8xAAAAAAAAAGB/ALgB+P8AGAAAAAAAAABgBwC4AVwbABkAAAAAAAAA8AMA+AF8AAABAAAAAAAAAPABAJABHACAAQAAAAAAAABAAACwAAAAgAUAAAAAAAAAAAAA8AAAAIAEAAAAAAAAAAAAAOAAAADABgAAAAAAAAAAAADAAAAAwAYAAAAAAAAAAAAAAAAAAGAGAAAAAAAAAAAAAAAAAAAwBgAAAAAAAAAAAAAAAAAAMAMAAAAAAAAAAAAAAAAAAOAHAAAAAAAAAAAAAAAAAADADQAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIBzAAAAAAAAAAAAAAAAAACA/gAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
17
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAPwBAAAAAAAAAAAAAAAAAAD8AwAAAAAAAAAAAAAAAAAA+A8AAAAAAAAAAAAAAAAAIIAcAAAAAAAAAAAAAAAAAKgBOAAAAAAAAAAAAAAAAACsAHAAAAAAAAAAAAAAAAAApgBgAAAAAAAAAAAAAAAAAP7A8AAAAAAAAAAAAAAAAMD8wPABAAAAAAAAAAAAAABAGGAgAwAAAAAAAAAAAAAAAABgYAMAAAAAAAAAAAAAAAAC4AAGAAAAAAAAAAAAAAAAAuAADAAAAAAAAAAAAAAATwPgBxgAAAAAAAAA4A8AwH8DYB4YAAAAAAAAAPx/AMD/AQBwCAAAAAAAAAAP4P//cQAA4BgAAAAAAACAAwD/PwAAEMAYAAAAAAAA4AAAwAAAAhiACAAAAAAAAHAAAAAAAAYIAAAAAAAAAAAeAAAAAAAECAAAAAAAAADgBwAAAAAADAwAAAAAAAD8+QcAAAAAAAgEAAAAAADg/8EHAAAAAAAIBAAAAAAAfACAGAAAAAAAAAYAAAAAgH8AcBgAAAAAAAACAAAAAMABAD8YABAAAAAAAwAAAAAAAAADEAAQAAAAAAEAAAAAAAAAATAAGAAAAIABAAAAAAAAAAEwABgAAADAAAAAAAAACHAAMAAYAAAA4AAAAAAAAA8/AGAAGAAAAGAAAAAAAMAAAwDgAAwAQAAwAAAAAABgAAAA8AB8AEAAMAAAAAAAMAAAADAAfABAADgAAAAAABgAAAAcAP4AQAAcAAAAAAAMDgDwA8DcBwAABgAAAAAADAcA+AHwD3/gCAMAAAAAAAwDABgAvwP4f44BAAAAAADGAQAA4OMBAOABAAAAAAAAYwAACGZ+AADg4AAAAAAAADkAAAifDwAAYPAAAAAAAAAIAAAIsAMAAOD4AAAAAAAAAAAAiDAGAADw3AAAAAAAAAAAAMhgBgAAcM4AAAAAAAAAAADIwAwAAHjPAAAAAAAAAAAAzIAJAACYzwAAAAAAAAAAAEyAGQAAzuwAAAAAAAAAAABMABMAeMbMAAAAAAAAAAAATAAjAB7nZwAAAAAAAAAAAGQAZwAH42MAAAAAAAAAAIBnAGYAjzk+AAAAAAAAAACAYwBsAJj9HwAAAAAAAAAAgDAAbACACwAAAAAAAAAAAIAdAG4AkAEAAAAAAAAAAAAgDgBOANgBAAAAAAAAAAAAIAcAXgDsAAAAAAAAAAAAALABAEwAYgAAAAAAAAAAAAAwAABMADMAAAAAAAAAAAAAAAAAQIAxAAAAAAAAAAAAAAAAAECAGQAAAAAAAAAAAAAAAAAAgA0AAAAAAAAAAAAAAAAAAIANAAAAAAAAAAAAAAAAAAAAGwAAAAAAAAAAAAAAAAAAACMAAAAAAAAAAAAAAAAAAIBjAAAAAAAAAAAAAAAAAAAAwQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
18
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAA+N8BAAAAAAAAAAAAAAAAAMwBBwAAAAAAAAAAAAAAAABmAA4AAAAAAAAAAAAAAAAAPgAYAAAAAAAAAAAAAAAAAB4QPgAAAAAAAAAAAAAAAMAOGG4AAAAAAAAAAAAAAABgBxjIAAAAAAAAAAAAAAAA4AMYCAAAAAAAAAAAAAAAAPABGAADAAAAAAAAAAAAAADwATAABgAAAAAAAAAAAAAA8AHwAQQAAAAAAAAAAAAAAOAB8A8EAAAAAAAAAAAAAAD2Axg4BAAAAAAAAAAADAAA/wAIcAQAAAAAAAAAwP8AwH8ADOAEAAAAAAAAAPD/f/9/AAzAAQAAAAAAAAA8AP7/fwAMAAAAAAAAAAAADwAAwHcABAAAAAAAAAAAgAMAAAAwAAQAAAAAAAAAAMABAAAAAAAEAAAAAAAAAADgAAAAAAAABgAAAAAAAAAAcAAAAAAAAAYAAAAAAAAAADgAIAAAAAAGAAAAAAAAAAA+ACAAAAAAAgAAAAAAgAPANwBgAAAAGAMAAAAAAP///zEAYAAAADADAAAAAMAP/P83AGAAAACwAQAAAADwAADgIwFAAAAAoAEAAAAAGAAAAGABQAAAAOAAAAAAAAAAAABgBsAAAADgAAAAAAAAAAAAwAzAAIAA4AAAAAAAAAAAAMAZQADAAPAAAAAAAAAEAAAAB2AAwAD4AAAAAADABQAAAB7wAMAAeAAAAABAYCAAAAAe8AHAAHgAAAAAQBwwAAAABvgfwPg/AAAAAEAWAAAAAAMe/v9/fwAAAABABgAAAIADB+P/l2MAAAAAwAYAAADwgQ8DgIFhAAAAAMAGAAAAfOAMA4DBwAAAAACAAQAAAAY44A+AwsMBAAAAAAEAAAAGHvAfgGPHAQAAAAAAAAAADAfwe4BzPgMAAAAAAAAAABgDzPuAM3gGAAAAAAAAAAAwAc7PgRvgBAAAAAAAAAAAcALPnIMIwAQAAAAAAAAAAGAG/zjPDOAAAAAAAAAAAADADh/x/QxwAAAAAAAAAAAAgB0ewycGvAMAAAAAAAAAAIA7PAcPB84BAAAAAAAAAAAAc/AO/ON3AAAAAAAAAAAAAGfAc/D8PwAAAAAAAAAAAABugMcAegwAAAAAAAAAAAAAbADPAD8HAAAAAAAAAAAAAG4AnoHpAwAAAAAAAAAAAABmAHzH/wEAAAAAAAAAAAAAcADw5h8AAAAAAAAAAAAAAHYA4I0AAAAAAAAAAAAAAABsAGAMAAAAAAAAAAAAAAAAfADAHwAAAAAAAAAAAAAAAHgAgB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
19
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAA/AAAAAAAAAAAAAAAAAAA+N8BAAAAAAAAAAAAAAAAAMwBBwAAAAAAAAAAAAAAAABmAA4AAAAAAAAAAAAAAAAAPgAYAAAAAAAAAAAAAAAAAB4QPgAAAAAAAAAAAAAAAMAOGG4AAAAAAAAAAAAAAABgBxhIAAAAAAAAAAAAAAAA4AMYCAAAAAAAAAAAAAAAAPABGAADAAAAAAAAAAAAAADwATAABgAAAAAAAAAAAAAA8AHwAQQAAAAAAAAAAAAAAOAB8A8EAAAAAAAAAAAAAAD2Axg4BAAAAAAAAAAADAAA/wAIcAQAAAAAAAAAwP8AwH8ADOAEAAAAAAAAAPD/f/9/AAzAAwAAAAAAAAA8AP7/fwAMAAAAAAAAAAAADwAAwHcABAAAAAAAAAAAgAMAAAAwAAQAAAAAAAAAAMABAAAAAAAEAAAAAAAAAADgAAAAAAAABgAAAAAAAAAAcAAAAAAAAAYAAAAAAAAAADgAMAAAAAAGAAAAAAAAAAA+ACAAAAAAAgAAAAAAgAPANwBgAAAAGAMAAAAAAP///zEAYAAAADADAAAAAMAP/P83AGAAAACwAQAAAADwAADgIwBAAAAAoAEAAAAAGAAAAGAAQAAAAOAAAAAAAAAAAABgBsAAAADgAAAAAAAAAAAAwAzAAIAA4AAAAAAAAAAAAMAZQADAAPAAAAAAAAAEAAAAB2AAwAD4AAAAAADABwAAAB7wAMAAeAAAAABAYAAAAAAe8AHAAHgAAAAAQBwQAAAABvgfwPg/AAAAAEAUAAAAAAMe/v9/fwAAAABABgAAAIADB+P/l2EAAAAAwAYAAADwgQ8DgIFhAAAAAMAGAAAAfOAMA4DBwAAAAACAAQAAAAY44A+AwsMBAAAAAAEAAAAGHvAfgGPHAQAAAAAAAAAADAf0e4BzPgMAAAAAAAAAABgDzPuAM3gGAAAAAAAAAAAwAc7PgRvgBAAAAAAAAAAAcALPnIMIwAQAAAAAAAAAAGAGzzjPDOAAAAAAAAAAAADADp/x/QxwAAAAAAAAAAAAgB2ewycGnAMAAAAAAAAAAIA7PAcOB84BAAAAAAAAAAAAc/Ae/ON3AAAAAAAAAAAAAGfAc/D8PwAAAAAAAAAAAABugMcAegwAAAAAAAAAAAAAbADPAD8HAAAAAAAAAAAAAG4AnoHpAwAAAAAAAAAAAABmAHzH/wEAAAAAAAAAAAAAcADw5h8AAAAAAAAAAAAAAHYA4I0AAAAAAAAAAAAAAABsAGAMAAAAAAAAAAAAAAAAfADAHwAAAAAAAAAAAAAAAHgAgB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
20
|
+
];
|
|
@@ -8,6 +8,7 @@ export const receiverStyleRegistry = [
|
|
|
8
8
|
{ id: 'cyclone', maxRows: 14, minRows: 7 },
|
|
9
9
|
{ id: 'nebula', maxRows: 14, minRows: 7 },
|
|
10
10
|
{ id: 'lava-lamp', maxRows: 14, minRows: 7 },
|
|
11
|
+
{ id: 'gallop-fine', maxRows: 18, minRows: 7 },
|
|
11
12
|
{ id: 'motion-contour', maxRows: 14, minRows: 8 },
|
|
12
13
|
{ id: 'ribbon', maxRows: 12, minRows: 7 },
|
|
13
14
|
{ id: 'braille-wave', maxRows: 12, minRows: 7 },
|
|
@@ -60,12 +61,21 @@ export const receiverStyleRegistry = [
|
|
|
60
61
|
{ id: 'skyline', maxRows: 14, minRows: 7 },
|
|
61
62
|
{ id: 'golden-gate', maxRows: 14, minRows: 7 },
|
|
62
63
|
{ id: 'manhattan', maxRows: 14, minRows: 7 },
|
|
63
|
-
{ id: 'alpine', maxRows: 14, minRows: 7 }
|
|
64
|
+
{ id: 'alpine', maxRows: 14, minRows: 7 },
|
|
65
|
+
{ id: 'crossfade', maxRows: 14, minRows: 7 },
|
|
64
66
|
];
|
|
65
67
|
export const receiverStyleNames = receiverStyleRegistry.map(style => style.id);
|
|
66
|
-
export const defaultReceiverStyle = '
|
|
68
|
+
export const defaultReceiverStyle = 'gallop-fine';
|
|
67
69
|
export const receiverStyleMetadata = Object.fromEntries(receiverStyleRegistry.map(style => [style.id, style]));
|
|
68
70
|
const retiredReceiverStyleNames = [
|
|
71
|
+
'duplex-wave', 'color-drift', 'undertow', 'cube-tide', 'parallax-slabs', 'voxel-swell',
|
|
72
|
+
'dot-current', 'flip-matrix', 'raster-harp',
|
|
73
|
+
'spin-lattice', 'packet-storm', 'spark-chamber',
|
|
74
|
+
'magnetic-bloom', 'liquid-chrome', 'vector-braid', 'halftone-orbit',
|
|
75
|
+
'sonic-fan', 'raster-disc', 'diamond-current', 'velvet-vortex',
|
|
76
|
+
'din-stack', 'bass-shutters', 'velvet-dither', 'chrome-sweep', 'prism-steps', 'stereo-iris',
|
|
77
|
+
'phosphor-marquee', 'ascii-drive', 'prism-bank', 'gallop', 'gallop-ultrafine',
|
|
78
|
+
'gallop-solid', 'gallop-shaded', 'gallop-dither', 'gallop-hatch', 'gallop-scanline',
|
|
69
79
|
'scope', 'spectrum', 'oscilloscope', 'sdr', 'signal', 'retro', 'neon', 'waterfall',
|
|
70
80
|
'cassette', 'casette', 'stars', 'radio-waves', 'raindrops', 'vinyl', 'soundwave',
|
|
71
81
|
'spectrum-3d', 'tuning-dial', 'rf-constellation', 'rf-constelation', 'sphere', 'mobius',
|