Commit c4127de
authored
feat(cli): add CLI with CI convenience functions (#394)
* feat(cli): add CLI with CI convenience functions for NiFi automation
- Add nipyapi CLI with 'ci' subcommand for NiFi CI/CD operations
- Profile auto-resolution: switch() without args auto-detects env vars or profile file
- CI functions: deploy_flow, start_flow, stop_flow, get_status, cleanup, configure_params
- New functions: configure_inherited_params, purge_flowfiles, upload_asset
- get_status defaults to root process group when no PG specified
- Log control via NIFI_LOG_LEVEL and NIFI_LOG_ON_ERROR env vars
- Suppress SSL warnings to keep CI output clean
- Convert snake_case to kebab-case for GitHub Actions output format
- resolve_git_ref to resolve tags/branches to SHAs
* feat: add layout module, CLI enhancements, and improve test infrastructure
Layout Module:
- New nipyapi/layout.py with intelligent canvas positioning
- Process group grid alignment (align_pg_grid, suggest_pg_position)
- Flow layout functions (below, above, right_of, left_of, fork, new_flow)
- Component movement with self-loop bend handling
- Flow transposition and de-overlap capabilities
- Spine/branch detection for flow restructuring (find_flow_spine, get_side_branches)
- Automated flow layout (suggest_flow_layout)
Canvas Enhancements:
- get_flow_components() for graph traversal of connected components
- Automatic bend calculation for self-loop connections
- Bends parameter support in create_connection()
CLI Improvements:
- Expose layout functions via CLI (align_pg_grid, suggest_pg_position, etc.)
- SafeModule wrapper for structured error handling
- Custom serializer for formatted output
Client Generation:
- Add octet-stream handler to rest.mustache template
- Regenerate NiFi and Registry clients with binary upload support
Profile System:
- Fix get_default_profile_name() to honor NIPYAPI_PROFILES_FILE env var
- Improve profile resolution order for testing isolation
CI Module:
- Fix purge_flowfiles.py to use detail='all' for process group status
Test Infrastructure:
- Add NIPYAPI_PROFILES_FILE to Makefile for test isolation
- Update conftest.py to use env var for profiles path
- Add comprehensive tests for layout, CLI, CI, canvas, and parameters
- 332 tests passing, lint clean (10.00/10)
* fix: remove switch() from CI functions to prevent profile override
- CI functions no longer call profiles.switch() internally
- Profile configuration is now solely the responsibility of the caller
- CLI main() handles switch() with --profile arg or auto-resolution
- Fixes bug where --profile flag was ignored by CI commands
Also includes:
- Add --profile CLI option for explicit profile selection
- Add NIPYAPI_PROFILE env var support in switch() auto-resolution
- Update profiles.rst documentation
- Add tests for new profile resolution behavior
* fix: regenerate clients with basicAuth and fix Python 3.9 test
- Regenerate NiFi and Registry clients from augmented OpenAPI specs
- Restore basicAuth in Registry configuration.py and access_api.py
- Fix mock patch path in test_ci.py for Python 3.9 compatibility
(use @patch('requests.get') instead of module path)
* fix(ci): select token env var based on provider
The ensure_registry function was resolving the token before determining
the provider, always preferring GH_REGISTRY_TOKEN regardless of whether
gitlab was specified. This caused GitLab deployments to fail when both
tokens were set.
Now resolves provider first, then selects the appropriate token:
- gitlab: GL_REGISTRY_TOKEN first, fallback to GH_REGISTRY_TOKEN
- github: GH_REGISTRY_TOKEN first, fallback to GL_REGISTRY_TOKEN
* style(tests): use urlparse for hostname assertion
Replace string 'in' check with urlparse().hostname for cleaner URL validation.
* test: improve coverage for cli, profiles, and ci modules
CLI coverage: 62% -> 81%
- Add tests for list serialization, heredoc format, _to_dict methods
- Add tests for _parse_profile_arg function
- Add tests for SafeModule error handling and log level inclusion
Profiles coverage: 68% -> 74%
- Add tests for unicode error handling in properties files
- Add tests for get_default_profile_name edge cases
CI coverage: 50% -> 58%
- ensure_registry: 17% -> 95% (validation + token priority tests)
- deploy_flow: 17% -> 61% (validation tests)
- configure_params: 27% -> 49% (JSON validation tests)
Overall coverage: 66% -> 69%
* docs: add comprehensive CLI and CI documentation
CLI documentation (cli.rst):
- Installation options (pip, uv, uvx)
- Configuration (env vars, profiles, priority)
- Discovering commands with --help
- All available modules with API reference links
- Output formatting (JSON, GitHub Actions, GitLab)
- Note that low-level nifi/registry APIs not exposed
CI documentation (ci.rst):
- All 14 CI operations with full parameter tables
- configure_inherited_params for inheritance-aware updates
- resolve_git_ref utility function
- Environment variable reference
- Complete workflow examples (shell, GitHub, GitLab, Python)
Other changes:
- Fix test_safe_module_error_handling for CI environments
- Fix security.rst title (was incorrectly 'NiPyAPI 2')
- Add layout module to core_modules docs
- Update dependencies list
* test: improve coverage for CI, parameters, layout modules and fix test isolation
Add integration tests against real NiFi for better coverage:
test_ci.py:
- configure_inherited_params: 10 tests (validation + integration)
- upload_asset: 8 tests (file path, PG resolution, param linking)
test_parameters.py:
- get_parameter_context_hierarchy: 3 tests
- get_parameter_ownership_map: 2 tests
- update_parameter_in_context: 4 tests
test_layout.py:
- move_port: 3 tests (input, output, no-refresh)
- move_component with port: 1 test
- snap_position, get_pg_grid_position, left_of, check_overlap: 5 tests
test_versioning.py:
- Fix test isolation: wait for async revert to complete in
test_revert_flow_ver_wait_false before test ends, preventing
revision conflicts in subsequent tests using same fixture
* feat(ci): add version control CI functions and helpers
New CI functions:
- commit_flow: save flow to version control (initial or subsequent)
- get_flow_versions: list version history for a flow
- detach_flow: remove version control (for forking workflows)
- get_flow_diff: get local modifications to a versioned flow
Renames for consistency:
- change_version -> change_flow_version
- get_versions -> list_flows
New versioning helper:
- get_local_modifications: helper for fetching local changes
Improvements:
- list_flows: use nipyapi.utils.getenv_bool for env var parsing
- list_flows: use nipyapi.canvas.get_flow helper instead of direct API
- save_git_flow_ver: accept string process group ID
Tests:
- Added comprehensive tests for all new CI functions
- Fixed flaky versioning tests with proper state handling
- Improved test isolation in shared fixtures
* feat(ci): add export_flow_definition and import_flow_definition commands
- Add export_flow_definition CI function for exporting process groups to files
- Add import_flow_definition CI function for importing flow definitions from files
- Support JSON and YAML formats for export
- Add include_referenced_services option to include external controller services
- Use smart positioning (suggest_pg_position) when import location not provided
- Add 10 tests covering validation, roundtrip export/import, and file operations
* feat(extensions): add NAR management with defensive lifecycle handling
- Add nipyapi.extensions module for NAR upload, delete, download
- Add Python processor initialization status and wait functions
- Add processor bundle version management for multi-version NARs
- Implement defensive delete_nar with initialization guard and cleanup wait
- Implement two-phase upload_nar wait (install + processor discovery)
- Fix canvas.create_processor to include bundle for multi-version support
- Add programmatic NAR generation for testing (create_test_nar)
- Add comprehensive tests for extension operations
- Add extensions operations guide (docs/extensions.rst) covering NAR lifecycle,
Python processor initialization, version management, and troubleshooting
* fix(cli): quote dotenv values containing special characters
Values with spaces, pipes, brackets, and other shell special characters
are now properly quoted in dotenv output format. This prevents export
failures when values contain characters like | [ ] that break shell parsing.
Embedded double quotes are escaped with backslash.
* feat(parameters): enhance get_parameter_context_hierarchy with bindings and optional parameters
- Add include_bindings parameter to include bound_process_groups for each context
- Add include_parameters parameter to optionally exclude parameter details
- Add description field to parameter output for better context
- Add tests for new functionality including transitive binding behavior
- Useful for cleanup workflows and parameter inspection during deployment
* feat(cli): add --version and verbosity flags
- Add --version/-V flags to display version and exit
- Add -v/-vv/-vvv flags to control log verbosity
- Refactor _parse_profile_arg to _parse_cli_flags for combined parsing
- Add _apply_verbosity to set NIFI_LOG_LEVEL from verbosity count
- Add comprehensive unit tests for flag parsing
- Add integration tests for version output
* feat(canvas): allow create_process_group to accept pg_id string
- Accept either a string ID or ProcessGroupEntity for parent_pg parameter
- Maintains backward compatibility with existing code using entities
- Raises TypeError with clear message for invalid types
- Supports 'root' as parent_pg for creating PGs on root canvas
- Add tests for string ID, UUID string, and invalid type cases
* feat: add list_registry_flows CI function and improve registry client handling
Registry client improvements:
- versioning.get_registry_client: add greedy parameter (default True for compat)
- ci.deploy_flow: accept registry client name or ID, add greedy param
- ci.list_registry_flows: new function to list flows in registry bucket
Canvas improvements:
- create_process_group: accept string ID or ProcessGroupEntity for parent_pg
- delete_remote_process_group: add force param to stop transmission before delete
- set_remote_process_group_transmission: wait for state change before returning
Test fixes:
- conftest: use force=True when cleaning up RPGs
- Add tests for greedy parameter and list_registry_flows validation
* fix: JSON-serialize lists in GitHub/GitLab CI output formats
Previously, lists nested within dict results were converted via str()
which produces Python repr format with single quotes. This is not valid
JSON and breaks downstream parsing.
Now lists and dicts at leaf positions are JSON-serialized with json.dumps()
producing valid JSON with double quotes.
Fixes output for: list_flows, list_registry_flows, get_flow_versions,
get_flow_diff, and any future CI functions returning list values.
Added tests for nested list serialization in both GitHub and dotenv formats.
* feat(ci): add is_uuid() utility and auto-detect registry client ID vs name
- Add is_uuid() function to nipyapi/utils.py for UUID format detection
- Update deploy_flow and list_registry_flows to auto-detect if registry_client is UUID (ID) or name
- Add comprehensive tests for is_uuid() in test_utils.py
- Update docstrings to document auto-detection behavior
* feat(layout): add connection management and improved bend handling
- Add get_connection() to fetch connection by ID or entity
- Add update_connection() with name/bends parameters (bends=[] clears)
- Add clear_flow_bends() to clear bends before flow reorganization
- Update get_flow_components() to return FlowSubgraph(components, connections)
- Add include_retry parameter to move_component/move_processor
- Refactor transpose_flow to handle all bends in single pass
- Add comprehensive tests for new functionality
* feat: add config verification functions and test optimizations
- Add nipyapi.canvas.verify_controller() for controller service verification
- Add nipyapi.canvas.verify_processor() for processor verification
- Add nipyapi.ci.verify_config() for batch verification of process groups
- Add refresh parameter to delete_controller and update_controller
- Improve delete_controller to accept ID or object
- Add PYTEST_ARGS support to Makefile test target
- Add fix_multi_version_nars module-scoped fixture for test optimization
- Remove useless @pytest.mark.usefixtures() decorator
- Extension tests now ~27% faster with shared NAR fixtures
* feat: add orphaned context cleanup and bulletin filtering
- Add list_orphaned_contexts() to parameters module for detecting
parameter contexts not bound to any process groups
- Enhance get_bulletin_board() with pg_id, source_name, message,
and limit filters for scoped bulletin retrieval
- Add delete_orphaned_contexts option to ci.cleanup() for safe
removal of unused parameter contexts after PG deletion
- Add comprehensive tests for all new functionality
Note: NiFi does not provide an API to clear bulletins in 2.6.0.
Clear bulletins API was introduced in 2.7.0 - upgrade planned separately.
* feat(bulletins): add bulletin management module with NiFi 2.7.0+ clearing
New nipyapi.bulletins module:
- get_bulletins(): controller-level bulletins
- get_bulletin_board(): filtered bulletins returning BulletinDTO directly
- clear_*_bulletins(): component-specific clearing (10 functions)
- clear_all_bulletins(): high-level helper for CI
Additional changes:
- nipyapi.profiles: add list_profiles, show, current commands
- nipyapi.utils: add format_timestamp utility
- nipyapi.ci.get_status: fix to capture controller service bulletins
- nipyapi.canvas: bulletin functions now alias to bulletins module
- Makefile: intelligent uv/pip detection
- docs: updated contributing guide, module documentation
* feat(canvas): add component state management functions
- Add get_processor_state and clear_processor_state for processor state inspection
- Add get_controller_state and clear_controller_state for controller service state
- All functions accept entity objects or ID strings
- Fix CLI --help flag handling in SafeModule wrapper
- Remove unused LogCapture.all_records attribute
- Add fix_state_flow test fixture with MapCacheServer and ListFile
- Add comprehensive tests for state operations
* feat(ci): add parameter export/import and VCS parameter handling
- Add export_parameters CI command for exporting parameter values
- Add --parameters_file option to configure_inherited_params for file-based import
- Add parameter_context_handling option to deploy_git_registry_flow for VCS
- Add deploy_flow CI command parameter_context_handling support
- Fix test fixture isolation to prevent shared fixtures being deleted
- Fix parameter context cleanup version check logic
- Add ACTIVE_PROFILES_PATH for consistent profile file handling
- Add parameter inheritance tests for VCS deployments
* test: add comprehensive CLI JSON input/output serialization tests
Add 43 new tests for CLI handling of complex JSON objects:
- 19 JSON input parsing tests (quotes, newlines, backslashes, nested
structures, Unicode, null/empty values, mixed types)
- 4 roundtrip tests (serialize -> parse verification)
- 8 CLI subprocess tests (verify JSON passes through CLI correctly)
- 12 CI function tests for configure_params complex inputs
These tests verify AI agents can use the nipyapi CLI directly for
common operations without needing to write Python code for complex
parameter structures.
* fix(tests): force JSON output format in CLI subprocess tests
In GitHub Actions CI, GITHUB_ACTIONS=true causes the CLI to
auto-detect 'github' output format (key=value), but the tests
expect JSON output for parsing. Force NIFI_OUTPUT_FORMAT=json
in the subprocess environment to ensure consistent JSON output.
Fixes JSONDecodeError in configure_params CLI tests.
* docs: comprehensive docstring and documentation revision
- Create AGENTS.md for AI agent guidance (consuming/contributing sections)
- Update contributing.rst with docstring standards and discovery patterns
- Fix all 51 Sphinx docstring warnings (nested lists, Example formatting)
- Standardize Example:: format across 91 instances with required blank lines
- Fix RST title underlines in ci.rst, security.rst
- Add cross-reference notation guidance for Sphinx
- Add module intent comments to __init__.py
* feat(canvas): add get_processor_docs() and enhance schedule_processor()
New features:
- get_processor_docs(processor): retrieve full processor documentation including
property_descriptors, tags, use cases. Accepts ProcessorEntity, DocumentedTypeDTO,
or processor type name string.
- schedule_processor() enhancements:
- Now accepts processor ID string or ProcessorEntity object
- Supports all processor states: RUNNING, STOPPED, DISABLED, RUN_ONCE
- Uses direct processor API for reliable state transitions
- Backwards compatible: bool values still work (True=RUNNING, False=STOPPED)
Client fixes:
- Add nifi_processor_state_enum.py augmentation to fix upstream NiFi OpenAPI bug
where ProcessorDTO.state enum was missing transitional states
Testing improvements:
- Add pytest filterwarnings config to suppress InsecureRequestWarning in tests
- Add comprehensive tests for new functionality
Docs:
- Minor AGENTS.md improvement: venv activation reminder
* Add FlowFile inspection helpers and enhance fs_write for binary mode
- nipyapi.canvas: Add list_flowfiles, get_flowfile_details, get_flowfile_content, peek_flowfiles
- get_flowfile_content supports decode options (auto/text/bytes) and output_file saving
- nipyapi.utils.fs_write: Add binary=False parameter for raw byte writing (backwards compatible)
- Tests: Add test_fs_write_binary, expand test_get_flowfile_content coverage
* Address Copilot review feedback
- Extract NiFi Registry functions to nipyapi.nifi_registry module
with backwards-compatible shims in versioning.py
- Replace global cache with @lru_cache in conftest.py
- Clarify switch() usage in profiles.py error message
- Document UUID format-only validation in utils.py
- Fix URL validation in test_ci.py (use urlparse for hostname check)
* Fix cluster_node_id handling, remove fail_on_error, improve CLI docstrings
Bug fixes:
- canvas.py: Add _resolve_flowfile_cluster_node() helper for clustered NiFi
- canvas.py: get_flowfile_details/get_flowfile_content auto-resolve cluster_node_id
- canvas.py: peek_flowfiles preserves cluster_node_id from FlowFileSummaryDTO
- canvas.py: create_processor accepts string ID or ProcessGroupEntity
- verify_config.py: Remove fail_on_error param (always return result dict)
CLI improvements:
- cli.py: Use functools.wraps for proper signature preservation in fire
- canvas.py, layout.py, utils.py: Inline docstring format for CLI compatibility
Documentation:
- contributing.rst: Add CLI-specific docstring guidance
Tests:
- test_canvas.py: Add tests for cluster_node_id handling
- test_ci.py: Update tests for verify_config changes
* docs: Add CLI boolean parameter gotcha to contributing guide
* fix: Use bulk disable instead of delete for controllers in force delete_process_group
Previously, force deletion would delete each controller service individually,
which was slow and caused version control to show local modifications.
Now uses schedule_all_controllers() to bulk disable, which is faster and
non-destructive.
* fix: Disable controllers in fix_state_flow cleanup before PG deletion
MapCacheServer binds to port 4557 and won't release it until disabled.
Without explicit cleanup, subsequent tests fail with 'Address already in use'
when trying to enable their own MapCacheServer.
Added finalizer to disable both server and client controllers before
fix_pg's finalizer runs to delete the process group.
* fix: schedule_all_controllers now waits for controllers to reach target state
Previously the function returned immediately after the API call, leaving
controllers in transitional states (ENABLING/DISABLING). This caused race
conditions in slower environments (e.g. Python 3.9) where callers would
check controller state before transitions completed.
Now uses wait_to_complete to poll until all controllers in the PG reach
the target state, consistent with schedule_controller behavior.
* docs: Prepare 1.2.0 release - CLI documentation and history1 parent b69632a commit c4127de
File tree
79 files changed
+22945
-653
lines changed- docs
- nipyapi-docs
- core_modules
- nifi_models
- registry_models
- scripts
- nipyapi
- ci
- nifi
- models
- registry
- resources/client_gen
- augmentations
- swagger_templates
- tests
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
79 files changed
+22945
-653
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 | + | |
| 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 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
8 | 13 | | |
9 | 14 | | |
10 | 15 | | |
11 | 16 | | |
12 | 17 | | |
13 | 18 | | |
14 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
15 | 32 | | |
16 | 33 | | |
17 | 34 | | |
| |||
107 | 124 | | |
108 | 125 | | |
109 | 126 | | |
110 | | - | |
111 | | - | |
| 127 | + | |
| 128 | + | |
112 | 129 | | |
113 | 130 | | |
114 | 131 | | |
| |||
141 | 158 | | |
142 | 159 | | |
143 | 160 | | |
144 | | - | |
| 161 | + | |
145 | 162 | | |
146 | 163 | | |
147 | | - | |
| 164 | + | |
148 | 165 | | |
149 | 166 | | |
150 | | - | |
| 167 | + | |
151 | 168 | | |
152 | 169 | | |
153 | 170 | | |
154 | 171 | | |
155 | 172 | | |
156 | 173 | | |
157 | 174 | | |
158 | | - | |
| 175 | + | |
159 | 176 | | |
160 | 177 | | |
161 | 178 | | |
| |||
181 | 198 | | |
182 | 199 | | |
183 | 200 | | |
184 | | - | |
| 201 | + | |
185 | 202 | | |
186 | 203 | | |
187 | 204 | | |
| |||
244 | 261 | | |
245 | 262 | | |
246 | 263 | | |
247 | | - | |
| 264 | + | |
248 | 265 | | |
249 | 266 | | |
250 | 267 | | |
| |||
272 | 289 | | |
273 | 290 | | |
274 | 291 | | |
275 | | - | |
| 292 | + | |
276 | 293 | | |
277 | | - | |
| 294 | + | |
278 | 295 | | |
279 | 296 | | |
280 | 297 | | |
| |||
288 | 305 | | |
289 | 306 | | |
290 | 307 | | |
291 | | - | |
292 | | - | |
293 | | - | |
294 | | - | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
295 | 313 | | |
296 | 314 | | |
297 | 315 | | |
| |||
345 | 363 | | |
346 | 364 | | |
347 | 365 | | |
348 | | - | |
| 366 | + | |
349 | 367 | | |
350 | 368 | | |
351 | 369 | | |
| |||
0 commit comments