Commit 5ffb3f7
feat: add config system with discovery, loading, and CLI commands (#11)
* docs: map existing codebase
- STACK.md - Technologies and dependencies
- ARCHITECTURE.md - System design and patterns
- STRUCTURE.md - Directory layout
- CONVENTIONS.md - Code style and patterns
- TESTING.md - Test structure
- INTEGRATIONS.md - External services
- CONCERNS.md - Technical debt and issues
* docs: initialize project
Terminal-based log viewer adding project-scoped configuration and stream cleanup
* chore: add project config
Mode: yolo
Depth: standard
Parallelization: enabled
Workflow agents: research=on, plan_check=on, verifier=on
* docs: complete project research
Files:
- STACK.md: serde-saphyr for YAML, signal-hook 0.4 upgrade
- FEATURES.md: table stakes (auto-discovery, precedence), differentiators (named sources)
- ARCHITECTURE.md: layered config with precedence merging, signal flag pattern
- PITFALLS.md: async-signal-safety, race conditions, discovery loops
- SUMMARY.md: synthesized findings with 5-phase roadmap structure
Key findings:
- Stack: serde-saphyr 0.0 (panic-free YAML), signal-hook 0.4.3 upgrade
- Architecture: config loads before event loop, flag pattern for cleanup
- Critical pitfall: async-signal-unsafe operations (existing pattern correct, needs refinement)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: define v1 requirements
20 requirements across 6 categories:
- Signal handling (4)
- Config discovery (3)
- Config loading (3)
- Config options (5)
- Project-local streams (2)
- Config commands (3)
* docs: create roadmap (5 phases)
Phases:
1. Signal Infrastructure: SIG-01..04
2. Config Discovery: DISC-01..03
3. Config Loading: LOAD-01..03, OPT-01..05
4. Project-Local Streams: PROJ-01..02
5. Config Commands: CMD-01..03
All 20 v1 requirements mapped to phases.
* docs(01): capture phase context
Phase 01: Signal Infrastructure
- Implementation decisions documented
- Phase boundary established
* docs(01): research signal infrastructure
Phase 1: Signal Infrastructure
- Standard stack: signal-hook flag module (already in deps)
- Architecture patterns: double Ctrl+C, flag-based shutdown, stale marker cleanup
- Pitfalls: process::exit() in handlers, blocking iterators, registration order
* docs(01): create phase plan
Phase 01: Signal Infrastructure
- 1 plan in 1 wave
- 3 tasks: signal module, capture refactor, stale cleanup
- Ready for execution
* feat(01-01): create signal module with shutdown infrastructure
- Add src/signal.rs with setup_shutdown_handlers() function
- Uses signal-hook::flag for flag-based signal handling
- Supports double Ctrl+C for force quit (exit code 1)
- Register conditional shutdown before flag setter (order matters)
- Add mod signal; declaration to main.rs
* refactor(01-01): use flag-based shutdown in capture mode
- Remove thread::spawn signal handler with process::exit()
- Use signal module's setup_shutdown_handlers() instead
- Check shutdown_flag.load(Ordering::SeqCst) in tee loop
- Cleanup now always runs (no premature exit from signal handler)
- Supports double Ctrl+C force quit via conditional_shutdown
* feat(01-01): add stale marker cleanup at startup
- Add cleanup_stale_markers() to source.rs
- Scans sources directory for marker files
- Removes markers where PID is no longer running
- Called in main() before any mode dispatch
- Errors logged to stderr but don't prevent startup
- Fixes SIGKILL recovery scenario
* docs(01-01): complete signal infrastructure plan
Tasks completed: 3/3
- Create signal.rs module with shutdown infrastructure
- Refactor capture.rs to use flag-based shutdown
- Add stale marker cleanup at startup
SUMMARY: .planning/phases/01-signal-infrastructure/01-01-SUMMARY.md
* docs(01): complete signal infrastructure phase
Phase 1 verified:
- Signal module with flag-based shutdown handlers
- Capture mode refactored to use flags (no process::exit)
- Stale marker cleanup at startup
- Double Ctrl+C force-exit support
Requirements: SIG-01, SIG-02, SIG-03, SIG-04 complete
* feat(install): add MCP configuration for AI assistants
- Detect installed AI assistants (Claude Code, Claude Desktop, Codex,
Gemini CLI, Cursor, Windsurf, Zed)
- Prompt to configure MCP integration for each detected assistant
- Support JSON config (Desktop, Cursor, Windsurf, Gemini) and TOML (Codex)
- Use /dev/tty for reads to work with piped installation
* docs(02): capture phase context
Phase 02: Config Discovery
- Implementation decisions documented
- Phase boundary established
* docs(02): research config discovery domain
Phase 02: Config Discovery
- Standard stack identified (std::path, dirs crate)
- Architecture patterns documented (ancestors traversal)
- Pitfalls catalogued (permission errors, symlinks)
* docs(02): create phase plan
Phase 02: Config Discovery
- 1 plan in 1 wave
- 1 parallel, 0 sequential
- Ready for execution
* fix(02): revise plan based on checker feedback
Addresses checker issues:
- DISC-03: Added explicit root boundary handling mention
- Added dirs crate dependency verification step
- Changed to discover_verbose() for -v flag search PATH output
- Added key_link for data_dir() -> Phase 4 connection
- Added test cases for root boundary and global config detection
- Clarified subdirectory walking verification in Task 2
* feat(02-01): add config discovery module
- Add src/config/discovery.rs with discover() and discover_verbose() functions
- DiscoveryResult struct holds project_root, project_config, global_config paths
- data_dir() method returns project_root/.lazytail for Phase 4 storage
- Walks parent directories to find lazytail.yaml (terminates at filesystem root)
- Checks ~/.config/lazytail/config.yaml for global config
- discover_verbose() returns all searched directories for -v output
- Unit tests verify discovery behavior including root boundary
* feat(02-01): integrate config discovery into main.rs
- Add mod config; declaration to main.rs
- Add -v/--verbose flag to Args struct
- Call discover_verbose() after cleanup_stale_markers()
- Verbose mode shows search path (all directories checked) to stderr
- Verbose mode shows discovery results (project root, project config, global config)
- Non-verbose mode has no discovery output
- Store discovery result for Phase 3 config loading
* docs(02-01): complete config discovery plan
Tasks completed: 2/2
- Task 1: Create config discovery module with tests
- Task 2: Integrate discovery into main.rs with verbose output
SUMMARY: .planning/phases/02-config-discovery/02-01-SUMMARY.md
* docs(02): complete config-discovery phase
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(03): capture phase context
Phase 03: Config Loading
- Implementation decisions documented
- Phase boundary established
* docs(03): research config loading phase
Phase 3: Config Loading
- Standard stack identified (serde-saphyr, strsim)
- Architecture patterns documented (strict parsing, typo suggestions)
- Pitfalls catalogued (deny_unknown_fields, tilde expansion)
* docs(03): create phase plan
Phase 03: Config Loading
- 2 plans in 2 waves
- Wave 1: Config infrastructure (types, parser, errors)
- Wave 2: Integration with main.rs and UI
- Ready for execution
* feat(03-01): add config types with deny_unknown_fields
- Add serde-saphyr, strsim, thiserror dependencies to Cargo.toml
- Create src/config/types.rs with RawConfig, RawSource, Source, Config
- Create stub src/config/error.rs with ConfigError variants
- Create stub src/config/loader.rs for later implementation
- Update src/config/mod.rs to export new modules
* feat(03-01): add ConfigError with suggestions and locations
- Add jaro_winkler similarity search for typo suggestions
- Known fields: root (name, sources), source (name, path)
- 0.8 threshold for Jaro-Winkler similarity matching
- Extract line/column from serde-saphyr error messages
- Cargo-style error formatting with suggestion hints
- Comprehensive unit tests for all error formatting
* feat(03-01): add config loader with path expansion
- Add expand_path() for tilde to home directory expansion
- Add load_file() for YAML parsing with serde-saphyr
- Add validate_sources() for path expansion and existence check
- Add load() to merge project and global configs
- Project name takes precedence, sources kept in separate groups
- Graceful degradation: empty Config when no configs exist
- Comprehensive unit tests for all loader functions
* docs(03-01): complete config loading infrastructure plan
Tasks completed: 3/3
- Add dependencies and create config types
- Create error module with suggestions
- Create config loader with path expansion
SUMMARY: .planning/phases/03-config-loading/03-01-SUMMARY.md
* feat(03-02): add config source types and tab creation
- Add ProjectSource and GlobalSource variants to SourceType enum
- Update SourcePanelState.expanded array to 5 elements
- Update tabs_by_category to return 5 categories
- Add from_config_source() method to TabState for creating tabs from config
- Add disabled_source() helper for missing config sources
- Add config_source_type and disabled fields to TabState
- Update source_type() to check config_source_type first
* feat(03-02): update UI for config source categories
- Add ProjectSource and GlobalSource category names to side panel
- Rename Global category to Captured for clarity
- Show disabled sources (missing files) in grayed-out style
* feat(03-02): integrate config loading in main.rs
- Load config from discovered files at startup
- Create tabs from project and global config sources
- Prepend config tabs before CLI args and discovery tabs
- Update discovery mode to accept config and errors
- Log config errors to stderr (debug source is future enhancement)
- Update exit message with config option when no sources found
* docs(03-02): complete config integration plan
Tasks completed: 3/3
- Task 1: Add config source types and tab creation
- Task 2: Update UI for config source categories
- Task 3: Integrate config loading in main.rs
SUMMARY: .planning/phases/03-config-loading/03-02-SUMMARY.md
* fix(03): commit Cargo.lock and formatting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(03): add phase verification report
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(filter): add query filter module (WIP)
Accidentally mixed with phase 3 commits - included to fix build.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(filter): export query module
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(03): complete config loading phase
- Mark phase 3 plans complete in ROADMAP.md
- Update STATE.md with phase completion
- Mark LOAD-01, LOAD-02, LOAD-03, OPT-01, OPT-02 complete in REQUIREMENTS.md
- OPT-03, OPT-04, OPT-05 deferred
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(04): research project-local streams phase
Phase 4: Project-Local Streams
- Document context-aware directory resolution pattern
- Research DirBuilder with mode 0o700 for secure permissions
- Identify integration points with existing discovery/source modules
- Catalogue pitfalls (mode permissions, context mismatch)
* docs(04): create phase plan
Phase 04: Project-Local Streams
- 2 plans in 2 waves
- Wave 1: Context-aware directory functions + capture mode
- Wave 2: Discovery mode with dual-location scanning
- Ready for execution
* feat(04-01): add context-aware directory resolution to source.rs
- Add create_secure_dir() for 0700 permissions on Unix
- Add resolve_data_dir(discovery) for context-aware data directory
- Add resolve_sources_dir(discovery) for context-aware sources directory
- Add ensure_directories_for_context(discovery) wrapper
- Add check_source_status_for_context, create_marker_for_context,
remove_marker_for_context for discovery-aware marker operations
- Add comprehensive tests for all new functions
* feat(04-01): integrate context-aware capture mode
- Update run_capture_mode to accept DiscoveryResult parameter
- Use context-aware functions: ensure_directories_for_context,
check_source_status_for_context, create_marker_for_context,
resolve_data_dir, remove_marker_for_context
- Add location indicator (project/global) to capture header output
- Update main.rs to pass discovery result to capture mode
* docs(04-01): complete context-aware directory resolution plan
Tasks completed: 2/2
- Add context-aware directory functions to source.rs
- Integrate context-aware capture mode
SUMMARY: .planning/phases/04-project-local-streams/04-01-SUMMARY.md
* feat(04-02): add SourceLocation enum and context-aware discovery
- Add SourceLocation enum (Project, Global) to track source origin
- Add location field to DiscoveredSource struct
- Create scan_data_directory helper for code reuse
- Add check_source_status_in_dir for location-specific status checks
- Add discover_sources_for_context to scan both project and global dirs
- Project sources appear first and shadow global sources with same name
- Update existing discover_sources to set location: Global
- Update main.rs DiscoveredSource construction with location field
- Add tests for dual-location discovery and shadowing
* feat(04-02): integrate context-aware discovery in discovery mode
- Update run_discovery_mode to accept DiscoveryResult parameter
- Use discover_sources_for_context for dual-location scanning
- Use ensure_directories_for_context for secure directory creation
- Directory watcher now watches project data dir if in project context
- Pass watched_location to run_app_with_discovery for correct source location
- New sources discovered via watcher use the context-appropriate location
* docs(04-02): complete dual-location discovery plan
Tasks completed: 2/2
- Add SourceLocation enum and context-aware discovery
- Integrate context-aware discovery in main.rs
SUMMARY: .planning/phases/04-project-local-streams/04-02-SUMMARY.md
* docs(04): complete project-local streams phase
- Phase 4 verified and complete
- PROJ-01, PROJ-02 requirements marked complete
- All success criteria met
* docs(05): capture phase context
Phase 05: Config Commands
- Implementation decisions documented
- Phase boundary established
* docs(05): research phase domain
Phase 5: Config Commands
- Standard stack identified (clap subcommands, colored crate)
- Architecture patterns documented (nested subcommands, closest-config-wins)
- Pitfalls catalogued (backward compat, quiet success, NO_COLOR)
* docs(05): create phase plan
Phase 05: Config Commands
- 2 plan(s) in 1 wave(s)
- Both parallel (wave 1), 05-02 depends on 05-01
- Ready for execution
* feat(05-01): add cmd module structure with subcommand definitions
- Add colored dependency (v3.1) to Cargo.toml
- Create src/cmd/mod.rs with Commands enum (Init, Config)
- Create InitArgs struct with --force flag
- Create ConfigAction enum (Validate, Show)
- Add placeholder init.rs for task 3
* feat(05-01): add subcommand dispatch to main.rs
- Rename Args to Cli struct for clarity
- Add optional command field with Option<cmd::Commands>
- Handle subcommands before mode detection logic
- Route init command to cmd::init::run()
- Add TODO stubs for config validate/show (Plan 05-02)
- Rename all args references to cli
- Preserve backward compatibility for file/stdin/discovery modes
* feat(05-01): implement lazytail init command
- Create lazytail.yaml with commented template
- Auto-detect project name from directory
- Create .lazytail/ directory with secure permissions (0700)
- Check for existing config, fail without --force
- Add unit tests for template generation
* docs(05-01): complete CLI subcommand infrastructure plan
Tasks completed: 3/3
- Add colored dependency and create cmd module structure
- Refactor main.rs for subcommand handling
- Implement init command
SUMMARY: .planning/phases/05-config-commands/05-01-SUMMARY.md
* feat(05-02): add load_single_file for config commands
- Add SingleFileConfig struct for single-file loading (closest-wins semantics)
- Add load_single_file() function that loads only one config file
- Export new types from config module
- Supports config validate and config show commands
* feat(05-02): implement config validate and show commands
- Add config::validate() with Unix-style quiet success
- Add config::show() with colored output display
- Implement closest-wins semantics via effective_config_path()
- Validate YAML syntax, known fields, and source file existence
- Show respects NO_COLOR environment variable
* feat(05-02): wire up config validate and show in main.rs
- Replace TODO placeholders with actual command implementations
- Use map_err pattern for correct exit code propagation
- Config commands now fully functional end-to-end
* docs(05-02): complete config validate and show plan
Tasks completed: 3/3
- Add load_single_file to config loader
- Implement config validate and show commands
- Wire up config subcommands in main.rs
SUMMARY: .planning/phases/05-config-commands/05-02-SUMMARY.md
* docs(05): complete config-commands phase
All phase requirements verified:
- CMD-01: lazytail init creates starter config
- CMD-02: lazytail config validate checks config errors
- CMD-03: lazytail config show displays effective config
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: update Cargo.lock for colored dependency
* fix(tab): set config_source_type from discovered source location
* fix: address review issues from PR review
- Replace process::exit() in map_err with anyhow error propagation
- Remove unused re-exports (discover_verbose, ConfigError) from config/mod.rs
- Gate test-only functions with #[cfg(test)] (ensure_directories, create_marker, has_sources)
* fix: resolve clippy warnings treated as errors in CI
- Gate test-only methods data_dir() and has_config() with #[cfg(test)]
- Allow dead_code on ConfigError::Validation variant (reserved for future use)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>1 parent aebf10d commit 5ffb3f7
File tree
67 files changed
+14442
-120
lines changed- .planning
- codebase
- phases
- 01-signal-infrastructure
- 02-config-discovery
- 03-config-loading
- 04-project-local-streams
- 05-config-commands
- research
- src
- cmd
- config
- filter
- ui
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
67 files changed
+14442
-120
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
0 commit comments