@musashishao/agent-kit 1.7.0 → 1.8.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.
Files changed (39) hide show
  1. package/.agent/rules/CODEX.md +8 -7
  2. package/.agent/rules/CODE_RULES.md +15 -0
  3. package/.agent/rules/REFERENCE.md +7 -2
  4. package/.agent/skills/brainstorming/SKILL.md +52 -0
  5. package/.agent/skills/frontend-design/SKILL.md +30 -0
  6. package/.agent/skills/git-worktrees/SKILL.md +181 -0
  7. package/.agent/skills/parallel-agents/SKILL.md +89 -0
  8. package/.agent/skills/react-patterns/SKILL.md +31 -0
  9. package/.agent/skills/react-patterns/bundle-patterns.md +129 -0
  10. package/.agent/skills/react-patterns/rerender-patterns.md +163 -0
  11. package/.agent/skills/react-patterns/server-patterns.md +146 -0
  12. package/.agent/skills/react-patterns/waterfall-patterns.md +102 -0
  13. package/.agent/skills/reader-testing/SKILL.md +183 -0
  14. package/.agent/skills/verification-gate/SKILL.md +129 -0
  15. package/.agent/skills/web-interface-guidelines/SKILL.md +94 -0
  16. package/.agent/skills/web-interface-guidelines/animation.md +153 -0
  17. package/.agent/skills/web-interface-guidelines/anti-patterns.md +204 -0
  18. package/.agent/skills/web-interface-guidelines/focus-states.md +104 -0
  19. package/.agent/skills/web-interface-guidelines/forms.md +154 -0
  20. package/.agent/skills/web-interface-guidelines/touch-interaction.md +150 -0
  21. package/.agent/workflows/autofix.md +1 -1
  22. package/.agent/workflows/brainstorm.md +1 -1
  23. package/.agent/workflows/context.md +1 -1
  24. package/.agent/workflows/create.md +1 -1
  25. package/.agent/workflows/dashboard.md +1 -1
  26. package/.agent/workflows/debug.md +1 -1
  27. package/.agent/workflows/deploy.md +1 -1
  28. package/.agent/workflows/enhance.md +1 -1
  29. package/.agent/workflows/next.md +1 -1
  30. package/.agent/workflows/orchestrate.md +1 -1
  31. package/.agent/workflows/plan.md +1 -1
  32. package/.agent/workflows/preview.md +1 -1
  33. package/.agent/workflows/quality.md +1 -1
  34. package/.agent/workflows/spec.md +1 -1
  35. package/.agent/workflows/status.md +1 -1
  36. package/.agent/workflows/test.md +1 -1
  37. package/.agent/workflows/ui-ux-pro-max.md +1 -1
  38. package/README.md +3 -3
  39. package/package.json +1 -1
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: web-interface-guidelines
3
+ description: Web Interface Guidelines audit for accessibility, forms, touch, animation, and anti-patterns. Use when reviewing UI code, checking accessibility, or auditing design. Based on Vercel's 100+ rules.
4
+ allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5
+ ---
6
+
7
+ # Web Interface Guidelines
8
+
9
+ > Audit UI code for compliance with modern web interface best practices.
10
+ > Based on [Vercel Web Interface Guidelines](https://github.com/vercel-labs/web-interface-guidelines).
11
+
12
+ ---
13
+
14
+ ## 🎯 When to Apply
15
+
16
+ | Trigger Phrase | Action |
17
+ |----------------|--------|
18
+ | "Review my UI" | Full audit |
19
+ | "Check accessibility" | Focus, forms, aria |
20
+ | "Audit design" | All categories |
21
+ | "Check my site" | Anti-patterns scan |
22
+
23
+ ---
24
+
25
+ ## 📚 Modular Files
26
+
27
+ Read ONLY the sections relevant to your task:
28
+
29
+ | File | Categories |
30
+ |------|-----------|
31
+ | [forms.md](forms.md) | Input, autocomplete, validation |
32
+ | [focus-states.md](focus-states.md) | Focus, keyboard navigation |
33
+ | [touch-interaction.md](touch-interaction.md) | Mobile, touch, safe areas |
34
+ | [animation.md](animation.md) | Motion, transitions |
35
+ | [anti-patterns.md](anti-patterns.md) | ❌ What NOT to do |
36
+
37
+ ---
38
+
39
+ ## Quick Reference
40
+
41
+ ### Accessibility (A11y)
42
+
43
+ | Rule | Check |
44
+ |------|-------|
45
+ | Visible focus | `focus-visible:ring-*` present |
46
+ | No outline:none | Unless replacement exists |
47
+ | Button for actions | Not `<div onClick>` |
48
+ | Labels on inputs | `<label>` or `aria-label` |
49
+ | Icon buttons | Has `aria-label` |
50
+
51
+ ### Forms
52
+
53
+ | Rule | Check |
54
+ |------|-------|
55
+ | autocomplete | Present on inputs |
56
+ | Correct type | `email`, `tel`, `url` |
57
+ | No paste block | Never `onPaste preventDefault` |
58
+ | Error placement | Inline next to field |
59
+
60
+ ### Animation
61
+
62
+ | Rule | Check |
63
+ |------|-------|
64
+ | Reduced motion | `prefers-reduced-motion` honored |
65
+ | Compositor only | `transform`, `opacity` only |
66
+ | No `transition: all` | List properties explicitly |
67
+
68
+ ### Touch & Mobile
69
+
70
+ | Rule | Check |
71
+ |------|-------|
72
+ | Touch action | `touch-action: manipulation` |
73
+ | Safe areas | `env(safe-area-inset-*)` |
74
+ | Scroll contain | `overscroll-behavior: contain` in modals |
75
+
76
+ ---
77
+
78
+ ## Output Format
79
+
80
+ When auditing, output findings in this format:
81
+
82
+ ```
83
+ filename:line - [CATEGORY] Description of issue
84
+ ```
85
+
86
+ Example:
87
+ ```
88
+ components/Button.tsx:15 - [FOCUS] Missing focus-visible ring
89
+ pages/login.tsx:42 - [FORMS] Input missing autocomplete attribute
90
+ ```
91
+
92
+ ---
93
+
94
+ > **Remember:** Run anti-patterns check first for quick wins.
@@ -0,0 +1,153 @@
1
+ # Animation Guidelines
2
+
3
+ > Respect user preferences. Animate only what's necessary.
4
+
5
+ ---
6
+
7
+ ## Reduced Motion
8
+
9
+ **Honor `prefers-reduced-motion`.**
10
+
11
+ ```css
12
+ /* ✅ Default animation */
13
+ .card {
14
+ transition: transform 200ms ease;
15
+ }
16
+
17
+ /* ✅ Reduce or disable for preference */
18
+ @media (prefers-reduced-motion: reduce) {
19
+ .card {
20
+ transition: none;
21
+ }
22
+ }
23
+ ```
24
+
25
+ In Tailwind:
26
+ ```html
27
+ <div class="motion-safe:animate-bounce motion-reduce:animate-none">
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Compositor-Friendly Properties
33
+
34
+ **Animate only `transform` and `opacity`.**
35
+
36
+ | ✅ Animate | ❌ Avoid |
37
+ |-----------|---------|
38
+ | `transform` | `width`, `height` |
39
+ | `opacity` | `top`, `left` |
40
+ | `filter` | `margin`, `padding` |
41
+ | | `border-width` |
42
+
43
+ ```css
44
+ /* ✅ GOOD: GPU-accelerated */
45
+ .card:hover {
46
+ transform: translateY(-4px);
47
+ opacity: 0.9;
48
+ }
49
+
50
+ /* ❌ BAD: Triggers layout */
51
+ .card:hover {
52
+ margin-top: -4px;
53
+ height: 104px;
54
+ }
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Explicit Transitions
60
+
61
+ **Never use `transition: all`.**
62
+
63
+ ```css
64
+ /* ❌ BAD: Animates everything */
65
+ button {
66
+ transition: all 200ms;
67
+ }
68
+
69
+ /* ✅ GOOD: Explicit properties */
70
+ button {
71
+ transition: background-color 200ms, transform 150ms;
72
+ }
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Transform Origin
78
+
79
+ **Set correct origin for expected behavior.**
80
+
81
+ ```css
82
+ /* ✅ Scale from center (default) */
83
+ .modal {
84
+ transform-origin: center;
85
+ }
86
+
87
+ /* ✅ Dropdown from top */
88
+ .dropdown {
89
+ transform-origin: top;
90
+ }
91
+
92
+ /* ✅ Menu from corner */
93
+ .context-menu {
94
+ transform-origin: top left;
95
+ }
96
+ ```
97
+
98
+ ---
99
+
100
+ ## SVG Animation
101
+
102
+ **Animate wrapper div, not SVG element.**
103
+
104
+ ```tsx
105
+ // ✅ GOOD: Animate wrapper
106
+ <div className="animate-spin">
107
+ <SpinnerSVG />
108
+ </div>
109
+
110
+ // ❌ BAD: Animate SVG directly (inconsistent behavior)
111
+ <SpinnerSVG className="animate-spin" />
112
+ ```
113
+
114
+ For SVG transforms:
115
+ ```css
116
+ .svg-icon {
117
+ transform-box: fill-box;
118
+ transform-origin: center;
119
+ }
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Interruptible Animations
125
+
126
+ **Animations should respond to user input.**
127
+
128
+ ```css
129
+ /* ✅ Allow interruption */
130
+ .drawer {
131
+ transition: transform 300ms ease-out;
132
+ will-change: transform;
133
+ }
134
+
135
+ /* User can swipe to close mid-animation */
136
+ ```
137
+
138
+ Avoid:
139
+ - Long animations (>500ms) without skip
140
+ - Animations that block interaction
141
+ - Auto-play that can't be paused
142
+
143
+ ---
144
+
145
+ ## Quick Checklist
146
+
147
+ | Check | Pass |
148
+ |-------|------|
149
+ | `prefers-reduced-motion` respected? | |
150
+ | Only `transform`/`opacity` animated? | |
151
+ | No `transition: all`? | |
152
+ | Correct `transform-origin`? | |
153
+ | SVG wrapped for animation? | |
@@ -0,0 +1,204 @@
1
+ # Anti-Patterns (FLAG THESE)
2
+
3
+ > Explicit list of violations to flag during UI audits.
4
+
5
+ ---
6
+
7
+ ## ❌ Accessibility Violations
8
+
9
+ ### Zoom Blocking
10
+ ```html
11
+ <!-- ❌ FLAG: Disables zoom -->
12
+ <meta name="viewport" content="user-scalable=no">
13
+ <meta name="viewport" content="maximum-scale=1">
14
+
15
+ <!-- ✅ CORRECT -->
16
+ <meta name="viewport" content="width=device-width, initial-scale=1">
17
+ ```
18
+
19
+ ### Outline Removal Without Replacement
20
+ ```css
21
+ /* ❌ FLAG */
22
+ button:focus {
23
+ outline: none;
24
+ }
25
+
26
+ /* ✅ CORRECT */
27
+ button:focus-visible {
28
+ outline: 2px solid var(--focus);
29
+ }
30
+ ```
31
+
32
+ ### Missing Labels
33
+ ```tsx
34
+ // ❌ FLAG: Input without label
35
+ <input type="email" />
36
+
37
+ // ❌ FLAG: Icon button without aria-label
38
+ <button><IconMenu /></button>
39
+
40
+ // ✅ CORRECT
41
+ <label htmlFor="email">Email</label>
42
+ <input id="email" type="email" />
43
+
44
+ <button aria-label="Open menu"><IconMenu /></button>
45
+ ```
46
+
47
+ ---
48
+
49
+ ## ❌ Semantic Violations
50
+
51
+ ### Wrong Element for Interaction
52
+ ```tsx
53
+ // ❌ FLAG: Div with click handler
54
+ <div onClick={handleClick}>Click me</div>
55
+ <span onClick={handleClick}>Action</span>
56
+
57
+ // ✅ CORRECT
58
+ <button onClick={handleClick}>Click me</button>
59
+ ```
60
+
61
+ ### Inline Navigation Without Link
62
+ ```tsx
63
+ // ❌ FLAG: onClick navigation
64
+ <button onClick={() => router.push('/dashboard')}>
65
+ Dashboard
66
+ </button>
67
+
68
+ // ✅ CORRECT
69
+ <Link href="/dashboard">Dashboard</Link>
70
+ ```
71
+
72
+ ---
73
+
74
+ ## ❌ Form Violations
75
+
76
+ ### Paste Blocking
77
+ ```tsx
78
+ // ❌ FLAG: Blocks paste
79
+ <input onPaste={e => e.preventDefault()} />
80
+ <input onPaste={() => false} />
81
+
82
+ // ✅ CORRECT: Allow paste always
83
+ <input type="password" />
84
+ ```
85
+
86
+ ### Missing Autocomplete
87
+ ```tsx
88
+ // ❌ FLAG: No autocomplete on auth fields
89
+ <input type="email" name="email" />
90
+
91
+ // ✅ CORRECT
92
+ <input type="email" name="email" autoComplete="email" />
93
+ ```
94
+
95
+ ---
96
+
97
+ ## ❌ Animation Violations
98
+
99
+ ### Transition All
100
+ ```css
101
+ /* ❌ FLAG */
102
+ .button {
103
+ transition: all 200ms;
104
+ }
105
+
106
+ /* ✅ CORRECT */
107
+ .button {
108
+ transition: background-color 200ms, transform 150ms;
109
+ }
110
+ ```
111
+
112
+ ### Layout Property Animation
113
+ ```css
114
+ /* ❌ FLAG: Animates layout properties */
115
+ .card {
116
+ transition: width 200ms, height 200ms, margin 200ms;
117
+ }
118
+
119
+ /* ✅ CORRECT: Transform only */
120
+ .card {
121
+ transition: transform 200ms;
122
+ }
123
+ ```
124
+
125
+ ---
126
+
127
+ ## ❌ Performance Violations
128
+
129
+ ### Large List Without Virtualization
130
+ ```tsx
131
+ // ❌ FLAG: 50+ items without virtualization
132
+ {items.map(item => <Item key={item.id} {...item} />)}
133
+ // items.length > 50
134
+
135
+ // ✅ CORRECT: Use virtualization
136
+ import { Virtualizer } from '@tanstack/virtual-core';
137
+ ```
138
+
139
+ ### Images Without Dimensions
140
+ ```tsx
141
+ // ❌ FLAG: No width/height
142
+ <img src="/photo.jpg" />
143
+
144
+ // ✅ CORRECT
145
+ <img src="/photo.jpg" width={800} height={600} alt="Description" />
146
+ ```
147
+
148
+ ### Hardcoded Date/Number Formats
149
+ ```tsx
150
+ // ❌ FLAG
151
+ const date = `${d.getMonth()}/${d.getDate()}/${d.getFullYear()}`;
152
+ const price = `$${amount.toFixed(2)}`;
153
+
154
+ // ✅ CORRECT
155
+ const date = new Intl.DateTimeFormat('en-US').format(d);
156
+ const price = new Intl.NumberFormat('en-US', {
157
+ style: 'currency',
158
+ currency: 'USD'
159
+ }).format(amount);
160
+ ```
161
+
162
+ ---
163
+
164
+ ## ❌ Mobile Violations
165
+
166
+ ### AutoFocus on Mobile
167
+ ```tsx
168
+ // ❌ FLAG: AutoFocus without mobile check
169
+ <input autoFocus />
170
+
171
+ // ✅ CORRECT
172
+ <input autoFocus={!isMobile} />
173
+ ```
174
+
175
+ ### Missing Safe Areas
176
+ ```css
177
+ /* ❌ FLAG: Full-bleed without safe areas */
178
+ .full-width {
179
+ padding: 0;
180
+ }
181
+
182
+ /* ✅ CORRECT */
183
+ .full-width {
184
+ padding-left: env(safe-area-inset-left);
185
+ padding-right: env(safe-area-inset-right);
186
+ }
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Audit Checklist
192
+
193
+ | Category | Check | Severity |
194
+ |----------|-------|----------|
195
+ | Zoom | No `user-scalable=no` | 🔴 Critical |
196
+ | Focus | Visible focus states | 🔴 Critical |
197
+ | Labels | All inputs labeled | 🔴 Critical |
198
+ | Semantics | `<button>` for actions | 🟠 High |
199
+ | Links | `<Link>` for navigation | 🟠 High |
200
+ | Paste | Never blocked | 🟠 High |
201
+ | Transition | No `transition: all` | 🟡 Medium |
202
+ | Images | Has dimensions | 🟡 Medium |
203
+ | Lists | Virtualized if 50+ | 🟡 Medium |
204
+ | Dates | Uses `Intl.*` | 🟢 Low |
@@ -0,0 +1,104 @@
1
+ # Focus States Guidelines
2
+
3
+ > Keyboard users rely on visible focus. Never hide it without replacement.
4
+
5
+ ---
6
+
7
+ ## Visible Focus
8
+
9
+ **Interactive elements need visible focus.**
10
+
11
+ ```css
12
+ /* ✅ Focus-visible (keyboard only) */
13
+ button:focus-visible {
14
+ outline: 2px solid var(--focus-ring);
15
+ outline-offset: 2px;
16
+ }
17
+
18
+ /* ❌ Never do this without replacement */
19
+ button:focus {
20
+ outline: none;
21
+ }
22
+ ```
23
+
24
+ | Tailwind | CSS |
25
+ |----------|-----|
26
+ | `focus-visible:ring-2` | `outline: 2px solid` |
27
+ | `focus-visible:ring-offset-2` | `outline-offset: 2px` |
28
+ | `focus-visible:ring-blue-500` | Custom color |
29
+
30
+ ---
31
+
32
+ ## Focus-Visible vs Focus
33
+
34
+ **Use `:focus-visible` over `:focus`.**
35
+
36
+ | Selector | When Applied |
37
+ |----------|--------------|
38
+ | `:focus` | Always on focus (keyboard + click) |
39
+ | `:focus-visible` | Only on keyboard focus |
40
+
41
+ ```css
42
+ /* ✅ Only shows ring on keyboard navigation */
43
+ button:focus-visible {
44
+ ring: 2px;
45
+ }
46
+
47
+ /* ❌ Shows ring on every click too */
48
+ button:focus {
49
+ ring: 2px;
50
+ }
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Focus-Within
56
+
57
+ **Group focus with `:focus-within` for compound controls.**
58
+
59
+ ```css
60
+ /* ✅ Highlight container when any child is focused */
61
+ .search-box:focus-within {
62
+ border-color: var(--focus);
63
+ box-shadow: 0 0 0 3px var(--focus-ring);
64
+ }
65
+ ```
66
+
67
+ Use cases:
68
+ - Search box with button
69
+ - Input groups
70
+ - Custom selects
71
+ - Dropdown menus
72
+
73
+ ---
74
+
75
+ ## Tab Order
76
+
77
+ | Rule | Check |
78
+ |------|-------|
79
+ | Logical order | Tab follows visual layout |
80
+ | No positive tabindex | Use `tabindex="0"` or `-1` only |
81
+ | Skip links | Provide "Skip to content" |
82
+ | Focus trapping | Modal keeps focus inside |
83
+
84
+ ```tsx
85
+ // ✅ Focusable div (rare cases)
86
+ <div tabIndex={0} role="button" onKeyDown={handleKey}>
87
+ Custom control
88
+ </div>
89
+
90
+ // ❌ Avoid
91
+ <div tabIndex={5}> // Breaks natural order
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Quick Audit
97
+
98
+ | Check | Pass/Fail |
99
+ |-------|-----------|
100
+ | Can tab through all interactive elements? | |
101
+ | Focus ring visible on each? | |
102
+ | No orphaned focus (hidden elements)? | |
103
+ | Modal traps focus? | |
104
+ | Escape closes modal? | |
@@ -0,0 +1,154 @@
1
+ # Forms Guidelines
2
+
3
+ > Form inputs are critical for user experience and security.
4
+
5
+ ---
6
+
7
+ ## Autocomplete
8
+
9
+ **Inputs need `autocomplete` and meaningful `name`.**
10
+
11
+ ```tsx
12
+ // ✅ GOOD
13
+ <input
14
+ type="email"
15
+ name="email"
16
+ autoComplete="email"
17
+ />
18
+
19
+ // ❌ BAD
20
+ <input type="text" /> // No type, no autocomplete
21
+ ```
22
+
23
+ | Field | autocomplete Value |
24
+ |-------|-------------------|
25
+ | Email | `email` |
26
+ | Password | `current-password` or `new-password` |
27
+ | Name | `name` |
28
+ | Phone | `tel` |
29
+ | Address | `street-address` |
30
+ | Credit Card | `cc-number` |
31
+
32
+ ---
33
+
34
+ ## Input Types
35
+
36
+ **Use correct `type` and `inputmode`.**
37
+
38
+ | Data | type | inputmode |
39
+ |------|------|-----------|
40
+ | Email | `email` | `email` |
41
+ | Phone | `tel` | `tel` |
42
+ | URL | `url` | `url` |
43
+ | Number | `number` | `numeric` |
44
+ | Search | `search` | `search` |
45
+ | OTP/Code | `text` | `numeric` |
46
+
47
+ ---
48
+
49
+ ## Never Block Paste
50
+
51
+ ```tsx
52
+ // ❌ NEVER DO THIS
53
+ <input
54
+ onPaste={e => e.preventDefault()} // Blocks password managers!
55
+ />
56
+
57
+ // ✅ Always allow paste
58
+ <input type="password" />
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Labels
64
+
65
+ **Labels must be clickable.**
66
+
67
+ ```tsx
68
+ // ✅ Using htmlFor
69
+ <label htmlFor="email">Email</label>
70
+ <input id="email" />
71
+
72
+ // ✅ Wrapping
73
+ <label>
74
+ Email
75
+ <input />
76
+ </label>
77
+
78
+ // ❌ No association
79
+ <span>Email</span>
80
+ <input />
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Error Handling
86
+
87
+ | Rule | Implementation |
88
+ |------|----------------|
89
+ | Inline errors | Next to field, not just top of form |
90
+ | Focus first error | On submit, focus the first invalid field |
91
+ | Clear on fix | Remove error when user starts typing |
92
+ | Specific messages | "Email is invalid" not "Error" |
93
+
94
+ ```tsx
95
+ // ✅ Inline error
96
+ <input aria-invalid={!!error} aria-describedby="email-error" />
97
+ {error && <span id="email-error">{error}</span>}
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Submit Button
103
+
104
+ | State | Button |
105
+ |-------|--------|
106
+ | Idle | Enabled, shows action |
107
+ | Submitting | Shows spinner, may disable |
108
+ | Error | Returns to idle |
109
+ | Success | Shows confirmation |
110
+
111
+ ```tsx
112
+ <button disabled={isSubmitting}>
113
+ {isSubmitting ? <Spinner /> : 'Submit'}
114
+ </button>
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Spellcheck
120
+
121
+ **Disable on non-prose fields.**
122
+
123
+ ```tsx
124
+ <input
125
+ type="email"
126
+ spellCheck={false} // ✅ No squiggly lines on emails
127
+ autoComplete="off" // ✅ No password manager on non-auth
128
+ />
129
+ ```
130
+
131
+ | Disable spellcheck | Keep spellcheck |
132
+ |-------------------|-----------------|
133
+ | Email, username | Comments, bio |
134
+ | Codes, tokens | Messages |
135
+ | URLs | Search queries |
136
+
137
+ ---
138
+
139
+ ## Unsaved Changes Warning
140
+
141
+ **Warn before navigation with unsaved changes.**
142
+
143
+ ```tsx
144
+ useEffect(() => {
145
+ const handleBeforeUnload = (e: BeforeUnloadEvent) => {
146
+ if (isDirty) {
147
+ e.preventDefault();
148
+ e.returnValue = '';
149
+ }
150
+ };
151
+ window.addEventListener('beforeunload', handleBeforeUnload);
152
+ return () => window.removeEventListener('beforeunload', handleBeforeUnload);
153
+ }, [isDirty]);
154
+ ```