mindsystem-cc 3.12.0 → 3.13.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/agents/ms-consolidator.md +4 -4
- package/agents/ms-executor.md +19 -351
- package/agents/ms-flutter-code-quality.md +7 -6
- package/agents/ms-mock-generator.md +51 -138
- package/agents/ms-plan-checker.md +170 -175
- package/agents/ms-plan-writer.md +120 -115
- package/agents/ms-verifier.md +22 -18
- package/commands/ms/check-phase.md +3 -3
- package/commands/ms/execute-phase.md +8 -6
- package/commands/ms/plan-phase.md +4 -3
- package/commands/ms/verify-work.md +7 -7
- package/mindsystem/references/goal-backward.md +10 -25
- package/mindsystem/references/mock-patterns.md +149 -240
- package/mindsystem/references/plan-format.md +326 -247
- package/mindsystem/references/scope-estimation.md +29 -24
- package/mindsystem/references/tdd-execution.md +70 -0
- package/mindsystem/references/tdd.md +53 -194
- package/mindsystem/templates/UAT.md +16 -16
- package/mindsystem/templates/phase-prompt.md +51 -367
- package/mindsystem/templates/roadmap.md +1 -1
- package/mindsystem/templates/verification-report.md +2 -2
- package/mindsystem/workflows/adhoc.md +16 -21
- package/mindsystem/workflows/execute-phase.md +71 -49
- package/mindsystem/workflows/execute-plan.md +183 -1054
- package/mindsystem/workflows/plan-phase.md +47 -38
- package/mindsystem/workflows/verify-phase.md +16 -20
- package/mindsystem/workflows/verify-work.md +54 -67
- package/package.json +1 -1
- package/scripts/update-state.sh +59 -0
- package/scripts/validate-execution-order.sh +102 -0
- package/skills/flutter-code-quality/SKILL.md +4 -3
- package/mindsystem/templates/summary.md +0 -293
- package/mindsystem/workflows/generate-mocks.md +0 -261
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
<overview>
|
|
2
|
-
Mock patterns for manual UAT testing. Mocks are temporary
|
|
2
|
+
Mock patterns for manual UAT testing. Mocks are temporary inline edits to service methods — hardcoded return values that let you reach testable UI states. They exist only as uncommitted changes, never in commit history.
|
|
3
3
|
</overview>
|
|
4
4
|
|
|
5
|
-
<philosophy>
|
|
6
|
-
**Mocks enable testing states you can't easily reach.**
|
|
7
|
-
|
|
8
|
-
Without mocks, testing "error message display" requires actually triggering server errors. Testing "premium user badge" requires a premium account. Testing "empty list placeholder" requires deleting all data.
|
|
9
|
-
|
|
10
|
-
**With mocks:** Set a flag, hot reload, test the UI state.
|
|
11
|
-
|
|
12
|
-
**Core principles:**
|
|
13
|
-
1. **Temporary** — Mocks are stashed/discarded, never committed
|
|
14
|
-
2. **Minimal** — One override file, minimal production hooks
|
|
15
|
-
3. **Explicit** — Clear flags, clear toggle instructions
|
|
16
|
-
4. **Removable** — Delete file + remove imports = clean
|
|
17
|
-
</philosophy>
|
|
18
|
-
|
|
19
5
|
<classification_framework>
|
|
20
6
|
|
|
21
7
|
**Two-question framework for mock classification:**
|
|
@@ -57,19 +43,161 @@ Domain terms don't map reliably to mock types. "View recipe list" needs external
|
|
|
57
43
|
|
|
58
44
|
</classification_framework>
|
|
59
45
|
|
|
46
|
+
<mock_types>
|
|
47
|
+
|
|
48
|
+
| Mock Type | Enables Testing | Inline Pattern |
|
|
49
|
+
|-----------|-----------------|----------------|
|
|
50
|
+
| `error_state` | Error messages, retry UI, fallback displays | Throw exception before real implementation |
|
|
51
|
+
| `premium_user` | Premium badges, gated features, upgrade prompts | Return mock user object with premium fields |
|
|
52
|
+
| `empty_response` | Empty states, placeholder UI, "no results" | Return empty list/null before real implementation |
|
|
53
|
+
| `loading_state` | Loading spinners, skeleton screens | Add delay before real implementation |
|
|
54
|
+
| `offline` | Offline UI, cached data, sync indicators | Throw network error before real implementation |
|
|
55
|
+
| `transient_state` | Brief async states (loading skeletons, transitions) | Delay or never-resolve strategies (see below) |
|
|
56
|
+
| `external_data` | Features depending on API data that may not exist locally | Return hardcoded data objects |
|
|
57
|
+
|
|
58
|
+
</mock_types>
|
|
59
|
+
|
|
60
|
+
<inline_mock_patterns>
|
|
61
|
+
|
|
62
|
+
**Inline mocks edit service methods directly.** Add hardcoded return values BEFORE the real implementation. Mark with `// MOCK:` comment for cleanup tracking.
|
|
63
|
+
|
|
64
|
+
**Pattern:** Early return with mock comment
|
|
65
|
+
```
|
|
66
|
+
// MOCK: {description} — revert after UAT
|
|
67
|
+
{hardcoded return/throw}
|
|
68
|
+
|
|
69
|
+
// Real implementation below...
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**By mock_type:**
|
|
73
|
+
|
|
74
|
+
**error_state** — Throw before real call:
|
|
75
|
+
```dart
|
|
76
|
+
// Before:
|
|
77
|
+
Future<User> login(String email, String password) async {
|
|
78
|
+
final response = await _api.post('/auth/login', data: {'email': email, 'password': password});
|
|
79
|
+
return User.fromJson(response.data);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// After:
|
|
83
|
+
Future<User> login(String email, String password) async {
|
|
84
|
+
// MOCK: force login error — revert after UAT
|
|
85
|
+
throw Exception('Invalid credentials');
|
|
86
|
+
|
|
87
|
+
final response = await _api.post('/auth/login', data: {'email': email, 'password': password});
|
|
88
|
+
return User.fromJson(response.data);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**empty_response** — Return empty collection:
|
|
93
|
+
```dart
|
|
94
|
+
// Before:
|
|
95
|
+
Future<List<Recipe>> getRecipes() async {
|
|
96
|
+
final response = await _api.get('/recipes');
|
|
97
|
+
return response.data.map((j) => Recipe.fromJson(j)).toList();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// After:
|
|
101
|
+
Future<List<Recipe>> getRecipes() async {
|
|
102
|
+
// MOCK: force empty list — revert after UAT
|
|
103
|
+
return [];
|
|
104
|
+
|
|
105
|
+
final response = await _api.get('/recipes');
|
|
106
|
+
return response.data.map((j) => Recipe.fromJson(j)).toList();
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**premium_user / external_data** — Return hardcoded object:
|
|
111
|
+
```dart
|
|
112
|
+
// Before:
|
|
113
|
+
Future<User> getCurrentUser() async {
|
|
114
|
+
final response = await _api.get('/user/me');
|
|
115
|
+
return User.fromJson(response.data);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// After:
|
|
119
|
+
Future<User> getCurrentUser() async {
|
|
120
|
+
// MOCK: force premium user — revert after UAT
|
|
121
|
+
return User(id: 'mock-001', name: 'Test User', isPremium: true, tier: 'gold');
|
|
122
|
+
|
|
123
|
+
final response = await _api.get('/user/me');
|
|
124
|
+
return User.fromJson(response.data);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**TypeScript equivalents follow identical pattern** — early return/throw with `// MOCK:` comment before the real implementation.
|
|
129
|
+
|
|
130
|
+
</inline_mock_patterns>
|
|
131
|
+
|
|
132
|
+
<transient_state_patterns>
|
|
133
|
+
|
|
134
|
+
**Transient states are UI states that appear briefly during async operations.** Loading skeletons, shimmer effects, transition animations — they resolve too fast to observe and test manually.
|
|
135
|
+
|
|
136
|
+
**Two strategies:**
|
|
137
|
+
|
|
138
|
+
**1. Extended delay (default):**
|
|
139
|
+
|
|
140
|
+
Add a configurable delay before the real data returns. The transient state stays visible long enough to test.
|
|
141
|
+
|
|
142
|
+
```dart
|
|
143
|
+
// MOCK: extend loading state for testing — revert after UAT
|
|
144
|
+
await Future.delayed(const Duration(seconds: 5));
|
|
145
|
+
|
|
146
|
+
// Real implementation continues...
|
|
147
|
+
final response = await _api.get('/recipes');
|
|
148
|
+
return response.data.map((j) => Recipe.fromJson(j)).toList();
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// MOCK: extend loading state for testing — revert after UAT
|
|
153
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
154
|
+
|
|
155
|
+
// Real implementation continues...
|
|
156
|
+
const response = await fetch('/api/recipes');
|
|
157
|
+
return response.json();
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**When to use:** Testing that the loading UI (skeleton, spinner) displays correctly while waiting.
|
|
161
|
+
|
|
162
|
+
**2. Never-resolve:**
|
|
163
|
+
|
|
164
|
+
The async call never completes. The transient state stays permanently visible.
|
|
165
|
+
|
|
166
|
+
```dart
|
|
167
|
+
// MOCK: freeze loading state — revert after UAT
|
|
168
|
+
await Completer<void>().future; // Never completes
|
|
169
|
+
|
|
170
|
+
// Real implementation continues...
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// MOCK: freeze loading state — revert after UAT
|
|
175
|
+
await new Promise(() => {}); // Never resolves
|
|
176
|
+
|
|
177
|
+
// Real implementation continues...
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**When to use:** Testing that the loading UI itself is correct (layout, styling, animation) without it disappearing.
|
|
181
|
+
|
|
182
|
+
**Choosing between strategies:**
|
|
183
|
+
- Testing the transition (loading → loaded): Use extended delay (5s default)
|
|
184
|
+
- Testing the loading UI appearance: Use never-resolve
|
|
185
|
+
|
|
186
|
+
</transient_state_patterns>
|
|
187
|
+
|
|
60
188
|
<git_stash_lifecycle>
|
|
61
189
|
|
|
62
190
|
**Why stash?**
|
|
63
191
|
|
|
64
|
-
Fixes must be clean commits (no mock code). But after fixing,
|
|
192
|
+
Fixes must be clean commits (no mock code). But after fixing, mocks need to be restored to re-test. Git stash enables this:
|
|
65
193
|
|
|
66
194
|
```
|
|
67
195
|
┌─────────────────────────────────────────────────────────────┐
|
|
68
196
|
│ Phase 1: Setup │
|
|
69
197
|
├─────────────────────────────────────────────────────────────┤
|
|
70
198
|
│ 1. git stash push -m "pre-verify-work" (if dirty) │
|
|
71
|
-
│ 2.
|
|
72
|
-
│ 3.
|
|
199
|
+
│ 2. Inline mocks applied to service methods (uncommitted) │
|
|
200
|
+
│ 3. Mocked files tracked in UAT.md: mocked_files: [...] │
|
|
73
201
|
└─────────────────────────────────────────────────────────────┘
|
|
74
202
|
│
|
|
75
203
|
▼
|
|
@@ -78,7 +206,7 @@ Fixes must be clean commits (no mock code). But after fixing, we need mocks back
|
|
|
78
206
|
├─────────────────────────────────────────────────────────────┤
|
|
79
207
|
│ 4. User tests on device with mocks active │
|
|
80
208
|
│ 5. User reports issue │
|
|
81
|
-
│ 6. git stash push -m "mocks-batch-N"
|
|
209
|
+
│ 6. git stash push -m "mocks-batch-N" -- <mocked_files> │
|
|
82
210
|
│ 7. Fixer investigates and commits fix ← Clean commit │
|
|
83
211
|
│ 8. git stash pop ← Restore mocks │
|
|
84
212
|
│ 9. User re-tests specific item │
|
|
@@ -89,7 +217,7 @@ Fixes must be clean commits (no mock code). But after fixing, we need mocks back
|
|
|
89
217
|
┌─────────────────────────────────────────────────────────────┐
|
|
90
218
|
│ Phase 3: Cleanup │
|
|
91
219
|
├─────────────────────────────────────────────────────────────┤
|
|
92
|
-
│ 11. git
|
|
220
|
+
│ 11. git checkout -- <mocked_files> ← Revert mocks │
|
|
93
221
|
│ 12. Generate UAT fixes patch │
|
|
94
222
|
│ 13. git stash pop (if pre-existing) ← Restore user work │
|
|
95
223
|
└─────────────────────────────────────────────────────────────┘
|
|
@@ -97,7 +225,7 @@ Fixes must be clean commits (no mock code). But after fixing, we need mocks back
|
|
|
97
225
|
|
|
98
226
|
**Stash naming convention:**
|
|
99
227
|
- `pre-verify-work` — User's original uncommitted work
|
|
100
|
-
- `mocks-batch-N` — Current mock state for batch N
|
|
228
|
+
- `mocks-batch-N` — Current mock state for batch N (stashed only during fix application)
|
|
101
229
|
|
|
102
230
|
</git_stash_lifecycle>
|
|
103
231
|
|
|
@@ -121,222 +249,3 @@ git add <conflicted-file>
|
|
|
121
249
|
**This is rare.** Mocks typically live in data layer, fixes often in UI layer.
|
|
122
250
|
|
|
123
251
|
</conflict_resolution>
|
|
124
|
-
|
|
125
|
-
<flutter_example>
|
|
126
|
-
|
|
127
|
-
**Override file: `lib/test_overrides.dart`**
|
|
128
|
-
|
|
129
|
-
```dart
|
|
130
|
-
// Test Overrides - DELETE THIS FILE BEFORE COMMITTING
|
|
131
|
-
// Used for manual UAT testing only
|
|
132
|
-
|
|
133
|
-
class TestOverrides {
|
|
134
|
-
// === STATE FLAGS ===
|
|
135
|
-
static bool forcePremiumUser = false;
|
|
136
|
-
static bool forceErrorState = false;
|
|
137
|
-
static bool forceEmptyResponse = false;
|
|
138
|
-
static bool forceLoadingState = false;
|
|
139
|
-
static bool forceTransientState = false;
|
|
140
|
-
|
|
141
|
-
// === MOCK DATA ===
|
|
142
|
-
static String mockErrorMessage = 'Simulated error for testing';
|
|
143
|
-
static Duration mockLoadingDelay = const Duration(seconds: 3);
|
|
144
|
-
static Duration mockTransientDelay = const Duration(seconds: 5);
|
|
145
|
-
|
|
146
|
-
static Map<String, dynamic> mockPremiumUser = {
|
|
147
|
-
'id': 'test-user-001',
|
|
148
|
-
'name': 'Test Premium User',
|
|
149
|
-
'isPremium': true,
|
|
150
|
-
'subscriptionTier': 'gold',
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
// === RESET ===
|
|
154
|
-
static void reset() {
|
|
155
|
-
forcePremiumUser = false;
|
|
156
|
-
forceErrorState = false;
|
|
157
|
-
forceEmptyResponse = false;
|
|
158
|
-
forceLoadingState = false;
|
|
159
|
-
forceTransientState = false;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
**Production hook: `lib/services/user_service.dart`**
|
|
165
|
-
|
|
166
|
-
```dart
|
|
167
|
-
import '../test_overrides.dart';
|
|
168
|
-
|
|
169
|
-
class UserService {
|
|
170
|
-
Future<User> getCurrentUser() async {
|
|
171
|
-
// TEST OVERRIDE - Remove before commit
|
|
172
|
-
if (TestOverrides.forcePremiumUser) {
|
|
173
|
-
return User.fromJson(TestOverrides.mockPremiumUser);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Real implementation
|
|
177
|
-
final response = await _api.get('/user/me');
|
|
178
|
-
return User.fromJson(response.data);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
Future<List<Item>> getItems() async {
|
|
182
|
-
// TEST OVERRIDE - Remove before commit
|
|
183
|
-
if (TestOverrides.forceEmptyResponse) {
|
|
184
|
-
return [];
|
|
185
|
-
}
|
|
186
|
-
if (TestOverrides.forceErrorState) {
|
|
187
|
-
throw Exception(TestOverrides.mockErrorMessage);
|
|
188
|
-
}
|
|
189
|
-
// TEST OVERRIDE - Extend transient state (loading skeleton stays visible)
|
|
190
|
-
if (TestOverrides.forceTransientState) {
|
|
191
|
-
await Future.delayed(TestOverrides.mockTransientDelay);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Real implementation
|
|
195
|
-
final response = await _api.get('/items');
|
|
196
|
-
return (response.data as List).map((j) => Item.fromJson(j)).toList();
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Toggle instructions:**
|
|
202
|
-
|
|
203
|
-
```
|
|
204
|
-
To enable Premium User state:
|
|
205
|
-
1. Open lib/test_overrides.dart
|
|
206
|
-
2. Set TestOverrides.forcePremiumUser = true
|
|
207
|
-
3. Hot reload (r in terminal)
|
|
208
|
-
4. Verify: User profile shows "Premium" badge
|
|
209
|
-
|
|
210
|
-
To enable Error State:
|
|
211
|
-
1. Open lib/test_overrides.dart
|
|
212
|
-
2. Set TestOverrides.forceErrorState = true
|
|
213
|
-
3. Hot reload (r in terminal)
|
|
214
|
-
4. Verify: Error message appears on relevant screens
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
</flutter_example>
|
|
218
|
-
|
|
219
|
-
<react_example>
|
|
220
|
-
|
|
221
|
-
**Override file: `src/testOverrides.ts`**
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
// Test Overrides - DELETE THIS FILE BEFORE COMMITTING
|
|
225
|
-
// Used for manual UAT testing only
|
|
226
|
-
|
|
227
|
-
export const testOverrides = {
|
|
228
|
-
// === STATE FLAGS ===
|
|
229
|
-
forcePremiumUser: false,
|
|
230
|
-
forceErrorState: false,
|
|
231
|
-
forceEmptyResponse: false,
|
|
232
|
-
forceLoadingState: false,
|
|
233
|
-
|
|
234
|
-
// === MOCK DATA ===
|
|
235
|
-
mockErrorMessage: 'Simulated error for testing',
|
|
236
|
-
mockLoadingDelayMs: 3000,
|
|
237
|
-
|
|
238
|
-
mockPremiumUser: {
|
|
239
|
-
id: 'test-user-001',
|
|
240
|
-
name: 'Test Premium User',
|
|
241
|
-
isPremium: true,
|
|
242
|
-
subscriptionTier: 'gold',
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
// === RESET ===
|
|
246
|
-
reset() {
|
|
247
|
-
this.forcePremiumUser = false;
|
|
248
|
-
this.forceErrorState = false;
|
|
249
|
-
this.forceEmptyResponse = false;
|
|
250
|
-
this.forceLoadingState = false;
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
**Production hook: `src/services/userService.ts`**
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
import { testOverrides } from '../testOverrides';
|
|
259
|
-
|
|
260
|
-
export async function getCurrentUser(): Promise<User> {
|
|
261
|
-
// TEST OVERRIDE - Remove before commit
|
|
262
|
-
if (testOverrides.forcePremiumUser) {
|
|
263
|
-
return testOverrides.mockPremiumUser as User;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Real implementation
|
|
267
|
-
const response = await fetch('/api/user/me');
|
|
268
|
-
return response.json();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export async function getItems(): Promise<Item[]> {
|
|
272
|
-
// TEST OVERRIDE - Remove before commit
|
|
273
|
-
if (testOverrides.forceEmptyResponse) {
|
|
274
|
-
return [];
|
|
275
|
-
}
|
|
276
|
-
if (testOverrides.forceErrorState) {
|
|
277
|
-
throw new Error(testOverrides.mockErrorMessage);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Real implementation
|
|
281
|
-
const response = await fetch('/api/items');
|
|
282
|
-
return response.json();
|
|
283
|
-
}
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
**Toggle instructions:**
|
|
287
|
-
|
|
288
|
-
```
|
|
289
|
-
To enable Premium User state:
|
|
290
|
-
1. Open src/testOverrides.ts
|
|
291
|
-
2. Set forcePremiumUser: true
|
|
292
|
-
3. Save file (auto hot reload in dev mode)
|
|
293
|
-
4. Verify: User profile shows "Premium" badge
|
|
294
|
-
|
|
295
|
-
To enable Error State:
|
|
296
|
-
1. Open src/testOverrides.ts
|
|
297
|
-
2. Set forceErrorState: true
|
|
298
|
-
3. Save file (auto hot reload)
|
|
299
|
-
4. Verify: Error message appears on relevant screens
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
</react_example>
|
|
303
|
-
|
|
304
|
-
<best_practices>
|
|
305
|
-
|
|
306
|
-
**Do:**
|
|
307
|
-
- Keep all flags in one file
|
|
308
|
-
- Use descriptive flag names (`forcePremiumUser` not `flag1`)
|
|
309
|
-
- Add comments marking test-only code
|
|
310
|
-
- Provide reset function
|
|
311
|
-
- Document toggle instructions clearly
|
|
312
|
-
|
|
313
|
-
**Don't:**
|
|
314
|
-
- Create complex mock infrastructure
|
|
315
|
-
- Add mocks in UI components (use service layer)
|
|
316
|
-
- Commit mock code (ever)
|
|
317
|
-
- Create multiple override files
|
|
318
|
-
- Add conditional compilation / build flags
|
|
319
|
-
|
|
320
|
-
**Signs you're over-engineering:**
|
|
321
|
-
- More than one override file
|
|
322
|
-
- Mock code in more than 3 production files
|
|
323
|
-
- Complex mock data generators
|
|
324
|
-
- Mocking at multiple layers simultaneously
|
|
325
|
-
|
|
326
|
-
</best_practices>
|
|
327
|
-
|
|
328
|
-
<cleanup>
|
|
329
|
-
|
|
330
|
-
**After UAT complete:**
|
|
331
|
-
|
|
332
|
-
1. `git stash drop` — Removes mock stash permanently
|
|
333
|
-
2. Delete override file if still present
|
|
334
|
-
3. Remove any imports/hooks still in production code
|
|
335
|
-
|
|
336
|
-
**Verification:**
|
|
337
|
-
```bash
|
|
338
|
-
git status # Should show no mock-related files
|
|
339
|
-
grep -r "testOverrides" src/ # Should find nothing (or only the override file itself)
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
</cleanup>
|