ha-opencode 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,29 +1,44 @@
1
- # ha-opencode
1
+ # OpenCode Home Assistant Plugin
2
2
 
3
- OpenCode plugin for Home Assistant integration via MQTT Discovery.
3
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://stephengolub.github.io/opencode-homeassistant)
4
+ [![GitHub Release](https://img.shields.io/github/v/release/stephengolub/opencode-homeassistant)](https://github.com/stephengolub/opencode-homeassistant/releases)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
6
 
5
- Exposes OpenCode session state as Home Assistant entities and allows bidirectional control (responding to permission requests, sending prompts, viewing history).
7
+ OpenCode plugin that enables real-time integration with Home Assistant via native WebSocket connection.
8
+
9
+ Monitor and control your OpenCode sessions directly from Home Assistant - get notified when tasks complete, approve permissions from your phone, and even send prompts remotely.
10
+
11
+ **[Full Documentation](https://stephengolub.github.io/opencode-homeassistant)** | **[Home Assistant Integration](https://github.com/stephengolub/ha-opencode)**
6
12
 
7
13
  ## Features
8
14
 
9
- - **Session-Based Identity**: Each OpenCode session gets its own HA device and entities
10
- - **Real-time State Tracking**: Session state, model, current tool, tokens, and cost
11
- - **Permission Handling**: Approve/reject permission requests from HA or mobile notifications
12
- - **Send Prompts**: Send prompts to OpenCode sessions via MQTT
13
- - **Session History**: Retrieve conversation history on demand
14
- - **Agent Tracking**: Track primary agent and sub-agents being used
15
- - **Hostname Display**: Identify which machine the session is running on
16
- - **Automatic Cleanup**: Stale sessions (7+ days inactive) are automatically removed
15
+ - **Native WebSocket**: Direct connection to Home Assistant - no MQTT broker required
16
+ - **Secure Pairing**: Simple one-time pairing flow with secure token authentication
17
+ - **Real-time Updates**: Instant session state, model, tool, token, and cost updates
18
+ - **Permission Handling**: Approve/reject tool permissions from Home Assistant or mobile notifications
19
+ - **Session History**: Retrieve full conversation history on demand
20
+ - **Multi-session Support**: Each session gets its own device in Home Assistant
21
+ - **Auto-reconnect**: Persistent connection with automatic reconnection
22
+
23
+ ## Requirements
24
+
25
+ - [OpenCode](https://opencode.ai) AI coding assistant
26
+ - [Home Assistant](https://www.home-assistant.io/) with the companion integration installed:
27
+ - **[ha-opencode](https://github.com/stephengolub/ha-opencode)** - Home Assistant integration (required)
17
28
 
18
29
  ## Installation
19
30
 
20
- ### 1. Install the plugin
31
+ ### 1. Install the Plugin
21
32
 
22
33
  ```bash
23
- npm install --prefix ~/.config/opencode /path/to/ha-opencode
34
+ # From npm (when published)
35
+ npm install --prefix ~/.config/opencode ha-opencode
36
+
37
+ # Or from local path
38
+ npm install --prefix ~/.config/opencode /path/to/opencode-homeassistant
24
39
  ```
25
40
 
26
- ### 2. Add to OpenCode config
41
+ ### 2. Add to OpenCode Config
27
42
 
28
43
  Add `"ha-opencode"` to the `plugins` array in `~/.config/opencode/opencode.json`:
29
44
 
@@ -33,223 +48,94 @@ Add `"ha-opencode"` to the `plugins` array in `~/.config/opencode/opencode.json`
33
48
  }
34
49
  ```
35
50
 
36
- ### 3. Configure MQTT connection
37
-
38
- Via environment variables:
39
-
40
- ```bash
41
- export OPENCODE_MQTT_HOST=your-mqtt-broker.local
42
- export OPENCODE_MQTT_PORT=1883
43
- export OPENCODE_MQTT_USERNAME=optional-username
44
- export OPENCODE_MQTT_PASSWORD=optional-password
45
- export OPENCODE_HA_DISCOVERY_PREFIX=homeassistant # default
46
- ```
47
-
48
- Or via `opencode.json`:
49
-
50
- ```json
51
- {
52
- "plugins": ["ha-opencode"],
53
- "ha-opencode": {
54
- "mqtt": {
55
- "host": "your-mqtt-broker.local",
56
- "port": 1883,
57
- "username": "optional-username",
58
- "password": "optional-password"
59
- },
60
- "ha": {
61
- "discoveryPrefix": "homeassistant"
62
- }
63
- }
64
- }
65
- ```
66
-
67
- Environment variables take precedence over JSON config.
68
-
69
- ## Session-Based Identity
70
-
71
- Each OpenCode session creates a unique Home Assistant device:
72
-
73
- - **Session ID**: `ses_46b09b89bffevq6HeMNIkuvk4B` (generated by OpenCode)
74
- - **Device ID**: `opencode_46b09b89bffevq6HeMNIkuvk4B` (strips `ses_` prefix)
75
- - **Initial Name**: `OpenCode - {projectName} - Untitled`
76
- - **After Title**: `OpenCode - {projectName} - {sessionTitle}`
77
-
78
- This allows running multiple concurrent OpenCode sessions in the same directory, each with their own entities.
79
-
80
- ## Entities Created
81
-
82
- Per OpenCode session (device), the following entities are created:
83
-
84
- | Entity | Type | Description |
85
- |--------|------|-------------|
86
- | `sensor.opencode_*_state` | Sensor | Session state (idle, working, waiting_permission, error) |
87
- | `sensor.opencode_*_session_title` | Sensor | Current session/conversation title |
88
- | `sensor.opencode_*_model` | Sensor | AI model being used (provider/model) |
89
- | `sensor.opencode_*_current_tool` | Sensor | Currently executing tool |
90
- | `sensor.opencode_*_tokens_input` | Sensor | Input token count |
91
- | `sensor.opencode_*_tokens_output` | Sensor | Output token count |
92
- | `sensor.opencode_*_cost` | Sensor | Session cost in USD |
93
- | `sensor.opencode_*_last_activity` | Sensor | Timestamp of last activity |
94
- | `sensor.opencode_*_permission` | Sensor | Permission request status |
95
- | `sensor.opencode_*_device_id` | Sensor | Device identifier with command/response topics |
96
-
97
- **Note**: The `*` in entity IDs represents the session ID (e.g., `sensor.opencode_46b09b89bffevq6HeMNIkuvk4B_state`).
98
-
99
- ### State Entity Attributes
100
-
101
- The `state` entity includes these attributes:
102
-
103
- - `previous_state`: The state before the current one (for automation conditions)
104
- - `agent`: Primary agent selected by the user
105
- - `current_agent`: Sub-agent currently being used (if any)
106
- - `hostname`: Machine hostname where OpenCode is running
107
- - `error_message`: Error details when in error state
108
-
109
- ### Device ID Entity Attributes
110
-
111
- The `device_id` entity includes:
112
-
113
- - `command_topic`: MQTT topic for sending commands
114
- - `response_topic`: MQTT topic for receiving responses
115
- - `state_topic_base`: Base topic for all state updates
116
- - `device_name`: Friendly device name
117
- - `session_id`: Full session ID (e.g., `ses_46b09b89bffevq6HeMNIkuvk4B`)
118
- - `project_name`: Project directory name
119
-
120
- ## MQTT Topics
121
-
122
- For a session with ID `ses_46b09b89bffevq6HeMNIkuvk4B`:
123
-
124
- ```
125
- # State topics
126
- opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/state
127
- opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/state/attributes
128
- opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/session_title
129
- opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/model
130
- opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/availability
131
-
132
- # Commands & responses
133
- opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/command
134
- opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/response
135
-
136
- # HA Discovery
137
- homeassistant/sensor/opencode_46b09b89bffevq6HeMNIkuvk4B/state/config
138
-
139
- # Global cleanup response
140
- opencode/cleanup/response
141
- ```
142
-
143
- ## MQTT Commands
51
+ ### 3. Install the Home Assistant Integration
144
52
 
145
- Send commands to the `command_topic` (e.g., `opencode/opencode_46b09b89bffevq6HeMNIkuvk4B/command`):
53
+ The plugin requires the companion Home Assistant integration. See [ha-opencode](https://github.com/stephengolub/ha-opencode) for installation instructions.
146
54
 
147
- ### Permission Response
148
-
149
- ```json
150
- {
151
- "command": "permission_response",
152
- "permission_id": "perm-123",
153
- "response": "once"
154
- }
155
- ```
55
+ ### 4. Pair with Home Assistant
156
56
 
157
- Response options: `"once"`, `"always"`, or `"reject"`
57
+ 1. In Home Assistant, go to Settings > Devices & Services
58
+ 2. Add the "OpenCode" integration
59
+ 3. A pairing code will be displayed (e.g., `ABC12DEF`)
60
+ 4. In OpenCode, use the `ha_pair` tool with:
61
+ - Your Home Assistant URL (e.g., `http://homeassistant.local:8123`)
62
+ - A [long-lived access token](https://www.home-assistant.io/docs/authentication/#your-account-profile)
63
+ - The pairing code
158
64
 
159
- ### Send Prompt
65
+ Once paired, the plugin will automatically reconnect on subsequent OpenCode sessions.
160
66
 
161
- ```json
162
- {
163
- "command": "prompt",
164
- "text": "Your prompt text here",
165
- "session_id": "optional-session-id"
166
- }
167
- ```
67
+ ## Configuration
168
68
 
169
- ### Get History
69
+ The plugin stores connection configuration in `~/.config/opencode/ha-config.json` after pairing:
170
70
 
171
71
  ```json
172
72
  {
173
- "command": "get_history",
174
- "session_id": "optional-session-id",
175
- "request_id": "optional-correlation-id"
73
+ "url": "ws://homeassistant.local:8123/api/websocket",
74
+ "accessToken": "your-access-token",
75
+ "instanceToken": "generated-during-pairing",
76
+ "instanceId": "instance_abc123"
176
77
  }
177
78
  ```
178
79
 
179
- ### Get History Since
80
+ You can also set the Home Assistant URL and access token via environment variables:
180
81
 
181
- ```json
182
- {
183
- "command": "get_history_since",
184
- "since": "2024-01-01T00:00:00Z",
185
- "session_id": "optional-session-id",
186
- "request_id": "optional-correlation-id"
187
- }
82
+ ```bash
83
+ export OPENCODE_HA_URL=http://homeassistant.local:8123
84
+ export OPENCODE_HA_ACCESS_TOKEN=your-access-token
188
85
  ```
189
86
 
190
- ### Cleanup Stale Sessions
87
+ ## How It Works
191
88
 
192
- ```json
193
- {
194
- "command": "cleanup_stale_sessions",
195
- "max_age_days": 7
196
- }
197
89
  ```
198
-
199
- Response published to `opencode/cleanup/response`:
200
-
201
- ```json
202
- {
203
- "type": "cleanup_result",
204
- "sessions_removed": 3,
205
- "session_ids": ["opencode_abc123...", "opencode_def456..."],
206
- "max_age_days": 7,
207
- "timestamp": "2025-01-07T12:00:00Z"
208
- }
90
+ ┌─────────────────┐ WebSocket ┌──────────────────┐
91
+ │ │◄────────────────►│ │
92
+ │ OpenCode │ │ Home Assistant │
93
+ │ + Plugin │ │ + Integration │
94
+ │ │ │ │
95
+ └─────────────────┘ └──────────────────┘
96
+
97
+
98
+ ┌──────────────────┐
99
+ Lovelace Card │
100
+ │ Mobile App │
101
+ │ Automations │
102
+ └──────────────────┘
209
103
  ```
210
104
 
211
- ## Stale Session Cleanup
212
-
213
- Sessions that haven't been active for 7 days are automatically cleaned up:
214
-
215
- - **Automatic**: Runs on every plugin startup (async, non-blocking)
216
- - **Manual**: Send `cleanup_stale_sessions` command via MQTT
217
-
218
- Cleanup removes all HA entities for stale sessions by publishing empty configs to the discovery topics.
219
-
220
- ## Home Assistant Blueprints
221
-
222
- Pre-built automation blueprints are available in the `blueprints/` directory:
223
-
224
- | Blueprint | Description |
225
- |-----------|-------------|
226
- | `opencode_state_notifications.yaml` | Mobile notifications for task complete, permission required, and errors |
227
- | `opencode_permission_response.yaml` | Handle approve/reject button taps from notifications |
228
-
229
- ### Installing Blueprints
230
-
231
- 1. Copy blueprints to your HA config:
232
- ```bash
233
- mkdir -p /path/to/ha/config/blueprints/automation/opencode
234
- cp blueprints/*.yaml /path/to/ha/config/blueprints/automation/opencode/
235
- ```
236
-
237
- 2. Reload automations in HA (Developer Tools > YAML > Reload Automations)
238
-
239
- 3. Create automations from blueprints:
240
- - Settings > Automations > Create Automation > Use Blueprint
241
- - Select the OpenCode blueprint
242
- - Configure your mobile device and preferences
243
-
244
- See [ha-card/README.md](ha-card/README.md) for detailed blueprint configuration and automation examples.
245
-
246
- ## Home Assistant Card
247
-
248
- A custom Lovelace card is included for displaying OpenCode sessions in Home Assistant.
249
-
250
- See [ha-card/README.md](ha-card/README.md) for installation and usage instructions.
251
-
252
- > **Note**: The card will be moved to a separate repository ([opencode-card](https://gitlab.com/opencode-home-assistant/opencode-card)) for HACS compatibility. The `ha-card/` directory is structured for easy extraction when that happens.
105
+ 1. **Plugin** connects to Home Assistant via WebSocket
106
+ 2. **Session updates** are sent in real-time (state, model, tokens, cost, permissions)
107
+ 3. **Commands** flow back from HA (send prompt, respond to permission, get history)
108
+ 4. **Events** are fired in HA for automations (state changes, permission requests)
109
+
110
+ ## Commands from Home Assistant
111
+
112
+ The plugin responds to these commands sent via the Home Assistant integration:
113
+
114
+ | Command | Description |
115
+ |---------|-------------|
116
+ | `send_prompt` | Send a text prompt to the current session |
117
+ | `respond_permission` | Approve (once/always) or reject a permission request |
118
+ | `get_history` | Retrieve session conversation history |
119
+ | `get_agents` | Get list of available agents |
120
+
121
+ ## Session Data
122
+
123
+ Each OpenCode session reports the following to Home Assistant:
124
+
125
+ | Data | Description |
126
+ |------|-------------|
127
+ | `state` | Session state: `idle`, `working`, `waiting_permission`, `error` |
128
+ | `title` | Session/conversation title |
129
+ | `model` | AI model being used (e.g., `anthropic/claude-sonnet-4-20250514`) |
130
+ | `current_tool` | Currently executing tool |
131
+ | `tokens_input` | Total input tokens used |
132
+ | `tokens_output` | Total output tokens used |
133
+ | `cost` | Total session cost in USD |
134
+ | `last_activity` | Timestamp of last activity |
135
+ | `agent` | Primary agent selected |
136
+ | `current_agent` | Sub-agent currently executing |
137
+ | `hostname` | Machine hostname |
138
+ | `permission` | Pending permission details (if any) |
253
139
 
254
140
  ## Development
255
141
 
@@ -274,41 +160,55 @@ npm run test:coverage
274
160
 
275
161
  ```
276
162
  src/
277
- index.ts Plugin entry point, defers setup until first session event
278
- config.ts Configuration loading (env vars + JSON)
279
- mqtt.ts MQTT client wrapper with wildcard support
280
- discovery.ts Session-based HA MQTT Discovery
281
- state.ts State tracking and publishing
282
- commands.ts MQTT command handler
283
- cleanup.ts Stale session cleanup
284
- notify.ts Terminal notification utilities (Kitty OSC 99)
285
-
286
- blueprints/
287
- opencode_state_notifications.yaml Mobile notification blueprint
288
- opencode_permission_response.yaml Permission action handler
289
-
290
- ha-card/
291
- src/ Custom Lovelace card source
292
- dist/ Built card JS
163
+ index.ts Plugin entry point
164
+ websocket.ts Home Assistant WebSocket client
165
+ state.ts Session state tracking
166
+ commands.ts Command handler (prompts, permissions, history)
167
+ ha-config.ts Configuration storage
168
+ notify.ts Terminal notifications (Kitty OSC 99)
169
+
170
+ tests/
171
+ *.test.ts Unit tests
293
172
  ```
294
173
 
295
174
  ## Troubleshooting
296
175
 
297
- ### Too many entities in HA
176
+ ### Plugin not connecting
177
+
178
+ 1. Verify the Home Assistant integration is installed and configured
179
+ 2. Check that your access token is valid (test in Developer Tools > API)
180
+ 3. Look for connection errors in OpenCode output
181
+ 4. Try re-pairing: delete `~/.config/opencode/ha-config.json` and pair again
182
+
183
+ ### Permission responses not working
184
+
185
+ 1. Ensure the session is still active (not disconnected)
186
+ 2. Check Home Assistant logs for errors
187
+ 3. Verify the permission ID matches the pending permission
188
+
189
+ ### Notifications not appearing
298
190
 
299
- Each session creates a new set of entities. Use the cleanup command or rely on automatic cleanup to remove old sessions. Sessions inactive for 7+ days are automatically removed on plugin startup.
191
+ This plugin uses Kitty terminal notifications (OSC 99). Supported terminals:
192
+ - Kitty
193
+ - iTerm2 (with notifications enabled)
300
194
 
301
- ### Entity naming shows "Untitled"
195
+ If your terminal doesn't support OSC 99, notifications will be silent.
302
196
 
303
- This is the initial name before session title is available. Once the session gets a proper title, the device name updates automatically.
197
+ ## Documentation
304
198
 
305
- ### Automation not triggering
199
+ Full documentation is available at **[stephengolub.github.io/opencode-homeassistant](https://stephengolub.github.io/opencode-homeassistant)**
306
200
 
307
- Check that `previous_state` attribute is available when state changes. Attributes are published BEFORE the state value to ensure they're available when automations trigger.
201
+ - [Installation Guide](https://stephengolub.github.io/opencode-homeassistant/getting-started/installation/)
202
+ - [Configuration](https://stephengolub.github.io/opencode-homeassistant/getting-started/configuration/)
203
+ - [Pairing with Home Assistant](https://stephengolub.github.io/opencode-homeassistant/getting-started/pairing/)
204
+ - [Session Tracking](https://stephengolub.github.io/opencode-homeassistant/features/session-tracking/)
205
+ - [Commands](https://stephengolub.github.io/opencode-homeassistant/features/commands/)
206
+ - [Permissions](https://stephengolub.github.io/opencode-homeassistant/features/permissions/)
308
207
 
309
- ### Kitty notifications not working
208
+ ## Related Projects
310
209
 
311
- Ensure your terminal supports OSC 99 (Kitty, iTerm2) and that stdout is a TTY.
210
+ - **[ha-opencode](https://github.com/stephengolub/ha-opencode)** - Home Assistant integration with Lovelace card and blueprints ([docs](https://stephengolub.github.io/ha-opencode))
211
+ - **[OpenCode](https://opencode.ai)** - AI coding assistant
312
212
 
313
213
  ## License
314
214
 
@@ -1,23 +1,25 @@
1
1
  import type { OpencodeClient } from "@opencode-ai/sdk";
2
- import type { MqttWrapper } from "./mqtt.js";
3
- import type { Discovery } from "./discovery.js";
2
+ import type { HAWebSocketClient } from "./websocket.js";
4
3
  import type { StateTracker } from "./state.js";
5
- import type { HaConfig } from "./config.js";
6
4
  export declare class CommandHandler {
7
- private readonly mqtt;
8
- private readonly discovery;
5
+ private readonly wsClient;
9
6
  private readonly state;
10
7
  private readonly client;
11
- private readonly haConfig;
12
- constructor(mqtt: MqttWrapper, discovery: Discovery, state: StateTracker, client: OpencodeClient, haConfig: HaConfig);
13
- start(): Promise<void>;
14
- private handleMessage;
8
+ private readonly instanceToken;
9
+ constructor(wsClient: HAWebSocketClient, state: StateTracker, client: OpencodeClient, instanceToken: string);
10
+ /**
11
+ * Start listening for commands from Home Assistant.
12
+ */
13
+ start(): void;
14
+ private handleCommand;
15
15
  private processCommand;
16
- private handleCleanup;
16
+ /**
17
+ * Handle state request from HA - send all current sessions.
18
+ */
19
+ private handleStateRequest;
17
20
  private handlePrompt;
18
21
  private handleGetAgents;
19
22
  private handleGetHistory;
20
- private handleGetHistorySince;
21
23
  private fetchSessionHistory;
22
24
  private handlePermissionResponse;
23
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA2F5C,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;gBAGlC,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,QAAQ;IASd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,OAAO,CAAC,aAAa;YA4BP,cAAc;YAyBd,aAAa;YAkBb,YAAY;YAgCZ,eAAe;YA6Bf,gBAAgB;YA4BhB,qBAAqB;YAwCrB,mBAAmB;YAkFnB,wBAAwB;CA4CvC"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EACV,iBAAiB,EAMlB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAuB/C,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;gBAGrC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,cAAc,EACtB,aAAa,EAAE,MAAM;IAQvB;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,aAAa;YAgBP,cAAc;IAgC5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;YASZ,YAAY;YAuCZ,eAAe;YA6Bf,gBAAgB;YAqChB,mBAAmB;YA6FnB,wBAAwB;CAoDvC"}