maidr 1.4.10__tar.gz → 1.6.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.
- {maidr-1.4.10 → maidr-1.6.0}/CHANGELOG.md +23 -0
- {maidr-1.4.10 → maidr-1.6.0}/PKG-INFO +3 -1
- maidr-1.6.0/example/flask/test_flask_app.py +71 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/__init__.py +1 -1
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/maidr.py +45 -2
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/environment.py +127 -0
- {maidr-1.4.10 → maidr-1.6.0}/pyproject.toml +4 -2
- {maidr-1.4.10 → maidr-1.6.0}/uv.lock +54 -1
- {maidr-1.4.10 → maidr-1.6.0}/.commitlintrc.cjs +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.editorconfig +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.github/copilot-instructions.md +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.github/workflows/ci.yml +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.github/workflows/docs.yml +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.github/workflows/release.yml +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.gitignore +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.pre-commit-config.yaml +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.vscode/extensions.json +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/.vscode/settings.json +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/CONDUCT.md +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/CONTRIBUTING.md +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/LICENSE +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/README.md +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/.gitignore +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/CNAME +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_environment +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/machow/interlinks/.gitignore +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/machow/interlinks/_extension.yml +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/machow/interlinks/interlinks.lua +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/shafayetShafee/line-highlight/_extension.yml +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/shafayetShafee/line-highlight/line-highlight.lua +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/shafayetShafee/line-highlight/resources/css/line-highlight.css +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/shafayetShafee/line-highlight/resources/js/line-highlight.js +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/_quarto.yml +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/examples.qmd +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/index.qmd +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/docs/styles.css +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/bar/example_bar_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/bar/matplotlib/example_mpl_bar_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/bar/seaborn/example_sns_bar_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/box/example_box_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/box/matplotlib/example_mpl_box.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/box/seaborn/example_sns_box.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/candle_stick/legacy_candlestick_example.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/candle_stick/mplfinance_candlestick_example.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/candle_stick/volcandat.csv +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/count/example_count_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/count/seaborn/example_sns_count_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/dodged/matplotlib/example_mpl_dodged.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/dodged/seaborn/example_sns_dodged.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/facet-subplots/matplotlib/example_mpl_facet_bar_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/facet-subplots/matplotlib/example_mpl_facet_combined_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/facet-subplots/seaborn/example_sns_facet_bar_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/facet-subplots/seaborn/example_sns_facet_combined_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/heatmap/example_heatmap_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/heatmap/matplotlib/example_mpl_heatmap.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/heatmap/seaborn/example_sns_heatmap.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/histogram/example_histogram_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/histogram/matplotlib/example_mpl_hist.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/histogram/matplotlib/histogram_with_kde_matplotlib.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/histogram/seaborn/example_sns_hist.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/histogram/seaborn/histogram_with_kde_seaborn.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/kde/example_kde_plots.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/kde/matplotlib/multiple_kde_matplotlib.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/kde/matplotlib/single_kde_matplotlib.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/kde/seaborn/multiple_kde_seaborn.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/kde/seaborn/single_kde_seaborn.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/line/example_line_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/line/matplotlib/example_mpl_line.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/line/seaborn/example_sns_line.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multilayer/example_mpl_multilayer.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multilayer/example_multilayer_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multiline/example_multiline_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multiline/matplotlib/example_mpl_multiline.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multiline/seaborn/example_sns_multiline.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multipanel/example_multipanel_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multipanel/matplotlib/example_mpl_multipanel.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/multipanel/seaborn/example_sns_multipanel.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/quarto/demo.qmd +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/reg/example_reg_plots.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/reg/matplotlib/example_matplotlib_smooth_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/reg/seaborn/example_sns_reg.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/scatter/example_scatter_plot.ipynb +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/scatter/matplotlib/example_mpl_scatter.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/scatter/seaborn/example_sns_scatter.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/shiny/example_shiny_scatter.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/stacked/matplotlib/example_mpl_stacked.html +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/stacked/matplotlib/example_mpl_stacked.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/stacked/seaborn/example_sns_stacked.html +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/stacked/seaborn/example_sns_stacked.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/example/streamlit/example_streamlit_app.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/api.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/context_manager.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/enum/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/enum/library.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/enum/maidr_key.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/enum/plot_type.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/enum/smooth_keywords.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/figure_manager.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/barplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/boxplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/candlestick.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/grouped_barplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/heatmap.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/histogram.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/lineplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/maidr_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/maidr_plot_factory.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/mplfinance_barplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/mplfinance_lineplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/regplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/core/plot/scatterplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/exception/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/exception/extraction_error.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/barplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/boxplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/candlestick.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/clear.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/common.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/heatmap.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/highlight.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/histogram.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/kdeplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/lineplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/mplfinance.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/regplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/patch/scatterplot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/dedup_utils.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/mixin/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/mixin/extractor_mixin.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/mixin/merger_mixin.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/mplfinance_utils.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/plot_detection.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/regression_line_utils.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/util/svg_utils.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/widget/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/maidr/widget/shiny.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/conftest.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/core/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/core/enum/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/core/plot/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/core/test_figure_manager.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/core/test_maidr_plot.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/core/test_maidr_plot_factory.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/fixture/__init__.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/fixture/library_factory.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/fixture/matplotlib_factory.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tests/fixture/seaborn_factory.py +0 -0
- {maidr-1.4.10 → maidr-1.6.0}/tox.ini +0 -0
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v1.6.0 (2025-08-04)
|
|
5
|
+
|
|
6
|
+
### Continuous Integration
|
|
7
|
+
|
|
8
|
+
- Update uv.lock ([#227](https://github.com/xability/py-maidr/pull/227),
|
|
9
|
+
[`f162971`](https://github.com/xability/py-maidr/commit/f162971f4e2585e055de3c837ce9342b292cb378))
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- Add WSL compatibility for opening HTML files
|
|
14
|
+
([#224](https://github.com/xability/py-maidr/pull/224),
|
|
15
|
+
[`2f2a899`](https://github.com/xability/py-maidr/commit/2f2a899b1df4137db94aeb843099ee6f0df952f0))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## v1.5.0 (2025-08-04)
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
- Detect if running in a flask app and render in an iframe
|
|
23
|
+
([#225](https://github.com/xability/py-maidr/pull/225),
|
|
24
|
+
[`dcd0e0f`](https://github.com/xability/py-maidr/commit/dcd0e0fb1f7a995e4eb2578e9f67cc31e45171ea))
|
|
25
|
+
|
|
26
|
+
|
|
4
27
|
## v1.4.10 (2025-07-30)
|
|
5
28
|
|
|
6
29
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maidr
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0
|
|
4
4
|
Summary: Multimodal Access and Interactive Data Representations
|
|
5
5
|
Project-URL: Homepage, https://xability.github.io/py-maidr
|
|
6
6
|
Project-URL: Repository, https://github.com/xability/py-maidr
|
|
@@ -34,12 +34,14 @@ Provides-Extra: jupyter
|
|
|
34
34
|
Requires-Dist: ipykernel>=6.0.0; extra == 'jupyter'
|
|
35
35
|
Requires-Dist: jupyter<2,>=1.0.0; extra == 'jupyter'
|
|
36
36
|
Provides-Extra: test
|
|
37
|
+
Requires-Dist: flask>=3.0.0; extra == 'test'
|
|
37
38
|
Requires-Dist: jupyter<2,>=1.0.0; extra == 'test'
|
|
38
39
|
Requires-Dist: matplotlib>=3.8; extra == 'test'
|
|
39
40
|
Requires-Dist: pytest-mock<4,>=3.12.0; extra == 'test'
|
|
40
41
|
Requires-Dist: pytest<8,>=7.3.2; extra == 'test'
|
|
41
42
|
Requires-Dist: seaborn>=0.12; extra == 'test'
|
|
42
43
|
Provides-Extra: visualization
|
|
44
|
+
Requires-Dist: flask>=3.0.0; extra == 'visualization'
|
|
43
45
|
Requires-Dist: matplotlib>=3.8; extra == 'visualization'
|
|
44
46
|
Requires-Dist: seaborn>=0.12; extra == 'visualization'
|
|
45
47
|
Requires-Dist: statsmodels>=0.14.4; extra == 'visualization'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import matplotlib
|
|
2
|
+
matplotlib.use('Agg') # Use non-interactive backend for Flask
|
|
3
|
+
|
|
4
|
+
from flask import Flask
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import seaborn as sns
|
|
7
|
+
import maidr
|
|
8
|
+
from maidr.util.environment import Environment
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
# Set up logging
|
|
12
|
+
logging.basicConfig(level=logging.INFO)
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
app = Flask(__name__)
|
|
16
|
+
|
|
17
|
+
@app.route('/')
|
|
18
|
+
def index():
|
|
19
|
+
# Log environment detection
|
|
20
|
+
logger.info("=== Environment Detection ===")
|
|
21
|
+
logger.info(f"is_flask(): {Environment.is_flask()}")
|
|
22
|
+
logger.info(f"is_notebook(): {Environment.is_notebook()}")
|
|
23
|
+
logger.info(f"is_shiny(): {Environment.is_shiny()}")
|
|
24
|
+
logger.info(f"get_renderer(): {Environment.get_renderer()}")
|
|
25
|
+
|
|
26
|
+
# Check iframe detection logic
|
|
27
|
+
use_iframe = True
|
|
28
|
+
flask_detected = Environment.is_flask()
|
|
29
|
+
notebook_detected = Environment.is_notebook()
|
|
30
|
+
shiny_detected = Environment.is_shiny()
|
|
31
|
+
|
|
32
|
+
logger.info("=== Iframe Detection Logic ===")
|
|
33
|
+
logger.info(f"use_iframe: {use_iframe}")
|
|
34
|
+
logger.info(f"flask_detected: {flask_detected}")
|
|
35
|
+
logger.info(f"notebook_detected: {notebook_detected}")
|
|
36
|
+
logger.info(f"shiny_detected: {shiny_detected}")
|
|
37
|
+
logger.info("Condition: use_iframe and (flask_detected or notebook_detected or shiny_detected)")
|
|
38
|
+
logger.info(f"Result: {use_iframe and (flask_detected or notebook_detected or shiny_detected)}")
|
|
39
|
+
|
|
40
|
+
# Load the penguins dataset
|
|
41
|
+
penguins = sns.load_dataset("penguins")
|
|
42
|
+
|
|
43
|
+
# Create a bar plot showing the average body mass of penguins by species
|
|
44
|
+
plt.figure(figsize=(10, 6))
|
|
45
|
+
|
|
46
|
+
# Create the bar plot and assign to variable
|
|
47
|
+
bar_plot = sns.barplot(
|
|
48
|
+
x="species", y="body_mass_g", data=penguins, errorbar="sd", palette="Blues_d"
|
|
49
|
+
)
|
|
50
|
+
plt.title("Average Body Mass of Penguins by Species")
|
|
51
|
+
plt.xlabel("Species")
|
|
52
|
+
plt.ylabel("Body Mass (g)")
|
|
53
|
+
|
|
54
|
+
# Use the user-facing API: maidr.render() with plot object
|
|
55
|
+
logger.info("=== Using maidr.render() API ===")
|
|
56
|
+
maidr_html = maidr.render(bar_plot)
|
|
57
|
+
logger.info(f"Type of maidr.render(): {type(maidr_html)}")
|
|
58
|
+
logger.info(f"String representation: {str(maidr_html)[:300]}...")
|
|
59
|
+
|
|
60
|
+
# Check if the output contains iframe
|
|
61
|
+
html_str = str(maidr_html)
|
|
62
|
+
contains_iframe = "<iframe" in html_str.lower()
|
|
63
|
+
logger.info(f"Contains iframe: {contains_iframe}")
|
|
64
|
+
|
|
65
|
+
# Return the maidr HTML directly
|
|
66
|
+
return str(maidr_html)
|
|
67
|
+
|
|
68
|
+
if __name__ == '__main__':
|
|
69
|
+
logger.info("Starting Flask app with logging...")
|
|
70
|
+
logger.info("Visit http://localhost:5002 to see the maidr plot in Flask")
|
|
71
|
+
app.run(debug=False, host='0.0.0.0', port=5002)
|
|
@@ -7,6 +7,8 @@ import os
|
|
|
7
7
|
import tempfile
|
|
8
8
|
import uuid
|
|
9
9
|
import webbrowser
|
|
10
|
+
import subprocess
|
|
11
|
+
from pathlib import Path
|
|
10
12
|
from typing import Any, Literal, cast
|
|
11
13
|
|
|
12
14
|
import matplotlib.pyplot as plt
|
|
@@ -137,7 +139,48 @@ class Maidr:
|
|
|
137
139
|
html_file_path = self.save_html(
|
|
138
140
|
temp_file_path
|
|
139
141
|
) # This will use use_iframe=False
|
|
140
|
-
|
|
142
|
+
if Environment.is_wsl():
|
|
143
|
+
wsl_distro_name = Environment.get_wsl_distro_name()
|
|
144
|
+
|
|
145
|
+
# Validate that WSL distro name is available
|
|
146
|
+
if not wsl_distro_name:
|
|
147
|
+
raise ValueError(
|
|
148
|
+
"WSL_DISTRO_NAME environment variable is not set or is empty. "
|
|
149
|
+
"Cannot construct WSL file URL. Please ensure you are running in a WSL environment."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Ensure html_file_path is an absolute POSIX path for proper WSL URL construction
|
|
153
|
+
html_file_path = Path(html_file_path).resolve().as_posix()
|
|
154
|
+
|
|
155
|
+
url = f"file://wsl$/{wsl_distro_name}{html_file_path}"
|
|
156
|
+
|
|
157
|
+
# Try to open the file in Windows using explorer.exe with robust path detection
|
|
158
|
+
explorer_path = Environment.find_explorer_path()
|
|
159
|
+
if explorer_path:
|
|
160
|
+
try:
|
|
161
|
+
result = subprocess.run(
|
|
162
|
+
[explorer_path, url],
|
|
163
|
+
capture_output=True,
|
|
164
|
+
text=True,
|
|
165
|
+
timeout=10
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
if result.returncode == 0:
|
|
169
|
+
return
|
|
170
|
+
else:
|
|
171
|
+
# Fall back to webbrowser.open() if explorer.exe fails
|
|
172
|
+
webbrowser.open(url)
|
|
173
|
+
|
|
174
|
+
except subprocess.TimeoutExpired:
|
|
175
|
+
webbrowser.open(url)
|
|
176
|
+
except Exception:
|
|
177
|
+
# Fall back to webbrowser.open() if explorer.exe fails
|
|
178
|
+
webbrowser.open(url)
|
|
179
|
+
else:
|
|
180
|
+
webbrowser.open(url)
|
|
181
|
+
|
|
182
|
+
else:
|
|
183
|
+
webbrowser.open(f"file://{html_file_path}")
|
|
141
184
|
|
|
142
185
|
def _create_html_tag(self, use_iframe: bool = True) -> Tag:
|
|
143
186
|
"""Create the MAIDR HTML using HTML tags."""
|
|
@@ -311,7 +354,7 @@ class Maidr:
|
|
|
311
354
|
# Render the plot inside an iframe if in a Jupyter notebook, Google Colab
|
|
312
355
|
# or VSCode notebook. No need for iframe if this is a Quarto document.
|
|
313
356
|
# For TypeScript we will use iframe by default for now
|
|
314
|
-
if use_iframe and (Environment.is_notebook() or Environment.is_shiny()):
|
|
357
|
+
if use_iframe and (Environment.is_flask() or Environment.is_notebook() or Environment.is_shiny()):
|
|
315
358
|
unique_id = "iframe_" + Maidr._unique_id()
|
|
316
359
|
|
|
317
360
|
def generate_iframe_script(unique_id: str) -> str:
|
|
@@ -1,11 +1,51 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
|
+
import subprocess
|
|
3
4
|
import sys
|
|
5
|
+
from typing import Union
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class Environment:
|
|
7
9
|
_engine = "ts"
|
|
8
10
|
|
|
11
|
+
@staticmethod
|
|
12
|
+
def is_flask() -> bool:
|
|
13
|
+
"""
|
|
14
|
+
Check if the current environment is a Flask application.
|
|
15
|
+
|
|
16
|
+
This method detects Flask applications by checking if Flask's app context
|
|
17
|
+
is available using `flask.has_app_context()`. The app context is Flask's
|
|
18
|
+
way of tracking the current application state and is only available when
|
|
19
|
+
code is running within a Flask application.
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
bool
|
|
24
|
+
True if the environment is a Flask application, False otherwise.
|
|
25
|
+
|
|
26
|
+
Examples
|
|
27
|
+
--------
|
|
28
|
+
>>> from maidr.util.environment import Environment
|
|
29
|
+
>>> Environment.is_flask()
|
|
30
|
+
False # When not in a Flask app
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
# Import Flask's has_app_context function
|
|
34
|
+
from flask import has_app_context
|
|
35
|
+
|
|
36
|
+
# has_app_context() returns True only when code is running within
|
|
37
|
+
# a Flask application context. This is Flask's built-in mechanism
|
|
38
|
+
# for detecting if the current execution environment is a Flask app.
|
|
39
|
+
#
|
|
40
|
+
# The app context is automatically created by Flask when:
|
|
41
|
+
# - A Flask app is running (app.run())
|
|
42
|
+
# - Code is executed within a Flask request context
|
|
43
|
+
# - The app context is manually pushed
|
|
44
|
+
return has_app_context()
|
|
45
|
+
except ImportError:
|
|
46
|
+
# Flask is not installed, so we're definitely not in a Flask app
|
|
47
|
+
return False
|
|
48
|
+
|
|
9
49
|
@staticmethod
|
|
10
50
|
def is_interactive_shell() -> bool:
|
|
11
51
|
"""Return True if the environment is an interactive shell."""
|
|
@@ -61,6 +101,93 @@ class Environment:
|
|
|
61
101
|
return False
|
|
62
102
|
except ImportError:
|
|
63
103
|
return False
|
|
104
|
+
@staticmethod
|
|
105
|
+
def is_wsl() -> bool:
|
|
106
|
+
"""
|
|
107
|
+
Check if the current environment is WSL (Windows Subsystem for Linux).
|
|
108
|
+
|
|
109
|
+
This method detects WSL environments by reading the `/proc/version` file
|
|
110
|
+
and checking for 'microsoft' or 'wsl' keywords in the version string.
|
|
111
|
+
WSL environments typically contain these identifiers in their kernel version.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
bool
|
|
116
|
+
True if the environment is WSL, False otherwise.
|
|
117
|
+
|
|
118
|
+
Examples
|
|
119
|
+
--------
|
|
120
|
+
>>> from maidr.util.environment import Environment
|
|
121
|
+
>>> Environment.is_wsl()
|
|
122
|
+
False # When not in WSL
|
|
123
|
+
"""
|
|
124
|
+
try:
|
|
125
|
+
with open('/proc/version', 'r') as f:
|
|
126
|
+
version_info = f.read().lower()
|
|
127
|
+
if 'microsoft' in version_info or 'wsl' in version_info:
|
|
128
|
+
return True
|
|
129
|
+
except FileNotFoundError:
|
|
130
|
+
pass
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def get_wsl_distro_name() -> str:
|
|
135
|
+
"""
|
|
136
|
+
Get the WSL distribution name from environment variables.
|
|
137
|
+
|
|
138
|
+
This method retrieves the WSL distribution name from the `WSL_DISTRO_NAME`
|
|
139
|
+
environment variable, which is automatically set by WSL when running
|
|
140
|
+
in a WSL environment.
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
str
|
|
145
|
+
The WSL distribution name (e.g., 'Ubuntu-20.04', 'Debian') if set,
|
|
146
|
+
otherwise an empty string.
|
|
147
|
+
|
|
148
|
+
Examples
|
|
149
|
+
--------
|
|
150
|
+
>>> from maidr.util.environment import Environment
|
|
151
|
+
>>> Environment.get_wsl_distro_name()
|
|
152
|
+
'' # When not in WSL or WSL_DISTRO_NAME not set
|
|
153
|
+
"""
|
|
154
|
+
return os.environ.get('WSL_DISTRO_NAME', '')
|
|
155
|
+
|
|
156
|
+
@staticmethod
|
|
157
|
+
def find_explorer_path() -> Union[str, None]:
|
|
158
|
+
"""
|
|
159
|
+
Find the correct path to explorer.exe in WSL environment.
|
|
160
|
+
|
|
161
|
+
This method checks if explorer.exe is available in the PATH
|
|
162
|
+
and returns the path if found.
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
str | None
|
|
167
|
+
The path to explorer.exe if found, None otherwise.
|
|
168
|
+
|
|
169
|
+
Examples
|
|
170
|
+
--------
|
|
171
|
+
>>> from maidr.util.environment import Environment
|
|
172
|
+
>>> Environment.find_explorer_path()
|
|
173
|
+
'/mnt/c/Windows/explorer.exe' # When found
|
|
174
|
+
"""
|
|
175
|
+
# Check if explorer.exe is in PATH
|
|
176
|
+
try:
|
|
177
|
+
result = subprocess.run(
|
|
178
|
+
['which', 'explorer.exe'],
|
|
179
|
+
capture_output=True,
|
|
180
|
+
text=True,
|
|
181
|
+
timeout=5
|
|
182
|
+
)
|
|
183
|
+
if result.returncode == 0:
|
|
184
|
+
return result.stdout.strip()
|
|
185
|
+
except Exception:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
|
|
64
191
|
|
|
65
192
|
@staticmethod
|
|
66
193
|
def get_renderer() -> str:
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "maidr"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.6.0"
|
|
8
8
|
description = "Multimodal Access and Interactive Data Representations"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "JooYoung Seo", email = "jseo1005@illinois.edu" },
|
|
@@ -55,7 +55,8 @@ dependencies = [
|
|
|
55
55
|
visualization = [
|
|
56
56
|
"matplotlib>=3.8",
|
|
57
57
|
"seaborn>=0.12",
|
|
58
|
-
"statsmodels>=0.14.4"
|
|
58
|
+
"statsmodels>=0.14.4",
|
|
59
|
+
"flask>=3.0.0"
|
|
59
60
|
]
|
|
60
61
|
jupyter = [
|
|
61
62
|
"jupyter>=1.0.0,<2",
|
|
@@ -67,6 +68,7 @@ test = [
|
|
|
67
68
|
"jupyter>=1.0.0,<2",
|
|
68
69
|
"pytest>=7.3.2,<8",
|
|
69
70
|
"pytest-mock>=3.12.0,<4",
|
|
71
|
+
"flask>=3.0.0"
|
|
70
72
|
]
|
|
71
73
|
|
|
72
74
|
[project.urls]
|
|
@@ -199,6 +199,15 @@ css = [
|
|
|
199
199
|
{ name = "tinycss2" },
|
|
200
200
|
]
|
|
201
201
|
|
|
202
|
+
[[package]]
|
|
203
|
+
name = "blinker"
|
|
204
|
+
version = "1.9.0"
|
|
205
|
+
source = { registry = "https://pypi.org/simple" }
|
|
206
|
+
sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" }
|
|
207
|
+
wheels = [
|
|
208
|
+
{ url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" },
|
|
209
|
+
]
|
|
210
|
+
|
|
202
211
|
[[package]]
|
|
203
212
|
name = "cachetools"
|
|
204
213
|
version = "6.1.0"
|
|
@@ -720,6 +729,25 @@ wheels = [
|
|
|
720
729
|
{ url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" },
|
|
721
730
|
]
|
|
722
731
|
|
|
732
|
+
[[package]]
|
|
733
|
+
name = "flask"
|
|
734
|
+
version = "3.1.1"
|
|
735
|
+
source = { registry = "https://pypi.org/simple" }
|
|
736
|
+
dependencies = [
|
|
737
|
+
{ name = "blinker" },
|
|
738
|
+
{ name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
|
739
|
+
{ name = "click", version = "8.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
|
740
|
+
{ name = "importlib-metadata", marker = "python_full_version < '3.10'" },
|
|
741
|
+
{ name = "itsdangerous" },
|
|
742
|
+
{ name = "jinja2" },
|
|
743
|
+
{ name = "markupsafe" },
|
|
744
|
+
{ name = "werkzeug" },
|
|
745
|
+
]
|
|
746
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" }
|
|
747
|
+
wheels = [
|
|
748
|
+
{ url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" },
|
|
749
|
+
]
|
|
750
|
+
|
|
723
751
|
[[package]]
|
|
724
752
|
name = "fonttools"
|
|
725
753
|
version = "4.58.5"
|
|
@@ -1059,6 +1087,15 @@ wheels = [
|
|
|
1059
1087
|
{ url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" },
|
|
1060
1088
|
]
|
|
1061
1089
|
|
|
1090
|
+
[[package]]
|
|
1091
|
+
name = "itsdangerous"
|
|
1092
|
+
version = "2.2.0"
|
|
1093
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1094
|
+
sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" }
|
|
1095
|
+
wheels = [
|
|
1096
|
+
{ url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" },
|
|
1097
|
+
]
|
|
1098
|
+
|
|
1062
1099
|
[[package]]
|
|
1063
1100
|
name = "jedi"
|
|
1064
1101
|
version = "0.19.2"
|
|
@@ -1638,7 +1675,7 @@ wheels = [
|
|
|
1638
1675
|
|
|
1639
1676
|
[[package]]
|
|
1640
1677
|
name = "maidr"
|
|
1641
|
-
version = "1.
|
|
1678
|
+
version = "1.5.0"
|
|
1642
1679
|
source = { editable = "." }
|
|
1643
1680
|
dependencies = [
|
|
1644
1681
|
{ name = "htmltools" },
|
|
@@ -1657,6 +1694,7 @@ jupyter = [
|
|
|
1657
1694
|
{ name = "jupyter" },
|
|
1658
1695
|
]
|
|
1659
1696
|
test = [
|
|
1697
|
+
{ name = "flask" },
|
|
1660
1698
|
{ name = "jupyter" },
|
|
1661
1699
|
{ name = "matplotlib", version = "3.9.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
|
1662
1700
|
{ name = "matplotlib", version = "3.10.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
|
@@ -1665,6 +1703,7 @@ test = [
|
|
|
1665
1703
|
{ name = "seaborn" },
|
|
1666
1704
|
]
|
|
1667
1705
|
visualization = [
|
|
1706
|
+
{ name = "flask" },
|
|
1668
1707
|
{ name = "matplotlib", version = "3.9.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
|
1669
1708
|
{ name = "matplotlib", version = "3.10.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
|
1670
1709
|
{ name = "seaborn" },
|
|
@@ -1684,6 +1723,8 @@ dev = [
|
|
|
1684
1723
|
|
|
1685
1724
|
[package.metadata]
|
|
1686
1725
|
requires-dist = [
|
|
1726
|
+
{ name = "flask", marker = "extra == 'test'", specifier = ">=3.0.0" },
|
|
1727
|
+
{ name = "flask", marker = "extra == 'visualization'", specifier = ">=3.0.0" },
|
|
1687
1728
|
{ name = "htmltools", specifier = ">=0.5" },
|
|
1688
1729
|
{ name = "ipykernel", marker = "extra == 'jupyter'", specifier = ">=6.0.0" },
|
|
1689
1730
|
{ name = "jupyter", marker = "extra == 'jupyter'", specifier = ">=1.0.0,<2" },
|
|
@@ -3900,6 +3941,18 @@ wheels = [
|
|
|
3900
3941
|
{ url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" },
|
|
3901
3942
|
]
|
|
3902
3943
|
|
|
3944
|
+
[[package]]
|
|
3945
|
+
name = "werkzeug"
|
|
3946
|
+
version = "3.1.3"
|
|
3947
|
+
source = { registry = "https://pypi.org/simple" }
|
|
3948
|
+
dependencies = [
|
|
3949
|
+
{ name = "markupsafe" },
|
|
3950
|
+
]
|
|
3951
|
+
sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" }
|
|
3952
|
+
wheels = [
|
|
3953
|
+
{ url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" },
|
|
3954
|
+
]
|
|
3955
|
+
|
|
3903
3956
|
[[package]]
|
|
3904
3957
|
name = "widgetsnbextension"
|
|
3905
3958
|
version = "4.0.14"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{maidr-1.4.10 → maidr-1.6.0}/docs/_extensions/shafayetShafee/line-highlight/line-highlight.lua
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{maidr-1.4.10 → maidr-1.6.0}/example/facet-subplots/matplotlib/example_mpl_facet_bar_plot.py
RENAMED
|
File without changes
|
{maidr-1.4.10 → maidr-1.6.0}/example/facet-subplots/matplotlib/example_mpl_facet_combined_plot.py
RENAMED
|
File without changes
|
|
File without changes
|
{maidr-1.4.10 → maidr-1.6.0}/example/facet-subplots/seaborn/example_sns_facet_combined_plot.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|