python-fx 0.3.1__tar.gz → 0.4.0__tar.gz
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.
- {python-fx-0.3.1 → python_fx-0.4.0}/CHANGELOG.md +10 -1
- python_fx-0.4.0/CLAUDE.md +121 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/PKG-INFO +28 -23
- {python-fx-0.3.1 → python_fx-0.4.0}/README.md +7 -3
- python_fx-0.4.0/dev-requirements.txt +81 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/pyproject.toml +21 -2
- python_fx-0.4.0/requirements.txt +15 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/setup.cfg +1 -1
- python_fx-0.4.0/src/pyfx/__version__.py +1 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/app.py +40 -7
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/autocomplete/autocomplete_listener.py +3 -1
- python_fx-0.4.0/src/pyfx/model/common/jsonpath/JSONPath.interp +67 -0
- python_fx-0.4.0/src/pyfx/model/common/jsonpath/JSONPathLexer.interp +78 -0
- python_fx-0.4.0/src/pyfx/model/common/jsonpath/JSONPathLexer.py +108 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPathListener.py +8 -13
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPathParser.py +146 -225
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/model.py +7 -1
- python_fx-0.4.0/src/pyfx/model/model_manager.py +210 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/frame.py +4 -3
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/selectable_text.py +1 -1
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/view_manager.py +2 -4
- {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/PKG-INFO +28 -23
- {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/SOURCES.txt +2 -0
- python_fx-0.4.0/src/python_fx.egg-info/requires.txt +17 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/tox.ini +5 -4
- python-fx-0.3.1/dev-requirements.txt +0 -82
- python-fx-0.3.1/requirements.txt +0 -17
- python-fx-0.3.1/src/pyfx/__version__.py +0 -1
- python-fx-0.3.1/src/pyfx/model/common/jsonpath/JSONPath.interp +0 -67
- python-fx-0.3.1/src/pyfx/model/common/jsonpath/JSONPathLexer.interp +0 -78
- python-fx-0.3.1/src/pyfx/model/common/jsonpath/JSONPathLexer.py +0 -126
- python-fx-0.3.1/src/python_fx.egg-info/requires.txt +0 -31
- {python-fx-0.3.1 → python_fx-0.4.0}/.coveragerc +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/.readthedocs.yml +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/CODE_OF_CONDUCT.md +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/LICENSE.txt +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/MANIFEST.in +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/docs/Makefile +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/docs/conf.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/docs/demo.gif +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/docs/index.rst +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/docs/make.bat +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/setup.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/cli.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/cli_utils.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/config.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/config_parser.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/config.yml +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/config_schema.yml +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/basic.yml +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/emacs.yml +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/vim.yml +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/themes/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/themes/basic.yml +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/error.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/autocomplete/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPath.g4 +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPath.tokens +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPathLexer.tokens +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/service/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/service/client.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/service/dispatcher.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/popup.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/abstract_component_keys.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/autocomplete_popup.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/help_popup.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/json_browser.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/query_bar.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/warning_bar.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_end_node.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_end_widget.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_node.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_start_widget.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_unexpanded_widget.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_composite_end_node.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_composite_node.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_listbox.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_listwalker.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_node_creator.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_node_factory.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_simple_node.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_widget.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_end_node.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_end_widget.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_node.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_start_widget.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_unexpanded_widget.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/__init__.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/base.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/boolean.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/integer.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/null.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/numeric.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/string.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/keys.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/themes.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/view_frame.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/view_mediator.py +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/dependency_links.txt +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/entry_points.txt +0 -0
- {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/top_level.txt +0 -0
|
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
|
+
### Changed
|
|
10
|
+
- Allow dynamic versions for dependency
|
|
11
|
+
- Remove support for python 3.8
|
|
12
|
+
|
|
13
|
+
## [0.3.2] - 2024-08-12
|
|
14
|
+
### Changed
|
|
15
|
+
- Bump all dependent libraries' version
|
|
16
|
+
- Bump ANTLR version and regenerate parser code
|
|
9
17
|
|
|
10
18
|
## [0.3.1] - 2023-09-24
|
|
11
19
|
### Changed
|
|
@@ -114,7 +122,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
114
122
|
|
|
115
123
|
- Initial commit with pyfx
|
|
116
124
|
|
|
117
|
-
[unreleased]: https://github.com/cielong/pyfx/compare/v0.3.
|
|
125
|
+
[unreleased]: https://github.com/cielong/pyfx/compare/v0.3.1...HEAD
|
|
126
|
+
[0.3.2]: https://github.com/cielong/pyfx/compare/v0.3.1...v0.3.2
|
|
118
127
|
[0.3.1]: https://github.com/cielong/pyfx/compare/v0.3.0...v0.3.1
|
|
119
128
|
[0.3.0]: https://github.com/cielong/pyfx/compare/v0.2.0...v0.3.0
|
|
120
129
|
[0.2.0]: https://github.com/cielong/pyfx/compare/v0.1.0...v0.2.0
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
Pyfx is a Python-native JSON viewer TUI (Terminal User Interface) inspired by fx. It provides an interactive terminal-based interface for browsing and querying JSON data with JSONPath support.
|
|
8
|
+
|
|
9
|
+
## Development Commands
|
|
10
|
+
|
|
11
|
+
### Core Development Workflow
|
|
12
|
+
- `make install` - Full build pipeline: clean, lint, test, build, and install
|
|
13
|
+
- `make build` - Build the project (includes clean, lint, test)
|
|
14
|
+
- `make test` - Run all tests via tox (includes clean, lint)
|
|
15
|
+
- `make lint` - Format code with autopep8
|
|
16
|
+
- `make clean` - Remove build artifacts
|
|
17
|
+
|
|
18
|
+
### Testing
|
|
19
|
+
- `tox` - Run tests across multiple Python versions (3.8-3.11)
|
|
20
|
+
- `tox -e py311` - Run tests for specific Python version
|
|
21
|
+
- `tox -e style_check` - Run flake8 style checks
|
|
22
|
+
- `pytest` - Run tests directly (after installing dev dependencies)
|
|
23
|
+
- `pytest --cov=pyfx --cov-report=term-missing` - Run tests with coverage
|
|
24
|
+
|
|
25
|
+
### Dependency Management
|
|
26
|
+
- `pipenv install --dev` - Install development dependencies
|
|
27
|
+
- `pipenv requirements > requirements.txt` - Update requirements.txt
|
|
28
|
+
- `make lock` - Generate both requirements.txt and dev-requirements.txt
|
|
29
|
+
|
|
30
|
+
### Installation and Running
|
|
31
|
+
- `pip install python-fx` - Install from PyPI
|
|
32
|
+
- `pyfx data.json` - Open JSON file
|
|
33
|
+
- `cat data.json | pyfx` - Read JSON from pipe
|
|
34
|
+
- `pyfx -x` - Read JSON from clipboard
|
|
35
|
+
- `pyfx --debug` - Enable debug logging
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
### High-Level Architecture
|
|
40
|
+
Pyfx follows an MVC-like pattern with additional service and mediator layers:
|
|
41
|
+
|
|
42
|
+
- **Model** (`src/pyfx/model/`) - Data processing and JSONPath queries
|
|
43
|
+
- **View** (`src/pyfx/view/`) - UI components built on urwid
|
|
44
|
+
- **Service** (`src/pyfx/service/`) - Business logic dispatcher and client
|
|
45
|
+
- **Config** (`src/pyfx/config/`) - Configuration management (themes, keymaps)
|
|
46
|
+
|
|
47
|
+
### Key Components
|
|
48
|
+
|
|
49
|
+
#### App Layer (`app.py`)
|
|
50
|
+
- `PyfxApp` - Main application entry point and dependency injection container
|
|
51
|
+
- Orchestrates all components and manages the UI lifecycle
|
|
52
|
+
|
|
53
|
+
#### Model Layer
|
|
54
|
+
- `Model` - Handles JSONPath queries and autocomplete functionality
|
|
55
|
+
- `autocomplete/` - JSONPath query autocompletion logic
|
|
56
|
+
|
|
57
|
+
#### View Layer
|
|
58
|
+
- **Core UI Framework**:
|
|
59
|
+
- `ViewFrame` - Main window frame management
|
|
60
|
+
- `ViewMediator` - Component communication mediator
|
|
61
|
+
- `View` - urwid MainLoop wrapper
|
|
62
|
+
|
|
63
|
+
- **Components** (`view/components/`):
|
|
64
|
+
- `JSONBrowser` - Main JSON tree viewer
|
|
65
|
+
- `QueryBar` - JSONPath query input
|
|
66
|
+
- `AutoCompletePopUp` - Query autocompletion popup
|
|
67
|
+
- `HelpPopUp` - Help system
|
|
68
|
+
- `WarningBar` - Error/warning display
|
|
69
|
+
|
|
70
|
+
- **JSON Rendering** (`view/json_lib/`):
|
|
71
|
+
- `JSONNodeFactory` - Creates appropriate widgets for JSON types
|
|
72
|
+
- `array/`, `object/`, `primitive/` - Type-specific rendering logic
|
|
73
|
+
- `JSONListBox`, `JSONListWalker` - Core list display widgets
|
|
74
|
+
|
|
75
|
+
#### Service Layer
|
|
76
|
+
- `Dispatcher` - Message routing between components
|
|
77
|
+
- `Client` - Async operation handling with ThreadPoolExecutor
|
|
78
|
+
|
|
79
|
+
#### Configuration System
|
|
80
|
+
- YAML-based configuration for themes and keymaps
|
|
81
|
+
- Predefined configurations: `basic`, `emacs`, `vim` keymaps
|
|
82
|
+
- Theme system with customizable colors for JSON types
|
|
83
|
+
|
|
84
|
+
### Data Flow
|
|
85
|
+
1. CLI loads JSON data from file/pipe/clipboard
|
|
86
|
+
2. `PyfxApp` initializes all components with dependency injection
|
|
87
|
+
3. `Model` processes JSONPath queries against data
|
|
88
|
+
4. `ViewMediator` coordinates communication between UI components
|
|
89
|
+
5. `JSONBrowser` renders JSON using type-specific widgets from `json_lib`
|
|
90
|
+
6. User interactions trigger events through `KeyMapper` and `Dispatcher`
|
|
91
|
+
|
|
92
|
+
### Key Design Patterns
|
|
93
|
+
- **Mediator Pattern**: `ViewMediator` decouples component communication
|
|
94
|
+
- **Factory Pattern**: `JSONNodeFactory` creates appropriate widgets
|
|
95
|
+
- **Command Pattern**: `Dispatcher` handles service requests
|
|
96
|
+
- **Observer Pattern**: Components register with mediator for updates
|
|
97
|
+
|
|
98
|
+
## Development Notes
|
|
99
|
+
|
|
100
|
+
### ANTLR Grammar
|
|
101
|
+
- JSONPath parsing uses ANTLR v4 grammar (`model/common/jsonpath/JSONPath.g4`)
|
|
102
|
+
- Generated parsers are committed to avoid build dependencies
|
|
103
|
+
- ANTLR version must match Python runtime version
|
|
104
|
+
|
|
105
|
+
### Testing Structure
|
|
106
|
+
- `tests/unit_tests/` - Component-level unit tests
|
|
107
|
+
- `tests/intergration_tests/` - Integration tests for UI interactions
|
|
108
|
+
- `tests/e2e_tests/` - End-to-end CLI testing
|
|
109
|
+
- `tests/fixtures/` - Test data and configuration files
|
|
110
|
+
|
|
111
|
+
### Urwid Framework
|
|
112
|
+
- Built on urwid for terminal UI
|
|
113
|
+
- Custom widgets extend urwid base classes
|
|
114
|
+
- Keyboard input handled through urwid's event system
|
|
115
|
+
- Screen management for proper terminal control
|
|
116
|
+
|
|
117
|
+
### Configuration
|
|
118
|
+
- Default config location: `~/.config/pyfx/config.yml`
|
|
119
|
+
- Fallback to: `src/pyfx/config/yaml/config.yml`
|
|
120
|
+
- Supports custom themes and keymaps
|
|
121
|
+
- YAML schema validation with yamale
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: python-fx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A python-native fx-alike terminal JSON viewer.
|
|
5
5
|
Author-email: Yutian Wu <yutianwu@umich.edu>
|
|
6
6
|
License: MIT
|
|
@@ -13,32 +13,32 @@ Classifier: Operating System :: POSIX
|
|
|
13
13
|
Classifier: Operating System :: MacOS :: MacOS X
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
15
|
Classifier: Topic :: Utilities
|
|
16
|
-
Requires-Python: >=3.
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE.txt
|
|
19
|
-
Requires-Dist: antlr4-python3-runtime
|
|
20
|
-
Requires-Dist: asciimatics
|
|
21
|
-
Requires-Dist: click
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-Dist:
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist: urwid
|
|
34
|
-
Requires-Dist: wcwidth
|
|
35
|
-
Requires-Dist: yamale
|
|
19
|
+
Requires-Dist: antlr4-python3-runtime<5,>=4.13
|
|
20
|
+
Requires-Dist: asciimatics<2,>=1.15
|
|
21
|
+
Requires-Dist: click<9,>=8.1.7
|
|
22
|
+
Requires-Dist: first<3,==2.0
|
|
23
|
+
Requires-Dist: dacite<2,==1.8
|
|
24
|
+
Requires-Dist: jsonpath-ng<2,==1.6
|
|
25
|
+
Requires-Dist: loguru<0.8,>=0.7.2
|
|
26
|
+
Requires-Dist: overrides<8,>=7.7.0
|
|
27
|
+
Requires-Dist: pillow<11,>=10.4
|
|
28
|
+
Requires-Dist: ply<4,>=3.11
|
|
29
|
+
Requires-Dist: pyfiglet<2,>=1.0
|
|
30
|
+
Requires-Dist: pyperclip>=1.9
|
|
31
|
+
Requires-Dist: pyyaml<7,>=6.0.2
|
|
32
|
+
Requires-Dist: typing-extensions<5,>=4.12.2
|
|
33
|
+
Requires-Dist: urwid<3,>=2.6
|
|
34
|
+
Requires-Dist: wcwidth<0.3,>=0.2.13
|
|
35
|
+
Requires-Dist: yamale<6,>=5.2
|
|
36
|
+
Dynamic: license-file
|
|
36
37
|
|
|
37
38
|
# Pyfx
|
|
38
39
|

|
|
39
40
|

|
|
40
41
|

|
|
41
|
-

|
|
42
42
|

|
|
43
43
|

|
|
44
44
|

|
|
@@ -69,7 +69,7 @@ A python-native JSON Viewer TUI, inspired by [fx](https://github.com/antonmedv/f
|
|
|
69
69
|
|
|
70
70
|
## Prerequisites
|
|
71
71
|
* OS: MacOS / Linux
|
|
72
|
-
* python: >= 3.
|
|
72
|
+
* python: >= 3.9
|
|
73
73
|
* pip
|
|
74
74
|
|
|
75
75
|
## Installation
|
|
@@ -84,7 +84,11 @@ pip install -U autopep8 tox build
|
|
|
84
84
|
make install
|
|
85
85
|
```
|
|
86
86
|
### Local Development
|
|
87
|
-
|
|
87
|
+
1. Download and install the latest [ANTLR v4](https://www.antlr.org/)
|
|
88
|
+
|
|
89
|
+
* It is required that ANTLR version installed matches the version of the Python ANTLR runtime version.
|
|
90
|
+
|
|
91
|
+
2. Clone the this [repo](https://github.com/cielong/pyfx.git), change directory into the project and run
|
|
88
92
|
```bash
|
|
89
93
|
pip install -U pipenv
|
|
90
94
|
pipenv install --dev
|
|
@@ -220,6 +224,7 @@ See the [changelog](CHANGELOG.md) for a history of notable changes to *Pyfx*.
|
|
|
220
224
|
## Contributors
|
|
221
225
|
[Avery (@nullableVoidPtr)](https://github.com/nullableVoidPtr)
|
|
222
226
|
[Zephyr Lykos (@mochaaP)](https://github.com/mochaaP)
|
|
227
|
+
[@jcaesar](https://github.com/jcaesar)
|
|
223
228
|
|
|
224
229
|
## How to Contribute
|
|
225
230
|
If you run into any issues, please let me know by creating a GitHub issue.
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|

|
|
3
3
|

|
|
4
4
|

|
|
5
|
-

|
|
6
5
|

|
|
7
6
|

|
|
8
7
|

|
|
@@ -33,7 +32,7 @@ A python-native JSON Viewer TUI, inspired by [fx](https://github.com/antonmedv/f
|
|
|
33
32
|
|
|
34
33
|
## Prerequisites
|
|
35
34
|
* OS: MacOS / Linux
|
|
36
|
-
* python: >= 3.
|
|
35
|
+
* python: >= 3.9
|
|
37
36
|
* pip
|
|
38
37
|
|
|
39
38
|
## Installation
|
|
@@ -48,7 +47,11 @@ pip install -U autopep8 tox build
|
|
|
48
47
|
make install
|
|
49
48
|
```
|
|
50
49
|
### Local Development
|
|
51
|
-
|
|
50
|
+
1. Download and install the latest [ANTLR v4](https://www.antlr.org/)
|
|
51
|
+
|
|
52
|
+
* It is required that ANTLR version installed matches the version of the Python ANTLR runtime version.
|
|
53
|
+
|
|
54
|
+
2. Clone the this [repo](https://github.com/cielong/pyfx.git), change directory into the project and run
|
|
52
55
|
```bash
|
|
53
56
|
pip install -U pipenv
|
|
54
57
|
pipenv install --dev
|
|
@@ -184,6 +187,7 @@ See the [changelog](CHANGELOG.md) for a history of notable changes to *Pyfx*.
|
|
|
184
187
|
## Contributors
|
|
185
188
|
[Avery (@nullableVoidPtr)](https://github.com/nullableVoidPtr)
|
|
186
189
|
[Zephyr Lykos (@mochaaP)](https://github.com/mochaaP)
|
|
190
|
+
[@jcaesar](https://github.com/jcaesar)
|
|
187
191
|
|
|
188
192
|
## How to Contribute
|
|
189
193
|
If you run into any issues, please let me know by creating a GitHub issue.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
alabaster==1.0.0; python_version >= '3.10'
|
|
2
|
+
autopep8==2.3.1; python_version >= '3.8'
|
|
3
|
+
babel==2.18.0; python_version >= '3.8'
|
|
4
|
+
backports.tarfile==1.2.0; python_version >= '3.8'
|
|
5
|
+
build==1.4.0; python_version >= '3.9'
|
|
6
|
+
cachetools==7.0.5; python_version >= '3.10'
|
|
7
|
+
certifi==2026.2.25; python_version >= '3.7'
|
|
8
|
+
charset-normalizer==3.4.6; python_version >= '3.7'
|
|
9
|
+
click==8.3.1; python_version >= '3.10'
|
|
10
|
+
colorama==0.4.6; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'
|
|
11
|
+
coverage[toml]==7.13.5; python_version >= '3.10'
|
|
12
|
+
distlib==0.4.0
|
|
13
|
+
docutils==0.22.4; python_version >= '3.9'
|
|
14
|
+
filelock==3.25.2; python_version >= '3.10'
|
|
15
|
+
flake8==7.1.1; python_full_version >= '3.8.1'
|
|
16
|
+
id==1.6.1; python_version >= '3.9'
|
|
17
|
+
idna==3.11; python_version >= '3.8'
|
|
18
|
+
imagesize==2.0.0; python_version >= '3.10' and python_version < '3.15'
|
|
19
|
+
importlib-metadata==8.7.1; python_version >= '3.9'
|
|
20
|
+
iniconfig==2.3.0; python_version >= '3.10'
|
|
21
|
+
jaraco.classes==3.4.0; python_version >= '3.8'
|
|
22
|
+
jaraco.context==6.1.1; python_version >= '3.9'
|
|
23
|
+
jaraco.functools==4.4.0; python_version >= '3.9'
|
|
24
|
+
jinja2==3.1.6; python_version >= '3.7'
|
|
25
|
+
keyring==25.7.0; python_version >= '3.9'
|
|
26
|
+
markdown-it-py==4.0.0; python_version >= '3.10'
|
|
27
|
+
markupsafe==3.0.3; python_version >= '3.9'
|
|
28
|
+
mccabe==0.7.0; python_version >= '3.6'
|
|
29
|
+
mdurl==0.1.2; python_version >= '3.7'
|
|
30
|
+
more-itertools==10.8.0; python_version >= '3.9'
|
|
31
|
+
nh3==0.3.3; python_version >= '3.8'
|
|
32
|
+
packaging==26.0; python_version >= '3.8'
|
|
33
|
+
parameterized==0.9.0; python_version >= '3.7'
|
|
34
|
+
pillow==12.1.1; python_version >= '3.10'
|
|
35
|
+
platformdirs==4.9.4; python_version >= '3.10'
|
|
36
|
+
pluggy==1.6.0; python_version >= '3.9'
|
|
37
|
+
pycodestyle==2.12.1; python_version >= '3.8'
|
|
38
|
+
pyflakes==3.2.0; python_version >= '3.8'
|
|
39
|
+
pygments==2.19.2; python_version >= '3.8'
|
|
40
|
+
pyproject-api==1.10.0; python_version >= '3.10'
|
|
41
|
+
pyproject-hooks==1.2.0; python_version >= '3.7'
|
|
42
|
+
pytest==9.0.2; python_version >= '3.10'
|
|
43
|
+
pytest-cov==7.0.0; python_version >= '3.9'
|
|
44
|
+
python-discovery==1.1.3; python_version >= '3.8'
|
|
45
|
+
readme-renderer==44.0; python_version >= '3.9'
|
|
46
|
+
requests==2.32.5; python_version >= '3.9'
|
|
47
|
+
requests-toolbelt==1.0.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
|
48
|
+
rfc3986==2.0.0; python_version >= '3.7'
|
|
49
|
+
rich==14.3.3; python_full_version >= '3.8.0'
|
|
50
|
+
roman-numerals==4.1.0; python_version >= '3.10'
|
|
51
|
+
setuptools==82.0.1; python_version >= '3.9'
|
|
52
|
+
snowballstemmer==3.0.1; python_version not in '3.0, 3.1, 3.2'
|
|
53
|
+
sphinx==9.0.4; python_version >= '3.11'
|
|
54
|
+
sphinx-click==6.2.0; python_version >= '3.10'
|
|
55
|
+
sphinxcontrib-applehelp==2.0.0; python_version >= '3.9'
|
|
56
|
+
sphinxcontrib-devhelp==2.0.0; python_version >= '3.9'
|
|
57
|
+
sphinxcontrib-htmlhelp==2.1.0; python_version >= '3.9'
|
|
58
|
+
sphinxcontrib-jsmath==1.0.1; python_version >= '3.5'
|
|
59
|
+
sphinxcontrib-qthelp==2.0.0; python_version >= '3.9'
|
|
60
|
+
sphinxcontrib-serializinghtml==2.0.0; python_version >= '3.9'
|
|
61
|
+
tomli==2.0.1; python_version >= '3.7'
|
|
62
|
+
tomli-w==1.2.0; python_version >= '3.9'
|
|
63
|
+
tox==4.50.0; python_version >= '3.10'
|
|
64
|
+
tox-gh-actions==3.5.0; python_version >= '3.7'
|
|
65
|
+
twine==6.2.0; python_version >= '3.9'
|
|
66
|
+
urllib3==2.6.3; python_version >= '3.9'
|
|
67
|
+
virtualenv==21.2.0; python_version >= '3.8'
|
|
68
|
+
zipp==3.23.0; python_version >= '3.9'
|
|
69
|
+
antlr4-python3-runtime==4.13.2
|
|
70
|
+
asciimatics==1.15.0; python_version >= '3.8'
|
|
71
|
+
dacite==1.9.2; python_version >= '3.7'
|
|
72
|
+
first==2.0.2
|
|
73
|
+
jsonpath-ng==1.8.0
|
|
74
|
+
loguru==0.7.3; python_version >= '3.5' and python_version < '4.0'
|
|
75
|
+
overrides==7.7.0; python_version >= '3.6'
|
|
76
|
+
pyfiglet==1.0.4; python_version >= '3.9'
|
|
77
|
+
pyperclip==1.11.0
|
|
78
|
+
pyyaml==6.0.3; python_version >= '3.8'
|
|
79
|
+
urwid==3.0.5; python_full_version >= '3.9.0'
|
|
80
|
+
wcwidth==0.6.0; python_version >= '3.8'
|
|
81
|
+
yamale==6.1.0; python_version >= '3.8'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-fx"
|
|
3
|
-
dynamic = ["version"
|
|
3
|
+
dynamic = ["version"]
|
|
4
4
|
authors = [
|
|
5
5
|
{ name = "Yutian Wu", email = "yutianwu@umich.edu" }
|
|
6
6
|
]
|
|
@@ -8,7 +8,7 @@ license = { text = "MIT" }
|
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
description = "A python-native fx-alike terminal JSON viewer."
|
|
10
10
|
keywords = ["fx", "pyfx", "json viewer", "tui"]
|
|
11
|
-
requires-python = ">=3.
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
12
|
classifiers = [
|
|
13
13
|
"Development Status :: 4 - Beta",
|
|
14
14
|
"Programming Language :: Python :: 3 :: Only",
|
|
@@ -18,6 +18,25 @@ classifiers = [
|
|
|
18
18
|
"License :: OSI Approved :: MIT License",
|
|
19
19
|
"Topic :: Utilities"
|
|
20
20
|
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"antlr4-python3-runtime>=4.13,<5",
|
|
23
|
+
"asciimatics>=1.15,<2",
|
|
24
|
+
"click>=8.1.7,<9",
|
|
25
|
+
"first==2.0,<3",
|
|
26
|
+
"dacite==1.8,<2",
|
|
27
|
+
"jsonpath-ng==1.6,<2",
|
|
28
|
+
"loguru>=0.7.2,<0.8",
|
|
29
|
+
"overrides>=7.7.0,<8",
|
|
30
|
+
"pillow>=10.4,<11",
|
|
31
|
+
"ply>=3.11,<4",
|
|
32
|
+
"pyfiglet>=1.0,<2",
|
|
33
|
+
"pyperclip>=1.9",
|
|
34
|
+
"pyyaml>=6.0.2,<7",
|
|
35
|
+
"typing-extensions>=4.12.2,<5",
|
|
36
|
+
"urwid>=2.6,<3",
|
|
37
|
+
"wcwidth>=0.2.13,<0.3",
|
|
38
|
+
"yamale>=5.2,<6",
|
|
39
|
+
]
|
|
21
40
|
|
|
22
41
|
[project.urls]
|
|
23
42
|
repository = "https://github.com/cielong/pyfx"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
antlr4-python3-runtime==4.13.2
|
|
2
|
+
asciimatics==1.15.0; python_version >= '3.8'
|
|
3
|
+
click==8.3.1; python_version >= '3.10'
|
|
4
|
+
dacite==1.9.2; python_version >= '3.7'
|
|
5
|
+
first==2.0.2
|
|
6
|
+
jsonpath-ng==1.8.0
|
|
7
|
+
loguru==0.7.3; python_version >= '3.5' and python_version < '4.0'
|
|
8
|
+
overrides==7.7.0; python_version >= '3.6'
|
|
9
|
+
pillow==12.1.1; python_version >= '3.10'
|
|
10
|
+
pyfiglet==1.0.4; python_version >= '3.9'
|
|
11
|
+
pyperclip==1.11.0
|
|
12
|
+
pyyaml==6.0.3; python_version >= '3.8'
|
|
13
|
+
urwid==3.0.5; python_full_version >= '3.9.0'
|
|
14
|
+
wcwidth==0.6.0; python_version >= '3.8'
|
|
15
|
+
yamale==6.1.0; python_version >= '3.8'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.0"
|
|
@@ -10,7 +10,8 @@ from pyfx.config import parse
|
|
|
10
10
|
from pyfx.config import themes_path
|
|
11
11
|
from pyfx.config.config_parser import load
|
|
12
12
|
from pyfx.error import PyfxException
|
|
13
|
-
from pyfx.model import
|
|
13
|
+
from pyfx.model.model_manager import ModelManager
|
|
14
|
+
from pyfx.model.model_manager import ModelResult
|
|
14
15
|
from pyfx.service.client import Client
|
|
15
16
|
from pyfx.service.dispatcher import Dispatcher
|
|
16
17
|
from pyfx.view import View
|
|
@@ -53,10 +54,12 @@ class PyfxApp:
|
|
|
53
54
|
|
|
54
55
|
# backend part
|
|
55
56
|
self._dispatcher = Dispatcher()
|
|
56
|
-
# model
|
|
57
|
-
self.
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
# model manager
|
|
58
|
+
self._model_manager = ModelManager(
|
|
59
|
+
result_callback=self.__handle_model_result,
|
|
60
|
+
progress_callback=None)
|
|
61
|
+
self._dispatcher.register("query", self._model_manager.query)
|
|
62
|
+
self._dispatcher.register("complete", self._model_manager.complete)
|
|
60
63
|
|
|
61
64
|
# UI part
|
|
62
65
|
self._keymapper = self.__convert_keymap(self._config.ui.keymap)
|
|
@@ -194,9 +197,19 @@ class PyfxApp:
|
|
|
194
197
|
"exit with {}", e)
|
|
195
198
|
finally:
|
|
196
199
|
self._thread_pool_executor.shutdown(wait=True)
|
|
200
|
+
self._model_manager.shutdown(wait=True)
|
|
197
201
|
self._screen.clear()
|
|
198
202
|
|
|
199
|
-
def
|
|
203
|
+
def process_input(self, keys):
|
|
204
|
+
"""
|
|
205
|
+
Test-used method to process a list of keypress with proper model initialization
|
|
206
|
+
"""
|
|
207
|
+
init_success = self.__init(blocking=True)
|
|
208
|
+
if not init_success:
|
|
209
|
+
return False, "Model failed to load within timeout"
|
|
210
|
+
return self.__process_input(keys)
|
|
211
|
+
|
|
212
|
+
def __init(self, blocking=False):
|
|
200
213
|
"""Post-initializes Pyfx, it must be called before `__run()`.
|
|
201
214
|
|
|
202
215
|
.. note::
|
|
@@ -207,13 +220,22 @@ class PyfxApp:
|
|
|
207
220
|
processing data to construct essential widgets.
|
|
208
221
|
"""
|
|
209
222
|
logger.debug("Initializing Pyfx...")
|
|
210
|
-
|
|
223
|
+
# Start async model loading
|
|
224
|
+
self._model_manager.load(self._data)
|
|
225
|
+
if not blocking:
|
|
226
|
+
return True
|
|
227
|
+
return self._model_manager.wait_until_ready(timeout=5.0)
|
|
211
228
|
|
|
212
229
|
def __run(self):
|
|
213
230
|
"""Starts the UI loop."""
|
|
214
231
|
logger.debug("Running Pyfx...")
|
|
215
232
|
self._view.run()
|
|
216
233
|
|
|
234
|
+
def __process_input(self, keys):
|
|
235
|
+
"""Test-used method to process a list of keypress with proper model initialization."""
|
|
236
|
+
logger.debug("Running Pyfx...")
|
|
237
|
+
return self._view.process_input(keys)
|
|
238
|
+
|
|
217
239
|
def __init_logger(self, is_debug_mode):
|
|
218
240
|
logger.configure(
|
|
219
241
|
handlers=[{
|
|
@@ -266,3 +288,14 @@ class PyfxApp:
|
|
|
266
288
|
# avoid potential error during e2e test
|
|
267
289
|
pass
|
|
268
290
|
return screen
|
|
291
|
+
|
|
292
|
+
def __handle_model_result(self, result: ModelResult):
|
|
293
|
+
"""Handle async model results"""
|
|
294
|
+
if not result.success:
|
|
295
|
+
logger.error("Model operation failed: {}", result.error)
|
|
296
|
+
return
|
|
297
|
+
|
|
298
|
+
if result.operation_name == "Load":
|
|
299
|
+
logger.debug("Model loading completed, refreshing view")
|
|
300
|
+
# Use urwid alarm to safely update UI from background thread
|
|
301
|
+
self._mediator.notify('backend', 'refresh', 'json_browser', result.data)
|
|
@@ -5,7 +5,9 @@ from antlr4.error.ErrorListener import ErrorListener
|
|
|
5
5
|
from loguru import logger
|
|
6
6
|
from overrides import overrides
|
|
7
7
|
|
|
8
|
-
from ..common.jsonpath import JSONPathLexer
|
|
8
|
+
from ..common.jsonpath.JSONPathLexer import JSONPathLexer
|
|
9
|
+
from ..common.jsonpath.JSONPathParser import JSONPathParser
|
|
10
|
+
from ..common.jsonpath.JSONPathListener import JSONPathListener
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def autocomplete(current_input, query):
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
token literal names:
|
|
2
|
+
null
|
|
3
|
+
'['
|
|
4
|
+
'?'
|
|
5
|
+
'('
|
|
6
|
+
')'
|
|
7
|
+
']'
|
|
8
|
+
'>'
|
|
9
|
+
'<'
|
|
10
|
+
'=='
|
|
11
|
+
','
|
|
12
|
+
':'
|
|
13
|
+
'*'
|
|
14
|
+
'[*]'
|
|
15
|
+
'$'
|
|
16
|
+
'@'
|
|
17
|
+
'.'
|
|
18
|
+
'..'
|
|
19
|
+
null
|
|
20
|
+
null
|
|
21
|
+
null
|
|
22
|
+
null
|
|
23
|
+
|
|
24
|
+
token symbolic names:
|
|
25
|
+
null
|
|
26
|
+
null
|
|
27
|
+
null
|
|
28
|
+
null
|
|
29
|
+
null
|
|
30
|
+
null
|
|
31
|
+
null
|
|
32
|
+
null
|
|
33
|
+
null
|
|
34
|
+
null
|
|
35
|
+
null
|
|
36
|
+
null
|
|
37
|
+
null
|
|
38
|
+
ROOT
|
|
39
|
+
CURRENT
|
|
40
|
+
SINGLE_DOT
|
|
41
|
+
DOUBLE_DOT
|
|
42
|
+
LETTER
|
|
43
|
+
STRING
|
|
44
|
+
INT
|
|
45
|
+
WS
|
|
46
|
+
|
|
47
|
+
rule names:
|
|
48
|
+
jsonpath
|
|
49
|
+
expression
|
|
50
|
+
doubleDotExpression
|
|
51
|
+
singleDotExpression
|
|
52
|
+
filters
|
|
53
|
+
numericFilter
|
|
54
|
+
stringFilter
|
|
55
|
+
booleanFilter
|
|
56
|
+
union
|
|
57
|
+
arraySlice
|
|
58
|
+
fieldAccessor
|
|
59
|
+
field
|
|
60
|
+
bracketField
|
|
61
|
+
arrayIndex
|
|
62
|
+
wildcard
|
|
63
|
+
bracketWildcard
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
atn:
|
|
67
|
+
[4, 1, 20, 159, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 1, 0, 1, 0, 5, 0, 35, 8, 0, 10, 0, 12, 0, 38, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 44, 8, 1, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 50, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 56, 8, 3, 1, 3, 1, 3, 3, 3, 60, 8, 3, 1, 3, 1, 3, 3, 3, 64, 8, 3, 1, 3, 1, 3, 3, 3, 68, 8, 3, 1, 3, 3, 3, 71, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 94, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 4, 8, 113, 8, 8, 11, 8, 12, 8, 114, 1, 8, 1, 8, 1, 9, 1, 9, 3, 9, 121, 8, 9, 1, 9, 1, 9, 3, 9, 125, 8, 9, 1, 9, 1, 9, 3, 9, 129, 8, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 3, 10, 136, 8, 10, 1, 10, 1, 10, 3, 10, 140, 8, 10, 1, 10, 3, 10, 143, 8, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 0, 0, 16, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 0, 2, 1, 0, 6, 8, 1, 0, 17, 18, 164, 0, 32, 1, 0, 0, 0, 2, 43, 1, 0, 0, 0, 4, 49, 1, 0, 0, 0, 6, 70, 1, 0, 0, 0, 8, 93, 1, 0, 0, 0, 10, 95, 1, 0, 0, 0, 12, 100, 1, 0, 0, 0, 14, 105, 1, 0, 0, 0, 16, 108, 1, 0, 0, 0, 18, 118, 1, 0, 0, 0, 20, 142, 1, 0, 0, 0, 22, 144, 1, 0, 0, 0, 24, 146, 1, 0, 0, 0, 26, 150, 1, 0, 0, 0, 28, 154, 1, 0, 0, 0, 30, 156, 1, 0, 0, 0, 32, 36, 5, 13, 0, 0, 33, 35, 3, 2, 1, 0, 34, 33, 1, 0, 0, 0, 35, 38, 1, 0, 0, 0, 36, 34, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 39, 1, 0, 0, 0, 38, 36, 1, 0, 0, 0, 39, 40, 5, 0, 0, 1, 40, 1, 1, 0, 0, 0, 41, 44, 3, 6, 3, 0, 42, 44, 3, 4, 2, 0, 43, 41, 1, 0, 0, 0, 43, 42, 1, 0, 0, 0, 44, 3, 1, 0, 0, 0, 45, 46, 5, 16, 0, 0, 46, 50, 3, 22, 11, 0, 47, 48, 5, 16, 0, 0, 48, 50, 3, 24, 12, 0, 49, 45, 1, 0, 0, 0, 49, 47, 1, 0, 0, 0, 50, 5, 1, 0, 0, 0, 51, 71, 3, 20, 10, 0, 52, 53, 5, 15, 0, 0, 53, 71, 3, 28, 14, 0, 54, 56, 5, 15, 0, 0, 55, 54, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 57, 1, 0, 0, 0, 57, 71, 3, 30, 15, 0, 58, 60, 5, 15, 0, 0, 59, 58, 1, 0, 0, 0, 59, 60, 1, 0, 0, 0, 60, 61, 1, 0, 0, 0, 61, 71, 3, 8, 4, 0, 62, 64, 5, 15, 0, 0, 63, 62, 1, 0, 0, 0, 63, 64, 1, 0, 0, 0, 64, 65, 1, 0, 0, 0, 65, 71, 3, 18, 9, 0, 66, 68, 5, 15, 0, 0, 67, 66, 1, 0, 0, 0, 67, 68, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 71, 3, 16, 8, 0, 70, 51, 1, 0, 0, 0, 70, 52, 1, 0, 0, 0, 70, 55, 1, 0, 0, 0, 70, 59, 1, 0, 0, 0, 70, 63, 1, 0, 0, 0, 70, 67, 1, 0, 0, 0, 71, 7, 1, 0, 0, 0, 72, 73, 5, 1, 0, 0, 73, 74, 5, 2, 0, 0, 74, 75, 5, 3, 0, 0, 75, 76, 3, 10, 5, 0, 76, 77, 5, 4, 0, 0, 77, 78, 5, 5, 0, 0, 78, 94, 1, 0, 0, 0, 79, 80, 5, 1, 0, 0, 80, 81, 5, 2, 0, 0, 81, 82, 5, 3, 0, 0, 82, 83, 3, 12, 6, 0, 83, 84, 5, 4, 0, 0, 84, 85, 5, 5, 0, 0, 85, 94, 1, 0, 0, 0, 86, 87, 5, 1, 0, 0, 87, 88, 5, 2, 0, 0, 88, 89, 5, 3, 0, 0, 89, 90, 3, 14, 7, 0, 90, 91, 5, 4, 0, 0, 91, 92, 5, 5, 0, 0, 92, 94, 1, 0, 0, 0, 93, 72, 1, 0, 0, 0, 93, 79, 1, 0, 0, 0, 93, 86, 1, 0, 0, 0, 94, 9, 1, 0, 0, 0, 95, 96, 5, 14, 0, 0, 96, 97, 3, 20, 10, 0, 97, 98, 7, 0, 0, 0, 98, 99, 5, 19, 0, 0, 99, 11, 1, 0, 0, 0, 100, 101, 5, 14, 0, 0, 101, 102, 3, 20, 10, 0, 102, 103, 5, 8, 0, 0, 103, 104, 5, 18, 0, 0, 104, 13, 1, 0, 0, 0, 105, 106, 5, 14, 0, 0, 106, 107, 3, 20, 10, 0, 107, 15, 1, 0, 0, 0, 108, 109, 5, 1, 0, 0, 109, 112, 7, 1, 0, 0, 110, 111, 5, 9, 0, 0, 111, 113, 7, 1, 0, 0, 112, 110, 1, 0, 0, 0, 113, 114, 1, 0, 0, 0, 114, 112, 1, 0, 0, 0, 114, 115, 1, 0, 0, 0, 115, 116, 1, 0, 0, 0, 116, 117, 5, 5, 0, 0, 117, 17, 1, 0, 0, 0, 118, 120, 5, 1, 0, 0, 119, 121, 5, 19, 0, 0, 120, 119, 1, 0, 0, 0, 120, 121, 1, 0, 0, 0, 121, 122, 1, 0, 0, 0, 122, 124, 5, 10, 0, 0, 123, 125, 5, 19, 0, 0, 124, 123, 1, 0, 0, 0, 124, 125, 1, 0, 0, 0, 125, 128, 1, 0, 0, 0, 126, 127, 5, 10, 0, 0, 127, 129, 5, 19, 0, 0, 128, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 130, 1, 0, 0, 0, 130, 131, 5, 5, 0, 0, 131, 19, 1, 0, 0, 0, 132, 133, 5, 15, 0, 0, 133, 143, 3, 22, 11, 0, 134, 136, 5, 15, 0, 0, 135, 134, 1, 0, 0, 0, 135, 136, 1, 0, 0, 0, 136, 137, 1, 0, 0, 0, 137, 143, 3, 24, 12, 0, 138, 140, 5, 15, 0, 0, 139, 138, 1, 0, 0, 0, 139, 140, 1, 0, 0, 0, 140, 141, 1, 0, 0, 0, 141, 143, 3, 26, 13, 0, 142, 132, 1, 0, 0, 0, 142, 135, 1, 0, 0, 0, 142, 139, 1, 0, 0, 0, 143, 21, 1, 0, 0, 0, 144, 145, 5, 17, 0, 0, 145, 23, 1, 0, 0, 0, 146, 147, 5, 1, 0, 0, 147, 148, 7, 1, 0, 0, 148, 149, 5, 5, 0, 0, 149, 25, 1, 0, 0, 0, 150, 151, 5, 1, 0, 0, 151, 152, 5, 19, 0, 0, 152, 153, 5, 5, 0, 0, 153, 27, 1, 0, 0, 0, 154, 155, 5, 11, 0, 0, 155, 29, 1, 0, 0, 0, 156, 157, 5, 12, 0, 0, 157, 31, 1, 0, 0, 0, 16, 36, 43, 49, 55, 59, 63, 67, 70, 93, 114, 120, 124, 128, 135, 139, 142]
|