wdyt 0.1.16 → 0.1.17

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
@@ -2,24 +2,104 @@
2
2
 
3
3
  Code review context builder for LLMs - get a second opinion on your code.
4
4
 
5
- A CLI tool that exports code context for AI review, compatible with flowctl/flow-next.
5
+ A CLI tool that exports code context for AI review, with adaptive review strategies that automatically select the best approach for each task.
6
+
7
+ ## What is wdyt?
8
+
9
+ wdyt is a drop-in replacement for rp-cli (RepoPrompt) that provides:
10
+
11
+ - **Adaptive review strategies** - Automatically selects single-pass, multi-pass, or exploration based on task characteristics
12
+ - **Smart context building** - Code maps for large files, full content for changed files
13
+ - **Token budget management** - Stays within Claude's context limits
14
+ - **Confidence scoring** - Filters findings to 80%+ confidence to reduce false positives
15
+ - **flowctl compatibility** - 100% interface compatibility with rp-cli
6
16
 
7
17
  ## Installation
8
18
 
9
19
  ```bash
10
- # Run directly with bunx (recommended)
11
- bunx wdyt init
12
-
13
- # Or install globally
20
+ # Install globally (provides both wdyt and rp-cli commands)
14
21
  bun add -g wdyt
22
+
23
+ # Or run directly with bunx
24
+ bunx wdyt -e 'windows'
15
25
  ```
16
26
 
27
+ ## How it Differs from RepoPrompt
28
+
29
+ | Aspect | rp-cli (RepoPrompt) | wdyt |
30
+ |--------|---------------------|------|
31
+ | **Philosophy** | Pack everything | Smart selection |
32
+ | **File handling** | All files = full content | Changed = full, imports = code maps |
33
+ | **Context limit** | Hard fail at ~120k tokens | Adaptive strategies |
34
+ | **Review quality** | Depends on context size | Optimized for accuracy |
35
+ | **Cost** | 1 large API call | Adaptive (1-4 calls) |
36
+
37
+ ## The 3-Pronged Adaptive Approach
38
+
39
+ wdyt automatically selects the best review strategy:
40
+
41
+ ```
42
+ ┌─────────────────────────────────────────────────────────────┐
43
+ │ STRATEGY SELECTION │
44
+ ├─────────────────────────────────────────────────────────────┤
45
+ │ │
46
+ │ Small changes (≤3 files, <500 lines) │
47
+ │ ┌─────────────────────────────────────┐ │
48
+ │ │ OPTION A: Single-Pass │ │
49
+ │ │ • Spec + Guidelines + Code │ │
50
+ │ │ • 1 API call │ │
51
+ │ │ • Fast, cheap, good for most cases │ │
52
+ │ └─────────────────────────────────────┘ │
53
+ │ │
54
+ │ Large/Critical changes (>10 files OR security review) │
55
+ │ ┌─────────────────────────────────────┐ │
56
+ │ │ OPTION B: Multi-Pass │ │
57
+ │ │ • 3 parallel review agents │ │
58
+ │ │ • Confidence scoring (80+ filter) │ │
59
+ │ │ • Higher accuracy, catches more │ │
60
+ │ └─────────────────────────────────────┘ │
61
+ │ │
62
+ │ Unknown scope (audit, exploration) │
63
+ │ ┌─────────────────────────────────────┐ │
64
+ │ │ OPTION C: Agentic Exploration │ │
65
+ │ │ • Agent uses glob/grep/read tools │ │
66
+ │ │ • Discovers relevant files itself │ │
67
+ │ │ • No context limit constraints │ │
68
+ │ └─────────────────────────────────────┘ │
69
+ │ │
70
+ └─────────────────────────────────────────────────────────────┘
71
+ ```
72
+
73
+ ### When Each Strategy is Used
74
+
75
+ | Scenario | Strategy | Why |
76
+ |----------|----------|-----|
77
+ | Bug fix (1-2 files) | Single-Pass | Fast, focused |
78
+ | Feature PR (5 files) | Single-Pass | Spec + changes fit |
79
+ | Major refactor (15+ files) | Multi-Pass | Need multiple perspectives |
80
+ | Security audit | Multi-Pass | Critical, need confidence scoring |
81
+ | "Review this repo" | Exploration | Unknown scope |
82
+ | CI/CD quick check | Single-Pass | Speed matters |
83
+
84
+ ## Research-Backed Decisions
85
+
86
+ wdyt's architecture is based on research findings:
87
+
88
+ 1. **Problem descriptions boost accuracy +22%** ([arxiv 2505.20206](https://arxiv.org/abs/2505.20206))
89
+ - wdyt prioritizes task specs in context
90
+
91
+ 2. **Less context = better reviews** (Claude official code-review)
92
+ - 60 files hurts accuracy; changed files + code maps is better
93
+
94
+ 3. **Multiple perspectives catch more issues** (Claude documentation)
95
+ - Multi-pass for large changes > single pass
96
+
97
+ 4. **Confidence scoring reduces false positives** (Claude official)
98
+ - Filter to 80+ confidence only
99
+
17
100
  ## Quick Start
18
101
 
19
102
  ```bash
20
- # Interactive setup - creates data directory and optionally adds rp-cli alias
21
- bunx wdyt init
22
-
23
103
  # List windows
24
104
  wdyt -e 'windows'
25
105
 
@@ -29,21 +109,12 @@ wdyt -w 1 -e 'builder {}'
29
109
  # Add files to selection
30
110
  wdyt -w 1 -t <tab-id> -e 'select add src/cli.ts'
31
111
 
32
- # Export context for review
112
+ # Export context for review (strategy auto-selected)
33
113
  wdyt -w 1 -t <tab-id> -e 'call chat_send {"mode":"review"}'
34
114
  ```
35
115
 
36
116
  ## Commands
37
117
 
38
- ### Setup
39
-
40
- ```bash
41
- wdyt init # Interactive setup
42
- wdyt init --global # Install binary globally
43
- wdyt init --rp-alias # Create rp-cli alias (for flowctl)
44
- wdyt init --no-alias # Skip rp-cli alias prompt
45
- ```
46
-
47
118
  ### Expressions
48
119
 
49
120
  | Expression | Description |
@@ -67,16 +138,69 @@ wdyt init --no-alias # Skip rp-cli alias prompt
67
138
 
68
139
  ## flowctl Compatibility
69
140
 
70
- This tool is compatible with [flow-next](https://github.com/gmickel/claude-marketplace) and provides the `rp-cli` interface expected by flowctl.
141
+ wdyt is a 100% drop-in replacement for rp-cli. No flowctl changes needed.
71
142
 
72
- ```bash
73
- # Create the rp-cli alias during init
74
- bunx wdyt init --rp-alias
143
+ ```
144
+ flowctl calls:
145
+ rp-cli -w <window> -t <tab> -e "call chat_send {json}"
146
+
147
+ wdyt accepts same call:
148
+ wdyt -w <window> -t <tab> -e "call chat_send {json}"
149
+ ```
150
+
151
+ The package.json includes both `wdyt` and `rp-cli` bin entries, so installing wdyt globally provides the rp-cli command automatically.
152
+
153
+ ### Payload Format (unchanged)
154
+
155
+ ```json
156
+ {
157
+ "message": "Review this code",
158
+ "mode": "chat",
159
+ "new_chat": true,
160
+ "chat_name": "fn-5-review",
161
+ "selected_paths": ["src/file1.ts", "src/file2.ts"]
162
+ }
163
+ ```
164
+
165
+ ### Output Format (unchanged)
166
+
167
+ ```
168
+ Chat: `<uuid>`
169
+
170
+ <review text>
171
+
172
+ <verdict>SHIP|NEEDS_WORK|MAJOR_RETHINK</verdict>
173
+ ```
174
+
175
+ ## Architecture
176
+
177
+ ```
178
+ src/
179
+ ├── cli.ts # CLI entry point
180
+ ├── commands/
181
+ │ ├── chat.ts # chat_send command (main review logic)
182
+ │ ├── builder.ts # Tab creation
183
+ │ ├── prompt.ts # Prompt management
184
+ │ ├── select.ts # File selection
185
+ │ └── windows.ts # Window listing
186
+ ├── context/
187
+ │ ├── strategy.ts # Adaptive strategy selection
188
+ │ ├── builder.ts # Context XML building
189
+ │ ├── codemap.ts # Code map extraction (signatures only)
190
+ │ ├── multipass.ts # Multi-pass review handler
191
+ │ ├── exploration.ts # Agentic exploration handler
192
+ │ └── index.ts # Exports
193
+ └── state/
194
+ └── index.ts # Window/tab state management
195
+
196
+ skills/
197
+ └── quality-auditor.md # Review prompt with chain-of-thought
75
198
  ```
76
199
 
77
200
  ## Requirements
78
201
 
79
202
  - [Bun](https://bun.sh) runtime
203
+ - [Claude CLI](https://www.anthropic.com/claude) (for actual reviews)
80
204
 
81
205
  ## License
82
206
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wdyt",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "type": "module",
5
5
  "description": "Code review context builder for LLMs - what do you think?",
6
6
  "license": "MIT",
@@ -47,7 +47,9 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "citty": "^0.1.6",
50
- "shell-quote": "^1.8.3"
50
+ "shell-quote": "^1.8.3",
51
+ "typescript": "^5.9.3",
52
+ "web-tree-sitter": "^0.26.3"
51
53
  },
52
54
  "devDependencies": {
53
55
  "@types/bun": "^1.1.0"
@@ -3,83 +3,118 @@ name: quality-auditor
3
3
  description: Review recent changes for correctness, simplicity, security, and test coverage.
4
4
  ---
5
5
 
6
- You are a pragmatic code auditor. Your job is to find real risks in recent changes - fast.
6
+ You are a senior engineer reviewing code changes. Your job is to find real risks - not style nitpicks.
7
7
 
8
- ## Audit Strategy
8
+ ## Review Process (Chain of Thought)
9
9
 
10
- ### 1. Quick Scan (find obvious issues fast)
10
+ Think through each step before giving findings:
11
+
12
+ ### 1. Understand Intent
13
+ - What is this change trying to accomplish?
14
+ - Is there a task spec or description provided?
15
+ - What are the acceptance criteria?
16
+
17
+ ### 2. Quick Scan (obvious issues)
11
18
  - **Secrets**: API keys, passwords, tokens in code
12
19
  - **Debug code**: console.log, debugger, TODO/FIXME
13
20
  - **Commented code**: Dead code that should be deleted
14
21
  - **Large files**: Accidentally committed binaries, logs
15
22
 
16
- ### 2. Correctness Review
23
+ ### 3. Correctness Review
17
24
  - Does the code match the stated intent?
18
25
  - Are there off-by-one errors, wrong operators, inverted conditions?
19
26
  - Do error paths actually handle errors?
20
27
  - Are promises/async properly awaited?
28
+ - Edge cases: null/undefined, empty arrays, boundary conditions
21
29
 
22
- ### 3. Security Scan
30
+ ### 4. Security Scan
23
31
  - **Injection**: SQL, XSS, command injection vectors
24
32
  - **Auth/AuthZ**: Are permissions checked? Can they be bypassed?
25
33
  - **Data exposure**: Is sensitive data logged, leaked, or over-exposed?
26
34
  - **Dependencies**: Any known vulnerable packages added?
27
35
 
28
- ### 4. Simplicity Check
36
+ ### 5. Simplicity Check
29
37
  - Could this be simpler?
30
38
  - Is there duplicated code that should be extracted?
31
39
  - Are there unnecessary abstractions?
32
40
  - Over-engineering for hypothetical future needs?
33
41
 
34
- ### 5. Test Coverage
42
+ ### 6. Test Coverage
35
43
  - Are new code paths tested?
36
44
  - Do tests actually assert behavior (not just run)?
37
- - Are edge cases from gap analysis covered?
45
+ - Are edge cases covered?
38
46
  - Are error paths tested?
39
47
 
40
- ### 6. Performance Red Flags
48
+ ### 7. Performance Red Flags
41
49
  - N+1 queries or O(n²) loops
42
50
  - Unbounded data fetching
43
51
  - Missing pagination/limits
44
52
  - Blocking operations on hot paths
45
53
 
54
+ ### 8. Confidence Check
55
+ For each issue you find, ask yourself:
56
+ - Am I confident this is a real problem (not a style preference)?
57
+ - Could this actually cause bugs, security issues, or outages?
58
+ - Is my suggested fix correct?
59
+
60
+ Only report issues where you have **80%+ confidence**.
61
+
46
62
  ## Output Format
47
63
 
48
64
  ```markdown
49
65
  ## Quality Audit: [Branch/Feature]
50
66
 
51
67
  ### Summary
52
- - Files changed: N
68
+ - Files reviewed: N
69
+ - Spec compliance: Yes / Partial / No
53
70
  - Risk level: Low / Medium / High
54
- - Ship recommendation: ✅ Ship / ⚠️ Fix first / ❌ Major rework
55
71
 
56
72
  ### Critical (MUST fix before shipping)
57
- - **[File:line]**: [Issue]
58
- - Risk: [What could go wrong]
73
+ - **[file.ts:42]** - [Issue description]
74
+ - Evidence: [Why this is a problem]
59
75
  - Fix: [Specific suggestion]
76
+ - Confidence: [X]%
60
77
 
61
- ### Should Fix (High priority)
62
- - **[File:line]**: [Issue]
63
- - [Brief fix suggestion]
78
+ ### Major (Should fix)
79
+ - **[file.ts:100]** - [Issue]
80
+ - Fix: [Brief suggestion]
81
+ - Confidence: [X]%
64
82
 
65
- ### Consider (Nice to have)
66
- - [Minor improvement suggestion]
83
+ ### Minor (Consider fixing)
84
+ - **[file.ts:200]** - [Issue]
67
85
 
68
86
  ### Test Gaps
69
- - [ ] [Untested scenario]
87
+ - [ ] [Untested scenario that should be tested]
70
88
 
71
89
  ### Security Notes
72
- - [Any security observations]
90
+ - [Any security observations, even if not issues]
73
91
 
74
92
  ### What's Good
75
93
  - [Positive observations - patterns followed, good decisions]
76
94
  ```
77
95
 
96
+ **REQUIRED**: End every review with a verdict tag:
97
+
98
+ ```
99
+ <verdict>SHIP</verdict> # Ready to merge
100
+ <verdict>NEEDS_WORK</verdict> # Has issues that should be fixed first
101
+ <verdict>MAJOR_RETHINK</verdict> # Fundamental problems, needs redesign
102
+ ```
103
+
78
104
  ## Rules
79
105
 
80
- - Find real risks, not style nitpicks
81
- - Be specific: file:line + concrete fix
82
- - Critical = could cause outage, data loss, security breach
83
- - Don't block shipping for minor issues
84
- - Acknowledge what's done well
85
- - If no issues found, say so clearly
106
+ 1. **Find real risks, not style nitpicks** - Don't comment on naming, formatting, or preferences
107
+ 2. **Be specific** - file:line + concrete fix for every issue
108
+ 3. **Critical = high impact** - Could cause outage, data loss, security breach
109
+ 4. **Don't block shipping for minor issues** - Minor issues can be follow-up tasks
110
+ 5. **Acknowledge what's done well** - Positive feedback is important
111
+ 6. **If no issues found, say so clearly** - It's OK to say "SHIP" with no issues
112
+ 7. **80% confidence threshold** - Don't report uncertain findings
113
+
114
+ ## Severity Guide
115
+
116
+ | Severity | Criteria | Examples |
117
+ |----------|----------|----------|
118
+ | Critical | Could cause outage, data loss, security breach | SQL injection, auth bypass, data corruption |
119
+ | Major | Bug that affects users or requires immediate fix | Logic error, race condition, missing validation |
120
+ | Minor | Improvement opportunity, tech debt | Complexity, missing tests, minor inefficiency |
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: review-exploration
3
+ description: Agentic discovery for unknown scope or audit tasks
4
+ ---
5
+
6
+ # Exploration Review Mode
7
+
8
+ No specific files were provided. Use tools to discover what needs reviewing.
9
+
10
+ ## Available Tools
11
+
12
+ - **Read** - Examine file contents
13
+ - **Glob** - Find files by pattern (`**/*.ts`, `src/**/*.js`)
14
+ - **Grep** - Search for patterns in code
15
+ - **Bash** - Run git commands (git diff, git log, git status)
16
+
17
+ ## Discovery Strategy
18
+
19
+ ### 1. Understand What Changed
20
+
21
+ ```bash
22
+ git status
23
+ git log --oneline -10
24
+ git diff --stat HEAD~5
25
+ ```
26
+
27
+ ### 2. Find High-Risk Areas
28
+
29
+ Search for patterns that often have issues:
30
+ - Recent changes (git diff files)
31
+ - Auth/authz code
32
+ - Input validation
33
+ - Database queries
34
+ - API endpoints
35
+ - Error handling
36
+
37
+ ### 3. Deep Dive
38
+
39
+ For each suspicious area:
40
+ 1. Read the file
41
+ 2. Trace data flow
42
+ 3. Check error handling
43
+ 4. Look for related tests
44
+
45
+ ### 4. Confidence Filter
46
+
47
+ For each finding, ask:
48
+ - Am I **80%+ confident** this is real?
49
+ - Could it cause bugs, security issues, or outages?
50
+
51
+ **Only report 80%+ confidence issues.**
52
+
53
+ ## Output Format
54
+
55
+ ```markdown
56
+ ## Exploration Review
57
+
58
+ ### Scope
59
+ - [What you discovered about the codebase]
60
+ - [What changed recently]
61
+
62
+ ### Areas Examined
63
+ 1. **[Area]** - [why you looked here]
64
+
65
+ ### Issues (80%+ confidence)
66
+
67
+ #### Critical
68
+ - **file:line** - [issue]
69
+ - Impact: [damage]
70
+ - Fix: [suggestion]
71
+
72
+ #### Major
73
+ - **file:line** - [issue] → [fix]
74
+
75
+ ### Not Covered
76
+ - [What you skipped]
77
+
78
+ ### What's Good
79
+ - [Positive observations]
80
+ ```
81
+
82
+ Then:
83
+ ```
84
+ <verdict>SHIP|NEEDS_WORK|MAJOR_RETHINK</verdict>
85
+ ```
86
+
87
+ ## Rules
88
+
89
+ 1. **Prioritize recent changes** - most likely to have issues
90
+ 2. **80% confidence threshold** - no uncertain findings
91
+ 3. **Follow the data** - trace user input paths
92
+ 4. **Document coverage** - be clear what you did/didn't review
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: review-quick
3
+ description: Fast review for small, focused changes
4
+ ---
5
+
6
+ # Quick Review
7
+
8
+ Small, focused change. Be efficient but thorough.
9
+
10
+ ## Process (Chain of Thought)
11
+
12
+ 1. **Understand Intent** - What is this change trying to do?
13
+ 2. **Check Correctness** - Does the code match the intent? Off-by-one? Null checks?
14
+ 3. **Check Error Handling** - Are errors caught and handled properly?
15
+ 4. **Security Basics** - No hardcoded secrets? No obvious injection vectors?
16
+
17
+ ## Confidence Rule
18
+
19
+ For each issue, ask: Am I **80%+ confident** this is real?
20
+ Only report high-confidence issues.
21
+
22
+ ## Skip
23
+
24
+ - Style nitpicks
25
+ - Refactoring suggestions
26
+ - "Nice to have" improvements
27
+
28
+ ## Output
29
+
30
+ ```markdown
31
+ ## Quick Review
32
+
33
+ **Change:** [1-sentence summary]
34
+ **Risk:** Low / Medium
35
+
36
+ ### Issues (80%+ confidence)
37
+ - **file:line** - [issue] → [fix]
38
+
39
+ ### Looks Good
40
+ - [positive observation]
41
+ ```
42
+
43
+ Then:
44
+ ```
45
+ <verdict>SHIP|NEEDS_WORK</verdict>
46
+ ```
47
+
48
+ Keep it brief. If it's clean, say so and ship it.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: review-router
3
+ description: Adaptive code review - analyzes context and loads appropriate skill
4
+ ---
5
+
6
+ You are an expert code reviewer. First, analyze the context to decide the best review approach.
7
+
8
+ ## Step 1: Analyze What You've Been Given
9
+
10
+ Look at the context provided:
11
+ - How many files?
12
+ - How many lines changed?
13
+ - What kind of change? (bug fix, feature, refactor, security-related)
14
+ - Is there a clear spec or requirements?
15
+
16
+ ## Step 2: Choose and Load Your Skill
17
+
18
+ Based on your analysis, choose ONE approach and load its instructions:
19
+
20
+ ### Quick Review
21
+ **When:** 1-3 files, <500 lines, clear purpose, bug fix or small feature
22
+ **Load:** Run `wdyt -e 'skill get review-quick'`
23
+
24
+ ### Thorough Review
25
+ **When:** 4-10 files, significant changes, needs careful analysis
26
+ **Load:** Run `wdyt -e 'skill get review-thorough'`
27
+
28
+ ### Security Review
29
+ **When:** Code touches auth, crypto, user input, sensitive data, or APIs
30
+ **Load:** Run `wdyt -e 'skill get review-security'`
31
+
32
+ ### Exploration Review
33
+ **When:** No specific files given, asked to "audit" or "explore"
34
+ **Load:** Run `wdyt -e 'skill get review-exploration'`
35
+
36
+ ## Step 3: Execute
37
+
38
+ 1. State which approach you're using and why (1 sentence)
39
+ 2. Run the wdyt command to load the skill instructions
40
+ 3. Follow those instructions exactly
41
+
42
+ ## Output
43
+
44
+ Always end with:
45
+ ```
46
+ <verdict>SHIP|NEEDS_WORK|MAJOR_RETHINK</verdict>
47
+ ```
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: review-security
3
+ description: Security-focused review for sensitive code
4
+ ---
5
+
6
+ # Security Review
7
+
8
+ This code touches security-sensitive areas. Be paranoid.
9
+
10
+ ## Process (Chain of Thought)
11
+
12
+ ### 1. Trace Data Flow
13
+ Follow user input from entry to storage/output. Every trust boundary needs validation.
14
+
15
+ ### 2. Check Input Validation
16
+ - All user input validated before use?
17
+ - SQL queries parameterized?
18
+ - File paths checked for traversal (../)?
19
+ - URLs validated before fetch/redirect?
20
+
21
+ ### 3. Check Auth
22
+ - Auth checks on all protected routes?
23
+ - Session tokens cryptographically secure?
24
+ - Password handling uses proper hashing?
25
+ - No auth bypass paths?
26
+
27
+ ### 4. Check Data Protection
28
+ - Sensitive data not logged?
29
+ - Secrets not hardcoded?
30
+ - PII properly handled?
31
+ - Encryption for sensitive storage/transit?
32
+
33
+ ### 5. Common Vulnerabilities
34
+ - XSS vectors (user content escaped)?
35
+ - CSRF protection on state-changing operations?
36
+ - Open redirects?
37
+ - Rate limiting on sensitive endpoints?
38
+ - Error messages don't leak stack traces?
39
+
40
+ ## Confidence Rule
41
+
42
+ For each issue, ask: Am I **80%+ confident** this is exploitable?
43
+ When in doubt about security, flag it anyway - better to discuss than to miss.
44
+
45
+ ## Output
46
+
47
+ ```markdown
48
+ ## Security Review
49
+
50
+ ### Threat Summary
51
+ - Attack surface: [what's exposed]
52
+ - Sensitive data: [what's at risk]
53
+ - Risk level: Low / Medium / High / Critical
54
+
55
+ ### Vulnerabilities (by severity)
56
+
57
+ #### Critical
58
+ - **file:line** - [vulnerability type]
59
+ - Attack: [how it could be exploited]
60
+ - Impact: [what damage could result]
61
+ - Fix: [specific remediation]
62
+
63
+ #### High
64
+ - **file:line** - [issue] → [fix]
65
+
66
+ #### Medium/Low
67
+ - **file:line** - [observation]
68
+
69
+ ### Security Positives
70
+ - [good security practices observed]
71
+
72
+ ### Recommendations
73
+ - [additional hardening suggestions]
74
+ ```
75
+
76
+ Then:
77
+ ```
78
+ <verdict>SHIP|NEEDS_WORK|MAJOR_RETHINK</verdict>
79
+ ```