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.
Files changed (114) hide show
  1. {python-fx-0.3.1 → python_fx-0.4.0}/CHANGELOG.md +10 -1
  2. python_fx-0.4.0/CLAUDE.md +121 -0
  3. {python-fx-0.3.1 → python_fx-0.4.0}/PKG-INFO +28 -23
  4. {python-fx-0.3.1 → python_fx-0.4.0}/README.md +7 -3
  5. python_fx-0.4.0/dev-requirements.txt +81 -0
  6. {python-fx-0.3.1 → python_fx-0.4.0}/pyproject.toml +21 -2
  7. python_fx-0.4.0/requirements.txt +15 -0
  8. {python-fx-0.3.1 → python_fx-0.4.0}/setup.cfg +1 -1
  9. python_fx-0.4.0/src/pyfx/__version__.py +1 -0
  10. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/app.py +40 -7
  11. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/autocomplete/autocomplete_listener.py +3 -1
  12. python_fx-0.4.0/src/pyfx/model/common/jsonpath/JSONPath.interp +67 -0
  13. python_fx-0.4.0/src/pyfx/model/common/jsonpath/JSONPathLexer.interp +78 -0
  14. python_fx-0.4.0/src/pyfx/model/common/jsonpath/JSONPathLexer.py +108 -0
  15. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPathListener.py +8 -13
  16. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPathParser.py +146 -225
  17. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/model.py +7 -1
  18. python_fx-0.4.0/src/pyfx/model/model_manager.py +210 -0
  19. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/frame.py +4 -3
  20. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/selectable_text.py +1 -1
  21. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/view_manager.py +2 -4
  22. {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/PKG-INFO +28 -23
  23. {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/SOURCES.txt +2 -0
  24. python_fx-0.4.0/src/python_fx.egg-info/requires.txt +17 -0
  25. {python-fx-0.3.1 → python_fx-0.4.0}/tox.ini +5 -4
  26. python-fx-0.3.1/dev-requirements.txt +0 -82
  27. python-fx-0.3.1/requirements.txt +0 -17
  28. python-fx-0.3.1/src/pyfx/__version__.py +0 -1
  29. python-fx-0.3.1/src/pyfx/model/common/jsonpath/JSONPath.interp +0 -67
  30. python-fx-0.3.1/src/pyfx/model/common/jsonpath/JSONPathLexer.interp +0 -78
  31. python-fx-0.3.1/src/pyfx/model/common/jsonpath/JSONPathLexer.py +0 -126
  32. python-fx-0.3.1/src/python_fx.egg-info/requires.txt +0 -31
  33. {python-fx-0.3.1 → python_fx-0.4.0}/.coveragerc +0 -0
  34. {python-fx-0.3.1 → python_fx-0.4.0}/.readthedocs.yml +0 -0
  35. {python-fx-0.3.1 → python_fx-0.4.0}/CODE_OF_CONDUCT.md +0 -0
  36. {python-fx-0.3.1 → python_fx-0.4.0}/LICENSE.txt +0 -0
  37. {python-fx-0.3.1 → python_fx-0.4.0}/MANIFEST.in +0 -0
  38. {python-fx-0.3.1 → python_fx-0.4.0}/docs/Makefile +0 -0
  39. {python-fx-0.3.1 → python_fx-0.4.0}/docs/conf.py +0 -0
  40. {python-fx-0.3.1 → python_fx-0.4.0}/docs/demo.gif +0 -0
  41. {python-fx-0.3.1 → python_fx-0.4.0}/docs/index.rst +0 -0
  42. {python-fx-0.3.1 → python_fx-0.4.0}/docs/make.bat +0 -0
  43. {python-fx-0.3.1 → python_fx-0.4.0}/setup.py +0 -0
  44. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/__init__.py +0 -0
  45. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/cli.py +0 -0
  46. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/cli_utils.py +0 -0
  47. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/__init__.py +0 -0
  48. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/config.py +0 -0
  49. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/config_parser.py +0 -0
  50. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/__init__.py +0 -0
  51. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/config.yml +0 -0
  52. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/config_schema.yml +0 -0
  53. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/__init__.py +0 -0
  54. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/basic.yml +0 -0
  55. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/emacs.yml +0 -0
  56. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/keymaps/vim.yml +0 -0
  57. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/themes/__init__.py +0 -0
  58. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/config/yaml/themes/basic.yml +0 -0
  59. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/error.py +0 -0
  60. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/__init__.py +0 -0
  61. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/autocomplete/__init__.py +0 -0
  62. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/__init__.py +0 -0
  63. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPath.g4 +0 -0
  64. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPath.tokens +0 -0
  65. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/JSONPathLexer.tokens +0 -0
  66. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/model/common/jsonpath/__init__.py +0 -0
  67. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/service/__init__.py +0 -0
  68. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/service/client.py +0 -0
  69. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/service/dispatcher.py +0 -0
  70. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/__init__.py +0 -0
  71. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/__init__.py +0 -0
  72. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/common/popup.py +0 -0
  73. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/__init__.py +0 -0
  74. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/abstract_component_keys.py +0 -0
  75. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/autocomplete_popup.py +0 -0
  76. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/help_popup.py +0 -0
  77. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/json_browser.py +0 -0
  78. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/query_bar.py +0 -0
  79. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/components/warning_bar.py +0 -0
  80. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/__init__.py +0 -0
  81. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/__init__.py +0 -0
  82. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_end_node.py +0 -0
  83. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_end_widget.py +0 -0
  84. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_node.py +0 -0
  85. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_start_widget.py +0 -0
  86. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/array/array_unexpanded_widget.py +0 -0
  87. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_composite_end_node.py +0 -0
  88. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_composite_node.py +0 -0
  89. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_listbox.py +0 -0
  90. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_listwalker.py +0 -0
  91. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_node_creator.py +0 -0
  92. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_node_factory.py +0 -0
  93. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_simple_node.py +0 -0
  94. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/json_widget.py +0 -0
  95. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/__init__.py +0 -0
  96. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_end_node.py +0 -0
  97. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_end_widget.py +0 -0
  98. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_node.py +0 -0
  99. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_start_widget.py +0 -0
  100. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/object/object_unexpanded_widget.py +0 -0
  101. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/__init__.py +0 -0
  102. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/base.py +0 -0
  103. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/boolean.py +0 -0
  104. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/integer.py +0 -0
  105. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/null.py +0 -0
  106. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/numeric.py +0 -0
  107. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/json_lib/primitive/string.py +0 -0
  108. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/keys.py +0 -0
  109. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/themes.py +0 -0
  110. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/view_frame.py +0 -0
  111. {python-fx-0.3.1 → python_fx-0.4.0}/src/pyfx/view/view_mediator.py +0 -0
  112. {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/dependency_links.txt +0 -0
  113. {python-fx-0.3.1 → python_fx-0.4.0}/src/python_fx.egg-info/entry_points.txt +0 -0
  114. {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.0...HEAD
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
1
+ Metadata-Version: 2.4
2
2
  Name: python-fx
3
- Version: 0.3.1
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.8
16
+ Requires-Python: >=3.9
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE.txt
19
- Requires-Dist: antlr4-python3-runtime==4.8
20
- Requires-Dist: asciimatics==1.14.0
21
- Requires-Dist: click==8.1.7; python_version >= "3.7"
22
- Requires-Dist: dacite==1.8.1; python_version >= "3.6"
23
- Requires-Dist: first==2.0.2
24
- Requires-Dist: future==0.18.3; python_version >= "2.6" and python_version not in "3.0, 3.1, 3.2, 3.3"
25
- Requires-Dist: jsonpath-ng==1.6.0
26
- Requires-Dist: loguru==0.7.2; python_version >= "3.5"
27
- Requires-Dist: overrides==7.4.0; python_version >= "3.6"
28
- Requires-Dist: pillow==10.0.1; python_version >= "3.8"
29
- Requires-Dist: ply==3.11
30
- Requires-Dist: pyfiglet==0.8.post1; python_version >= "3.9"
31
- Requires-Dist: pyperclip==1.8.2
32
- Requires-Dist: pyyaml==6.0.1; python_version >= "3.6"
33
- Requires-Dist: urwid==2.2.1; python_full_version >= "3.7.0"
34
- Requires-Dist: wcwidth==0.2.6
35
- Requires-Dist: yamale==4.0.4; python_version >= "3.6"
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
  ![Build Status](https://github.com/cielong/pyfx/actions/workflows/ci.yml/badge.svg?branch=main)
39
40
  ![Documentation Status](https://readthedocs.org/projects/python-fx/badge/?version=latest)
40
41
  ![PyPI version](https://badge.fury.io/py/python-fx.svg)
41
- ![Python](https://img.shields.io/badge/python-3.8-green.svg)
42
42
  ![Python](https://img.shields.io/badge/python-3.9-green.svg)
43
43
  ![Python](https://img.shields.io/badge/python-3.10-green.svg)
44
44
  ![Python](https://img.shields.io/badge/python-3.11-green.svg)
@@ -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.8
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
- Clone the this [repo](https://github.com/cielong/pyfx.git), change directory into the project and run
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
  ![Build Status](https://github.com/cielong/pyfx/actions/workflows/ci.yml/badge.svg?branch=main)
3
3
  ![Documentation Status](https://readthedocs.org/projects/python-fx/badge/?version=latest)
4
4
  ![PyPI version](https://badge.fury.io/py/python-fx.svg)
5
- ![Python](https://img.shields.io/badge/python-3.8-green.svg)
6
5
  ![Python](https://img.shields.io/badge/python-3.9-green.svg)
7
6
  ![Python](https://img.shields.io/badge/python-3.10-green.svg)
8
7
  ![Python](https://img.shields.io/badge/python-3.11-green.svg)
@@ -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.8
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
- Clone the this [repo](https://github.com/cielong/pyfx.git), change directory into the project and run
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", "dependencies"]
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.8"
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'
@@ -4,7 +4,7 @@ test = pytest
4
4
  [flake8]
5
5
  max_line_length = 120
6
6
  exclude =
7
- .git,,
7
+ .git,
8
8
  .github,
9
9
  .tox,
10
10
  __pycache__,
@@ -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 Model
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._model = Model(self._data)
58
- self._dispatcher.register("query", self._model.query)
59
- self._dispatcher.register("complete", self._model.complete)
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 __init(self):
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
- self._json_browser.refresh_view(self._data)
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, JSONPathParser, JSONPathListener
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]