vibe-sort 0.2.0
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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +27 -0
- data/CHANGELOG.md +101 -0
- data/LICENSE.txt +21 -0
- data/README.md +281 -0
- data/Rakefile +12 -0
- data/docs/IMPLEMENTATION_PLAN.md +534 -0
- data/docs/README.md +211 -0
- data/docs/api_reference.md +440 -0
- data/docs/architecture.md +320 -0
- data/docs/development.md +566 -0
- data/docs/v0.2.0_UPDATE.md +377 -0
- data/lib/vibe/sort/version.rb +7 -0
- data/lib/vibe/sort.rb +10 -0
- data/lib/vibe_sort/client.rb +87 -0
- data/lib/vibe_sort/configuration.rb +21 -0
- data/lib/vibe_sort/error.rb +17 -0
- data/lib/vibe_sort/sorter.rb +125 -0
- data/lib/vibe_sort/version.rb +5 -0
- data/lib/vibe_sort.rb +14 -0
- data/sig/vibe/sort.rbs +6 -0
- metadata +83 -0
data/docs/development.md
ADDED
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
# Development Guide
|
|
2
|
+
|
|
3
|
+
## Getting Started
|
|
4
|
+
|
|
5
|
+
### Prerequisites
|
|
6
|
+
|
|
7
|
+
- Ruby >= 3.0.0
|
|
8
|
+
- Bundler
|
|
9
|
+
- Git
|
|
10
|
+
- OpenAI API key (for integration tests)
|
|
11
|
+
|
|
12
|
+
### Initial Setup
|
|
13
|
+
|
|
14
|
+
1. **Clone the repository**
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git clone https://github.com/chayut/vibe-sort.git
|
|
18
|
+
cd vibe-sort
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
2. **Install dependencies**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bundle install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. **Set up environment variables**
|
|
28
|
+
|
|
29
|
+
Create a `.env` file (not committed to git):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
echo "OPENAI_API_KEY=your-api-key-here" > .env
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or export it in your shell:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
export OPENAI_API_KEY='sk-your-key-here'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
4. **Run the console**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bin/console
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This starts an IRB session with the gem loaded:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
irb(main):001:0> client = VibeSort::Client.new(api_key: ENV['OPENAI_API_KEY'])
|
|
51
|
+
irb(main):002:0> client.sort([5, 2, 8, 1, 9])
|
|
52
|
+
# => {:success=>true, :sorted_array=>[1, 2, 5, 8, 9]}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Project Structure
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
vibe-sort/
|
|
59
|
+
├── lib/
|
|
60
|
+
│ ├── vibe_sort.rb # Main entry point
|
|
61
|
+
│ └── vibe_sort/
|
|
62
|
+
│ ├── client.rb # Public API
|
|
63
|
+
│ ├── configuration.rb # Config object
|
|
64
|
+
│ ├── error.rb # Custom exceptions
|
|
65
|
+
│ ├── sorter.rb # API communication
|
|
66
|
+
│ └── version.rb # Version constant
|
|
67
|
+
├── spec/
|
|
68
|
+
│ ├── spec_helper.rb # RSpec configuration
|
|
69
|
+
│ └── vibe_sort/
|
|
70
|
+
│ ├── client_spec.rb # Client tests
|
|
71
|
+
│ ├── configuration_spec.rb # Configuration tests
|
|
72
|
+
│ ├── sorter_spec.rb # Sorter tests
|
|
73
|
+
│ └── integration_spec.rb # End-to-end tests
|
|
74
|
+
├── docs/
|
|
75
|
+
│ ├── architecture.md # Architecture overview
|
|
76
|
+
│ ├── api_reference.md # API documentation
|
|
77
|
+
│ └── development.md # This file
|
|
78
|
+
├── bin/
|
|
79
|
+
│ ├── console # Interactive console
|
|
80
|
+
│ └── setup # Setup script
|
|
81
|
+
├── Gemfile # Dependencies
|
|
82
|
+
├── Rakefile # Rake tasks
|
|
83
|
+
├── vibe-sort.gemspec # Gem specification
|
|
84
|
+
├── README.md # User documentation
|
|
85
|
+
├── CHANGELOG.md # Version history
|
|
86
|
+
└── LICENSE.txt # MIT License
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Running Tests
|
|
90
|
+
|
|
91
|
+
### All Tests
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
bundle exec rspec
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### With Coverage
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
bundle exec rspec --format documentation
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Specific Test File
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
bundle exec rspec spec/vibe_sort/client_spec.rb
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Specific Test
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
bundle exec rspec spec/vibe_sort/client_spec.rb:23
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Watch Mode (with guard)
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
bundle exec guard
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Writing Tests
|
|
122
|
+
|
|
123
|
+
### Unit Tests
|
|
124
|
+
|
|
125
|
+
Mock external API calls using WebMock or VCR:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
# spec/vibe_sort/sorter_spec.rb
|
|
129
|
+
require 'spec_helper'
|
|
130
|
+
|
|
131
|
+
RSpec.describe VibeSort::Sorter do
|
|
132
|
+
let(:config) { VibeSort::Configuration.new(api_key: 'test-key') }
|
|
133
|
+
let(:sorter) { described_class.new(config) }
|
|
134
|
+
|
|
135
|
+
describe '#perform' do
|
|
136
|
+
it 'sorts the array via API' do
|
|
137
|
+
stub_request(:post, VibeSort::Sorter::OPENAI_API_URL)
|
|
138
|
+
.with(
|
|
139
|
+
headers: { 'Authorization' => 'Bearer test-key' },
|
|
140
|
+
body: hash_including(model: 'gpt-3.5-turbo-1106')
|
|
141
|
+
)
|
|
142
|
+
.to_return(
|
|
143
|
+
status: 200,
|
|
144
|
+
body: {
|
|
145
|
+
choices: [{
|
|
146
|
+
message: {
|
|
147
|
+
content: '{"sorted_array": [1, 2, 3]}'
|
|
148
|
+
}
|
|
149
|
+
}]
|
|
150
|
+
}.to_json,
|
|
151
|
+
headers: { 'Content-Type' => 'application/json' }
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
result = sorter.perform([3, 1, 2])
|
|
155
|
+
|
|
156
|
+
expect(result[:success]).to be true
|
|
157
|
+
expect(result[:sorted_array]).to eq([1, 2, 3])
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Integration Tests
|
|
164
|
+
|
|
165
|
+
Test with real API (use test API key):
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
# spec/vibe_sort/integration_spec.rb
|
|
169
|
+
require 'spec_helper'
|
|
170
|
+
|
|
171
|
+
RSpec.describe 'Integration Tests', :integration do
|
|
172
|
+
let(:api_key) { ENV['OPENAI_API_KEY'] }
|
|
173
|
+
let(:client) { VibeSort::Client.new(api_key: api_key) }
|
|
174
|
+
|
|
175
|
+
before do
|
|
176
|
+
skip 'No API key provided' unless api_key
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'sorts an array end-to-end' do
|
|
180
|
+
result = client.sort([5, 2, 8, 1, 9])
|
|
181
|
+
|
|
182
|
+
expect(result[:success]).to be true
|
|
183
|
+
expect(result[:sorted_array]).to eq([1, 2, 5, 8, 9])
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Run integration tests separately:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
bundle exec rspec --tag integration
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Code Style
|
|
195
|
+
|
|
196
|
+
### Linting
|
|
197
|
+
|
|
198
|
+
Use RuboCop for code style:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
bundle exec rubocop
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Auto-fix issues:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
bundle exec rubocop -a
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Style Guidelines
|
|
211
|
+
|
|
212
|
+
- Use 2 spaces for indentation
|
|
213
|
+
- Keep lines under 120 characters
|
|
214
|
+
- Use snake_case for methods and variables
|
|
215
|
+
- Use CamelCase for classes and modules
|
|
216
|
+
- Add comments for complex logic
|
|
217
|
+
- Write descriptive method and variable names
|
|
218
|
+
|
|
219
|
+
### Example
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
# Good
|
|
223
|
+
def build_payload(array)
|
|
224
|
+
{
|
|
225
|
+
model: DEFAULT_MODEL,
|
|
226
|
+
temperature: config.temperature,
|
|
227
|
+
messages: build_messages(array)
|
|
228
|
+
}
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Bad
|
|
232
|
+
def bp(a)
|
|
233
|
+
{ m: M, t: c.t, msgs: bm(a) }
|
|
234
|
+
end
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Debugging
|
|
238
|
+
|
|
239
|
+
### Using Pry
|
|
240
|
+
|
|
241
|
+
Add `binding.pry` anywhere in the code:
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
def sort(array)
|
|
245
|
+
binding.pry # Execution will stop here
|
|
246
|
+
|
|
247
|
+
unless valid_input?(array)
|
|
248
|
+
return { success: false, sorted_array: [], error: "Invalid input" }
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# ...
|
|
252
|
+
end
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Then run your code:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
bundle exec rspec spec/vibe_sort/client_spec.rb
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Logging HTTP Requests
|
|
262
|
+
|
|
263
|
+
Enable Faraday logging:
|
|
264
|
+
|
|
265
|
+
```ruby
|
|
266
|
+
# lib/vibe_sort/sorter.rb
|
|
267
|
+
def connection
|
|
268
|
+
@connection ||= Faraday.new(url: OPENAI_API_URL) do |f|
|
|
269
|
+
f.request :json
|
|
270
|
+
f.response :json
|
|
271
|
+
f.response :logger # Add this line
|
|
272
|
+
f.adapter Faraday.default_adapter
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Building the Gem
|
|
278
|
+
|
|
279
|
+
### Local Build
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
gem build vibe-sort.gemspec
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
This creates `vibe-sort-0.1.0.gem`.
|
|
286
|
+
|
|
287
|
+
### Local Install
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
gem install ./vibe-sort-0.1.0.gem
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Or use rake:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
bundle exec rake install
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Test Local Gem
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
irb
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
require 'vibe_sort'
|
|
307
|
+
client = VibeSort::Client.new(api_key: ENV['OPENAI_API_KEY'])
|
|
308
|
+
client.sort([5, 2, 8])
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Release Process
|
|
312
|
+
|
|
313
|
+
### 1. Update Version
|
|
314
|
+
|
|
315
|
+
Edit `lib/vibe_sort/version.rb`:
|
|
316
|
+
|
|
317
|
+
```ruby
|
|
318
|
+
module VibeSort
|
|
319
|
+
VERSION = "0.2.0"
|
|
320
|
+
end
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 2. Update CHANGELOG
|
|
324
|
+
|
|
325
|
+
Add release notes to `CHANGELOG.md`:
|
|
326
|
+
|
|
327
|
+
```markdown
|
|
328
|
+
## [0.2.0] - 2025-10-17
|
|
329
|
+
|
|
330
|
+
### Added
|
|
331
|
+
- New feature X
|
|
332
|
+
- New feature Y
|
|
333
|
+
|
|
334
|
+
### Fixed
|
|
335
|
+
- Bug fix Z
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### 3. Commit Changes
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
git add -A
|
|
342
|
+
git commit -m "Bump version to 0.2.0"
|
|
343
|
+
git tag v0.2.0
|
|
344
|
+
git push origin main --tags
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 4. Build and Release
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
bundle exec rake release
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
This will:
|
|
354
|
+
- Build the gem
|
|
355
|
+
- Create a git tag
|
|
356
|
+
- Push to RubyGems.org (if configured)
|
|
357
|
+
|
|
358
|
+
## Documentation
|
|
359
|
+
|
|
360
|
+
### Generating RDoc
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
bundle exec rake rdoc
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Output: `doc/` directory
|
|
367
|
+
|
|
368
|
+
### Generating YARD Docs
|
|
369
|
+
|
|
370
|
+
Add `yard` to Gemfile:
|
|
371
|
+
|
|
372
|
+
```ruby
|
|
373
|
+
gem 'yard', group: :development
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Then run:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
bundle exec yard doc
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Output: `doc/` directory
|
|
383
|
+
|
|
384
|
+
View docs:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
bundle exec yard server
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
Visit: http://localhost:8808
|
|
391
|
+
|
|
392
|
+
## Common Tasks
|
|
393
|
+
|
|
394
|
+
### Add a New Feature
|
|
395
|
+
|
|
396
|
+
1. Write a failing test
|
|
397
|
+
2. Implement the feature
|
|
398
|
+
3. Make the test pass
|
|
399
|
+
4. Refactor if needed
|
|
400
|
+
5. Update documentation
|
|
401
|
+
6. Commit changes
|
|
402
|
+
|
|
403
|
+
### Fix a Bug
|
|
404
|
+
|
|
405
|
+
1. Write a test that reproduces the bug
|
|
406
|
+
2. Fix the bug
|
|
407
|
+
3. Ensure all tests pass
|
|
408
|
+
4. Update CHANGELOG
|
|
409
|
+
5. Commit changes
|
|
410
|
+
|
|
411
|
+
### Add a Dependency
|
|
412
|
+
|
|
413
|
+
1. Add to `vibe-sort.gemspec`:
|
|
414
|
+
|
|
415
|
+
```ruby
|
|
416
|
+
spec.add_dependency "new-gem", "~> 1.0"
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
2. Run `bundle install`
|
|
420
|
+
3. Update documentation
|
|
421
|
+
4. Commit changes
|
|
422
|
+
|
|
423
|
+
### Remove a Dependency
|
|
424
|
+
|
|
425
|
+
1. Remove from `vibe-sort.gemspec`
|
|
426
|
+
2. Remove all usage from code
|
|
427
|
+
3. Run `bundle install`
|
|
428
|
+
4. Run tests to ensure nothing breaks
|
|
429
|
+
5. Update documentation
|
|
430
|
+
6. Commit changes
|
|
431
|
+
|
|
432
|
+
## Troubleshooting
|
|
433
|
+
|
|
434
|
+
### Tests Failing
|
|
435
|
+
|
|
436
|
+
**Check API key:**
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
echo $OPENAI_API_KEY
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Check dependencies:**
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
bundle check
|
|
446
|
+
bundle install
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Check Ruby version:**
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
ruby -v
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Gem Won't Build
|
|
456
|
+
|
|
457
|
+
**Check gemspec:**
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
gem build vibe-sort.gemspec
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Look for errors in output.
|
|
464
|
+
|
|
465
|
+
**Check file permissions:**
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
ls -la
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### API Errors
|
|
472
|
+
|
|
473
|
+
**Test API key manually:**
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
curl https://api.openai.com/v1/chat/completions \
|
|
477
|
+
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
|
478
|
+
-H "Content-Type: application/json" \
|
|
479
|
+
-d '{
|
|
480
|
+
"model": "gpt-3.5-turbo",
|
|
481
|
+
"messages": [{"role": "user", "content": "Hello"}]
|
|
482
|
+
}'
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## Best Practices
|
|
486
|
+
|
|
487
|
+
### 1. Test Coverage
|
|
488
|
+
|
|
489
|
+
Aim for 100% coverage:
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
bundle exec rspec --format documentation
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### 2. Error Handling
|
|
496
|
+
|
|
497
|
+
Always handle errors gracefully:
|
|
498
|
+
|
|
499
|
+
```ruby
|
|
500
|
+
def sort(array)
|
|
501
|
+
# Validate input
|
|
502
|
+
return error_hash("Invalid input") unless valid_input?(array)
|
|
503
|
+
|
|
504
|
+
# Perform operation
|
|
505
|
+
sorter.perform(array)
|
|
506
|
+
rescue ApiError => e
|
|
507
|
+
error_hash(e.message)
|
|
508
|
+
rescue StandardError => e
|
|
509
|
+
error_hash("Unexpected error: #{e.message}")
|
|
510
|
+
end
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### 3. Documentation
|
|
514
|
+
|
|
515
|
+
Document all public methods:
|
|
516
|
+
|
|
517
|
+
```ruby
|
|
518
|
+
# Sort an array of numbers using OpenAI API
|
|
519
|
+
#
|
|
520
|
+
# @param array [Array<Numeric>] Array of numbers to sort
|
|
521
|
+
# @return [Hash] Result hash with :success, :sorted_array, :error keys
|
|
522
|
+
#
|
|
523
|
+
# @example
|
|
524
|
+
# client.sort([5, 2, 8])
|
|
525
|
+
# # => { success: true, sorted_array: [2, 5, 8] }
|
|
526
|
+
def sort(array)
|
|
527
|
+
# ...
|
|
528
|
+
end
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### 4. Git Workflow
|
|
532
|
+
|
|
533
|
+
Use meaningful commit messages:
|
|
534
|
+
|
|
535
|
+
```bash
|
|
536
|
+
git commit -m "feat: Add support for custom models"
|
|
537
|
+
git commit -m "fix: Handle empty API responses"
|
|
538
|
+
git commit -m "docs: Update API reference"
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### 5. Code Reviews
|
|
542
|
+
|
|
543
|
+
Before submitting a PR:
|
|
544
|
+
|
|
545
|
+
- Run all tests
|
|
546
|
+
- Check code style
|
|
547
|
+
- Update documentation
|
|
548
|
+
- Add CHANGELOG entry
|
|
549
|
+
- Write a clear PR description
|
|
550
|
+
|
|
551
|
+
## Resources
|
|
552
|
+
|
|
553
|
+
- [Ruby Style Guide](https://rubystyle.guide/)
|
|
554
|
+
- [RSpec Best Practices](https://www.betterspecs.org/)
|
|
555
|
+
- [Semantic Versioning](https://semver.org/)
|
|
556
|
+
- [OpenAI API Docs](https://platform.openai.com/docs/)
|
|
557
|
+
- [Faraday Documentation](https://lostisland.github.io/faraday/)
|
|
558
|
+
|
|
559
|
+
## Getting Help
|
|
560
|
+
|
|
561
|
+
- Open an issue on GitHub
|
|
562
|
+
- Check existing issues and PRs
|
|
563
|
+
- Read the documentation
|
|
564
|
+
- Ask in the community
|
|
565
|
+
|
|
566
|
+
Happy coding! 🚀
|