No project description provided
Project description
Stockula
Stockula is a comprehensive Python trading platform that provides tools for technical analysis, backtesting, data fetching, and price forecasting. Built with modern Python practices, it integrates popular financial libraries to offer a complete solution for quantitative trading strategy development.
- Stockula
โจ Features
- ๐ Technical Analysis: 40+ indicators (SMA, EMA, RSI, MACD, Bollinger Bands, etc.)
- ๐ Backtesting: Test trading strategies with realistic broker costs and commission structures
- ๐ Data Fetching: Real-time and historical market data via yfinance with intelligent SQLite caching
- ๐ฎ Price Forecasting: Automated time series forecasting with multiple backends:
- AutoGluon TimeSeries: Automated ML for accurate predictions (Python < 3.13)
- AutoGluon: Modern AutoML with deep learning models (DeepAR, Temporal Fusion Transformer)
- Chronos (GPU): Zero-shot forecasting with pretrained transformer models
- GluonTS (GPU): Advanced probabilistic models for uncertainty quantification
- Future prediction mode: Forecast N days from today
- Historical evaluation mode: Train/test split with accuracy metrics (RMSE, MAE, MASE)
- GPU Acceleration: Full CUDA support via PyTorch 2.8.0 base images
- ๐จ Rich CLI Interface: Beautiful progress bars, tables, and colored output
- ๐๏ธ Database Caching: Automatic SQLite caching for offline analysis and fast data access
- ๐ Modern Python: Built with uv for fast package management and Pydantic for configuration
๐ Quick Start
Installation
Method 1: Docker (Recommended for GPU Support)
# Standard CPU version
docker pull ghcr.io/mkm29/stockula:latest
docker run ghcr.io/mkm29/stockula:latest -m stockula --help
# GPU-accelerated version (PyTorch 2.8.0 with CUDA 12.9)
docker pull ghcr.io/mkm29/stockula-gpu:latest
docker run --gpus all ghcr.io/mkm29/stockula-gpu:latest -m stockula --help
# Run with mounted config file
docker run -v $(pwd)/.stockula.yaml:/app/.stockula.yaml ghcr.io/mkm29/stockula:latest \
-m stockula --ticker AAPL --mode forecast
GPU Docker Features:
- Based on PyTorch 2.8.0 official images for optimal compatibility
- Python 3.11 pre-installed
- Includes Chronos (zero-shot forecasting) and GluonTS (probabilistic models)
- Full AutoGluon TimeSeries support with GPU acceleration
- Non-root user
stockula(UID 1000) for security
Method 2: Local Installation with uv
-
Install uv (if not already installed):
curl -LsSf https://astral.sh/uv/install.sh | sh
-
Clone and install:
git clone https://github.com/mkm29/stockula.git cd stockula uv sync
-
For GPU support (optional):
# Install GPU extras (requires CUDA 11.8+ and compatible drivers) uv pip install -r requirements-gpu.txt --extra-index-url https://download.pytorch.org/whl/cu118
Basic Usage
# Analyze a single stock
uv run python -m stockula --ticker AAPL
# Run with configuration file
cp examples/config.simple.yaml .stockula.yaml
uv run python -m stockula
# Run specific analysis modes
uv run python -m stockula --ticker GOOGL --mode ta # Technical analysis
uv run python -m stockula --ticker MSFT --mode backtest # Backtesting (results sorted by return, highest first)
uv run python -m stockula --ticker NVDA --mode forecast # Forecasting with AutoGluon or fallback
# Show help
uv run python -m stockula --help
Configuration Example
data:
start_date: "2023-01-01"
end_date: null
portfolio:
initial_capital: 100000
allocation_method: equal_weight
tickers:
- symbol: AAPL
quantity: 10
- symbol: GOOGL
quantity: 5
backtest:
initial_cash: 10000.0
broker_config:
name: "robinhood" # Zero commission + TAF
strategies:
- name: smacross
parameters:
fast_period: 10
slow_period: 20
Using Chronos (Zero-Shot Forecasting)
Chronos provides zero-shot probabilistic forecasts using pretrained transformer models. Enable it via config:
# examples/config/forecast_chronos.yaml
data:
start_date: "2023-01-01"
portfolio:
allocation_method: equal_weight
tickers:
- symbol: AAPL
quantity: 1
forecast:
forecast_length: 7
prediction_interval: 0.9
# Select Chronos explicitly
models: "zero_shot" # or ["Chronos"]
# Optional: choose a specific pretrained Chronos model
# models: ["Chronos", "amazon/chronos-bolt-small"]
Run with:
uv run python -m stockula --config examples/config/forecast_chronos.yaml --ticker AAPL --mode forecast
# or
uv run python examples/forecast_chronos.py --ticker AAPL
Notes:
- When AutoGluon is available (Python 3.11/3.12), Stockula uses Chronos via AutoGluon to enable covariates and ensembling; otherwise it falls back to standalone Chronos.
- GPU strongly recommended. The GPU Docker image already includes
chronos-forecastingandgluonts[torch]==0.16.2. - If you set
forecast.modelsto"zero_shot"or include"Chronos", Chronos is selected automatically.
Backtest-Optimized Allocation
Stockula includes an advanced allocation strategy that uses historical backtesting to optimize portfolio allocation:
# .stockula.yaml for backtest-optimized allocation
portfolio:
initial_capital: 100000
allocation_method: backtest_optimized
tickers:
- symbol: AAPL
category: TECH
quantity: 0 # Placeholder - will be calculated
- symbol: SPY
category: INDEX
quantity: 0 # Placeholder - will be calculated
- symbol: GLD
category: COMMODITY
quantity: 0 # Placeholder - will be calculated
- symbol: NVDA
category: MOMENTUM
quantity: 0 # Placeholder - will be calculated
# Configure backtest optimization
backtest_optimization:
train_start_date: "2023-01-01"
train_end_date: "2023-12-31"
test_start_date: "2024-01-01"
test_end_date: "2024-06-30"
ranking_metric: "Return [%]" # Default, can also use "Sharpe Ratio", etc.
min_allocation_pct: 2.0
max_allocation_pct: 25.0
initial_allocation_pct: 2.0
The BacktestOptimizedAllocator will:
- Test 11 different trading strategies on each asset using training data
- Select the best-performing strategy for each asset
- Evaluate performance on test data
- Allocate capital based on test performance (higher return = larger allocation by default)
Forecast-Aware Optimization (NEW!)
You can now enhance allocation decisions by incorporating price forecasts:
backtest_optimization:
# ... existing configuration ...
# Enable forecast integration
use_forecast: true # Enable forecast-aware optimization
forecast_weight: 0.3 # 30% weight to forecast, 70% to historical
forecast_length: 30 # Predict 30 days ahead
forecast_backend: null # Auto-select best backend (chronos/autogluon/simple)
When enabled, the allocator will:
- Run historical backtesting as usual
- Generate price forecasts for each asset
- Combine historical performance with predicted returns using weighted scoring
- Allocate capital based on the combined score
This creates a more forward-looking allocation that balances proven historical performance with predicted future potential.
See the Allocation Strategies documentation for more details.
Note: Currently, the
backtest_optimizedallocation method requires placeholder quantities in the config. Full CLI integration is planned for a future release.
Forecast Evaluation
When running forecasts in evaluation mode (with train/test split), Stockula provides accuracy metrics:
Portfolio Value
โโโโโโโโโโโโโโโโโโโณโโโโโโโโโโโโโณโโโโโโโโโโโโโ
โ Metric โ Date โ Value โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ Observed Value โ 2025-04-01 โ $20,000.00 โ
โ Predicted Value โ 2025-04-30 โ $20,201.99 โ
โ Accuracy โ 2025-04-30 โ 92.4190% โ
โโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโ
How Accuracy is Calculated:
Portfolio accuracy uses MASE (Mean Absolute Scaled Error), a scale-independent metric that compares model performance to a naive forecast:
- MASE < 1.0: Model beats naive forecast (good performance)
- MASE = 1.0: Model equals naive forecast
- MASE > 1.0: Model worse than naive forecast
For example:
- If a stock's MASE is 0.8, the model is 20% better than a naive forecast
- The portfolio MASE is the average of all individual stock MASE values
This provides an intuitive measure where:
- 100% = Perfect prediction
- 90%+ = Excellent forecast
- 80-90% = Good forecast
- <80% = Consider improving model or data
๐ Documentation
For comprehensive documentation, visit our MkDocs Documentation Site:
๐ Getting Started
- Installation Guide - Detailed setup instructions
- Quick Start - Common workflows and examples
- Configuration - Complete configuration reference
๐ User Guide
- Architecture Overview - System design and data flow
- Data Fetching - Market data and caching system
- Technical Analysis - 40+ indicators and usage
- Backtesting - Strategy testing with realistic costs
- Allocation Strategies - Portfolio allocation methods including backtest optimization
- Forecasting - Time series prediction with AutoGluon
- Forecasting Models - Fast & full financial model details
- Rich CLI Features - Enhanced command-line interface
๐ง API Reference
- Strategies API - Built-in and custom trading strategies
- Broker Configuration - TODO Commission structures and fee models
- Data Models - TODO Pydantic models and validation
- Database API - TODO SQLite operations and CLI
๐ ๏ธ Development
- Testing - Comprehensive testing guide, strategy, and coverage
- CI/CD - Continuous integration and deployment with GitHub Actions
๐ Help
- Troubleshooting - Common issues and solutions
๐๏ธ Architecture
graph TB
subgraph "User Interface"
CLI["CLI<br/>cli.py"]
Config["Configuration<br/>.stockula.yaml"]
end
subgraph "Managers"
SM["Stockula Manager"]
TAM["Technical Analysis<br/>Manager"]
BTM["Backtesting<br/>Manager"]
FCM["Forecasting<br/>Manager"]
ALM["Allocator<br/>Manager"]
end
subgraph "Core Domain"
Factory["Domain Factory"]
Portfolio["Portfolio"]
Asset["Asset"]
end
subgraph "Allocation Module"
Allocator["Base Allocator"]
STD["Standard Allocator"]
OPT["Backtest Optimized<br/>Allocator"]
end
subgraph "Data Layer"
Fetcher["Data Fetcher<br/>yfinance wrapper"]
DB[("SQLite Database<br/>stockula.db")]
end
subgraph "Analysis Modules"
TA["Technical Analysis<br/>finta"]
BT["Backtesting<br/>strategies"]
FC["Forecasting<br/>AutoGluon/Simple"]
end
CLI --> Config
CLI --> SM
SM --> TAM
SM --> BTM
SM --> FCM
SM --> ALM
SM --> Factory
Config --> Factory
Factory --> Portfolio
ALM --> Allocator
STD --> Allocator
OPT --> Allocator
OPT --> BTM
TAM --> TA
BTM --> BT
FCM --> FC
TA --> Fetcher
BT --> Fetcher
FC --> Fetcher
Fetcher --> DB
style CLI fill:#2196F3,stroke:#1976D2,color:#fff
style SM fill:#9C27B0,stroke:#7B1FA2,color:#fff
style Config fill:#4CAF50,stroke:#388E3C,color:#fff
style DB fill:#FF9800,stroke:#F57C00,color:#fff
๐ Requirements
- Python: 3.11 or higher (3.11 recommended for GPU support)
- Operating System: macOS, Linux, or Windows
- Memory: 8GB RAM recommended (16GB+ for GPU operations)
- Storage: 100MB free space
- GPU (optional): NVIDIA GPU with CUDA 11.8+ for acceleration
Key Dependencies
- pandas: Data manipulation and analysis
- yfinance: Yahoo Finance data fetching
- finta: Financial technical analysis indicators
- backtesting: Strategy backtesting framework
- autogluon-timeseries: Advanced time series forecasting (optional, Python < 3.13)
- scikit-learn: Simple fallback forecasting for Python 3.13+
- autogluon (optional): Advanced AutoML forecasting with deep learning
- chronos-forecasting (GPU): Zero-shot time series forecasting with transformer models
- gluonts (GPU): Probabilistic time series modeling (DeepAR, Temporal Fusion Transformer)
- rich: Enhanced CLI formatting with progress bars and tables
- pydantic: Data validation and settings management
๐จ Rich CLI Examples
Progress Tracking
โ Backtesting SMACROSS on AAPL... โโโโโโโโโโโโโโโโโโโโโโโโโโโโ 85% 0:00:02
Results Tables
Portfolio Composition
โโโโโโโโโโณโโโโโโโโโโโโโโณโโโโโโโโโโโณโโโโโโโโโโโโโโโณโโโโโโโโโโโโโณโโโโโโโโโโโโ
โ Ticker โ Category โ Quantity โ Allocation % โ Value โ Status โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ SPY โ INDEX โ 1.00 โ 0.7% โ $637.10 โ Hold Only โ
โ VOO โ INDEX โ 1.00 โ 0.6% โ $585.58 โ Hold Only โ
โ DFUSX โ INDEX โ 1.00 โ 0.0% โ $42.40 โ Hold Only โ
โ FSKAX โ INDEX โ 1.00 โ 0.2% โ $175.65 โ Hold Only โ
โ FSMDX โ INDEX โ 199.00 โ 7.8% โ $7,279.42 โ Hold Only โ
โ FXAIX โ INDEX โ 1.00 โ 0.2% โ $221.98 โ Hold Only โ
โ NVDA โ MOMENTUM โ 1.00 โ 0.2% โ $173.50 โ Tradeable โ
โ AMD โ MOMENTUM โ 1.00 โ 0.2% โ $166.47 โ Tradeable โ
โ TSM โ MOMENTUM โ 1.00 โ 0.3% โ $245.60 โ Tradeable โ
โ AAPL โ MOMENTUM โ 1.00 โ 0.2% โ $213.88 โ Tradeable โ
โ MSFT โ MOMENTUM โ 1.00 โ 0.5% โ $513.71 โ Tradeable โ
โ GOOGL โ MOMENTUM โ 1.00 โ 0.2% โ $193.18 โ Tradeable โ
โ AMZN โ MOMENTUM โ 1.00 โ 0.2% โ $231.44 โ Tradeable โ
โ META โ MOMENTUM โ 1.00 โ 0.8% โ $712.68 โ Tradeable โ
โ TSLA โ MOMENTUM โ 1.00 โ 0.3% โ $316.06 โ Tradeable โ
โ PLTR โ MOMENTUM โ 469.00 โ 79.7% โ $74,477.20 โ Tradeable โ
โ LIDR โ SPECULATIVE โ 1631.00 โ 7.7% โ $7,233.48 โ Tradeable โ
โ OPEN โ SPECULATIVE โ 1.00 โ 0.0% โ $2.54 โ Tradeable โ
โ SOFI โ SPECULATIVE โ 1.00 โ 0.0% โ $21.20 โ Tradeable โ
โ IONQ โ SPECULATIVE โ 1.00 โ 0.0% โ $43.17 โ Tradeable โ
โโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโ
Ticker-Level Backtest Results
Ticker-Level Backtest Results
โโโโโโโโโโณโโโโโโโโโโโโโโโโโณโโโโโโโโโโโณโโโโโโโโโโโโโโโณโโโโโโโโโโโโโโโณโโโโโโโโโณโโโโโโโโโโโ
โ Ticker โ Strategy โ Return โ Sharpe Ratio โ Max Drawdown โ Trades โ Win Rate โ
โกโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฉ
โ NVDA โ VIDYA โ +27.67% โ 1.50 โ -3.43% โ 0 โ N/A โ
โ NVDA โ SMACROSS โ +44.60% โ 0.64 โ -38.09% โ 9 โ 44.4% โ
โ NVDA โ DOUBLEEMACROSS โ +27.67% โ 1.50 โ -3.43% โ 0 โ N/A โ
โ NVDA โ VAMA โ +41.34% โ 0.59 โ -42.46% โ 9 โ 33.3% โ
โ NVDA โ ER โ +60.37% โ 1.20 โ -14.22% โ 10 โ 40.0% โ
| ... โ ... โ ... โ ... โ ... โ ... โ ... โ
โโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโดโโโโโโโโโโโ
Strategy Summaries
Strategy summaries are displayed in descending order by "Return During Period" (highest returns first):
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ STRATEGY: DOUBLEEMACROSS โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ โ
โ Parameters: Default โ
โ Broker: robinhood (zero-commission) โ
โ โ
โ Portfolio Value at Start Date: $19,997.94 โ
โ Portfolio Value at End (Backtest): $30,261.55 โ
โ โ
โ Strategy Performance: โ
โ Average Return: +51.32% โ
โ Winning Stocks: 12 โ
โ Losing Stocks: 2 โ
โ Total Trades: 22 โ
โ โ
โ Return During Period: $10,263.61 (+51.32%) โ
โ โ
โ Detailed report saved to: results/reports/strategy_report_doubleemacross_20250727_221642.json โ
โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
๐ CI/CD
Continuous Integration
Stockula uses GitHub Actions for automated testing and deployment:
-
Testing (
test.yml): Runs on all pull requests and pushes to main- Linting: Code style checks with
ruff - Unit Tests: Fast, isolated tests with coverage reporting
- Integration Tests: Currently disabled, will test with SQLite database
- Linting: Code style checks with
-
Release Management (
release-please.yml): Automated versioning and releases- Monitors commits using Conventional Commits
- Creates release PRs automatically
- Publishes to PyPI on release
-
Docker Builds (
docker-build.yml): Multi-platform container images- Triggers on version tags (
v*) - Builds for
linux/amd64andlinux/arm64/v8 - Publishes to GitHub Container Registry
- Triggers on version tags (
Commit Guidelines
This project uses Conventional Commits:
feat:New featuresfix:Bug fixeschore:Maintenance tasksdocs:Documentation updatestest:Test additions or changes
๐ Links
- ๐ Full Documentation: docs/
- ๐ Issue Tracker: GitHub Issues
- ๐ก Feature Requests: GitHub Discussions
๐ License
MIT License - see LICENSE file for details.
๐ Git Flow & Release Process
We follow a Git Flow branching strategy with automated releases via Release Please.
Branching Strategy
graph LR
A[feature/*] -->|Push| K[Docker Build<br/>0.12.1-feat.branch.sha]
K -->|GHCR| L[ghcr.io/mkm29/stockula:feat]
A -->|PR| B[develop]
C[bugfix/*] -->|PR| B
B -->|Release Please| D[RC Release<br/>0.12.1-rc.1]
D -->|Docker Build| E[ghcr.io/mkm29/stockula:0.12.1-rc.1]
B -->|Promote PR| F[main]
F -->|Release Please| G[Stable Release<br/>v0.12.1]
G -->|Docker Build| H[ghcr.io/mkm29/stockula:v0.12.1]
G -->|Publish| I[PyPI]
J[hotfix/*] -->|PR| F
J -->|Auto-backport| B
develop- Integration branch for active developmentmain- Production-ready releases only- Feature branches (
feature/*) - New features - Bugfix branches (
bugfix/*) - Bug fixes - Hotfix branches (
hotfix/*) - Critical production fixes
Release Types
| Type | Branch | Git Tag | Docker Tag | Example |
|---|---|---|---|---|
| Feature Branch | feature/* | None | X.Y.Z-feat.<branch>.<sha> |
ghcr.io/mkm29/stockula:0.12.1-feat.new-api.a1b2c3d |
| Release Candidate | develop | 0.Y.Z-rc.N |
0.Y.Z-rc.N |
ghcr.io/mkm29/stockula:0.12.1-rc.1 |
| Stable Release | main | vX.Y.Z |
vX.Y.Z |
ghcr.io/mkm29/stockula:v0.12.1 |
Docker Images
Automated builds are triggered on releases and feature branch pushes:
| Image | Description | Latest Feature | Latest RC | Latest Stable |
|---|---|---|---|---|
ghcr.io/mkm29/stockula |
CLI with development tools | :feat |
:rc |
:latest |
ghcr.io/mkm29/stockula-gpu |
GPU-accelerated CLI (CUDA) | N/A | :rc |
:latest |
# Pull latest stable
docker pull ghcr.io/mkm29/stockula:latest
# Pull latest RC for testing
docker pull ghcr.io/mkm29/stockula:rc
# Pull latest feature branch build
docker pull ghcr.io/mkm29/stockula:feat
# Pull specific versions (tags match Git tags for releases)
docker pull ghcr.io/mkm29/stockula:v0.12.1 # Stable release
docker pull ghcr.io/mkm29/stockula:0.12.1-rc.1 # Release candidate
# Pull specific feature branch build
docker pull ghcr.io/mkm29/stockula:0.12.1-feat.new-api.a1b2c3d
# Run GPU-accelerated version (requires NVIDIA Docker runtime)
docker run --gpus all ghcr.io/mkm29/stockula-gpu:latest
# Check GPU availability
docker run --gpus all ghcr.io/mkm29/stockula-gpu:latest bash -c "/home/stockula/gpu_info.sh"
๐ค Contributing
Contributions are welcome! Please see our Contributing Guide for development setup and guidelines.
Development Setup
-
Install pre-commit hooks:
uv run pre-commit install
-
Run tests and linting:
# Run tests uv run pytest # Run linting (checks src, tests, and utils directories) uv run lint # Or run individual commands uv run ruff check src tests utils uv run ruff format --check src tests utils # Fix linting issues automatically uv run lint --fix
-
Utility commands:
# Check Python compatibility uv run check-python # Verify GPU packages uv run verify-gpu # Validate Docker configuration uv run validate-docker uv run verify-build # Format YAML files uv run format-yaml
See Utility Commands Documentation for all available commands.
-
Manual pre-commit run:
uv run pre-commit run --all-files
This project uses:
- Conventional Commits for commit messages
- Release Please for automated releases
- pre-commit for code quality checks
๐ For detailed documentation, examples, and API references, visit our comprehensive documentation site.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stockula-0.16.0.tar.gz.
File metadata
- Download URL: stockula-0.16.0.tar.gz
- Upload date:
- Size: 652.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ed8fb13cc4b557a8fe08ebc4d018e9845689c93ea5704d62e83eedcc516382c
|
|
| MD5 |
ec1c415f2fda1c0cda7ed44dc43ce795
|
|
| BLAKE2b-256 |
1fd658f0c2eb843d5181fcbba8236a640c2432652c785275a61a80aab57f5278
|
File details
Details for the file stockula-0.16.0-py3-none-any.whl.
File metadata
- Download URL: stockula-0.16.0-py3-none-any.whl
- Upload date:
- Size: 164.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33d97e93581f77eaa9731634d61e4c3dedc34d95a8c7e696ecbb1a3cb328ac9a
|
|
| MD5 |
78b6f068595bc0186f74972184b9ab00
|
|
| BLAKE2b-256 |
37afa29c4d02a96cc4f3e5785caae5522d7cde46ac751960f82de7bdb7a4b9f1
|