Marci: Marketing Science utilities for campaign analysis and simulation
Project description
Marci: Marketing Analytics and ROI Calculator
Marci is a comprehensive Python package for marketing analytics, campaign optimization, and ROI calculations. It provides tools for simulating marketing campaigns, analyzing performance, and optimizing budget allocation across multiple channels.
๐ Features
- ๐ฏ Campaign Simulation: Realistic campaign performance modeling with seasonality, conversion delays, and elasticity
- ๐ Portfolio Optimization: Multi-campaign budget allocation and performance analysis
- ๐ Statistical Distributions: Advanced probability distributions for modeling uncertainty
- ๐ Elasticity Analysis: Marketing mix modeling and response curve analysis
- ๐ Seasonality Modeling: Time-series patterns and seasonal adjustments
- โฑ๏ธ Conversion Delay: Realistic conversion timing modeling
- ๐ Visualization: Built-in plotting and charting capabilities
๐ฆ Installation
pip install marci
๐ฏ Quick Start
Marci provides powerful tools for marketing analytics. Let's start with the basics!
๐ง Installation and Import
Install the package and import the main classes:
# Standard package import - how users will use it
import marci
from marci import Campaign, Portfolio
# Display available classes
print("โ
Marci package imported successfully!")
print("Available classes:", [attr for attr in dir(marci) if not attr.startswith("_")])
โ
Marci package imported successfully!
Available classes: ['Budgets', 'Campaign', 'Conversion_Delay', 'Distribution', 'Elasticity', 'Lognormal', 'PerformanceStats', 'Portfolio', 'Seasonality', 'antidiag_sums', 'budgets', 'campaigns', 'fmt', 'get_campaign_colors', 'portfolio', 'simulated_data', 'style', 'utils']
๐ฏ Single Campaign Example
Let's start with a comprehensive single campaign example that demonstrates all the key features of Marci:
๐ Campaign Parameters Explained:
name: Campaign identifierstart_date: Campaign start dateduration: Campaign duration in daysbudget: Total campaign budgetcpm: Cost per thousand impressionscvr: Conversion rate (probability of conversion)aov: Average order valuecv: Coefficient of variation (volatility)seasonality_cv: Seasonality coefficient of variationconv_delay: Conversion delay probabilityconv_delay_duration: Conversion delay duration in dayselasticity: Marketing elasticity coefficientis_organic: Whether this is an organic campaign
C = Campaign(
name="Test Campaign",
start_date="2025-01-01",
duration=90,
budget=1000,
cpm=10,
cvr=1e-4,
aov=100,
cv=0.1,
seasonality_cv=0.2,
conv_delay=0.3,
conv_delay_duration=7,
elasticity=0.9,
is_organic=False,
)
# Display campaign statistics
C.print_stats()
# Visualize elasticity and conversion delay effects
C.plot_elasticity_and_delay()
# Plot campaign performance over time
C.plot()
# Access simulation data
print("Simulation DataFrame (first 5 rows):")
print(C.sim_data.df.head())
print("\nAggregated DataFrame (first 5 rows):")
print(C.sim_data.agg_df.head())
Simulating Campaign('Test Campaign', budget=$1,000, duration=90, exp_roas=100%, cv=10%)
group meta budget sales roas
metric name kind paid paid total paid total
0 Test Campaign Expected $90,000 $90,000 $90,000 100% 100%
1 Test Campaign Simulated $90,617 $97,622 $97,622 108% 108%
Simulation DataFrame (first 5 rows):
date name seasonality base budget elastic_budget \
0 2025-01-01 Test Campaign 1.070570 1000.0 1066.678961 1.066679
1 2025-01-02 Test Campaign 0.969624 1000.0 1077.424553 1.077425
2 2025-01-03 Test Campaign 0.999554 1000.0 843.474380 0.843474
3 2025-01-04 Test Campaign 1.054579 1000.0 1047.619627 1.047620
4 2025-01-05 Test Campaign 1.096727 1000.0 1029.258477 1.029258
elastic_returns imps convs sales is_organic roas
0 1.059816 96797.0 7.0 649.374062 False 0.608781
1 1.069420 88450.0 11.0 1128.692625 False 1.047584
2 0.857955 91293.0 11.0 1102.327693 False 1.306889
3 1.042757 104047.0 10.0 840.966592 False 0.802740
4 1.026295 110951.0 11.0 1477.024418 False 1.435037
Aggregated DataFrame (first 5 rows):
Metric Budget Sales
Name Test Campaign All All
date
2025-01-01 00:00:00 1066.678961 1066.678961 649.374062
2025-01-02 00:00:00 1077.424553 1077.424553 1128.692625
2025-01-03 00:00:00 843.474380 843.474380 1102.327693
2025-01-04 00:00:00 1047.619627 1047.619627 840.966592
2025-01-05 00:00:00 1029.258477 1029.258477 1477.024418
๐ Portfolio Management
Now let's explore portfolio management with multiple campaigns. This example shows how to create and manage a portfolio of campaigns with different characteristics:
๐ข Portfolio Campaign Types:
- Stable Organic: Low volatility organic campaign
- High Performance: High conversion rate paid campaign
- Low Performance: Lower conversion rate paid campaign
campaigns = [
Campaign(
name="Stable Organic",
start_date="2025-01-01",
cv=0,
seasonality_cv=0,
duration=90,
is_organic=True,
),
Campaign(
name="High Performace",
cvr=0.0015,
start_date="2025-02-01",
duration=20,
),
Campaign(
name="Low Performance",
cvr=0.0005,
start_date="2025-03-01",
duration=30,
),
]
P = Portfolio(campaigns)
# Display portfolio statistics
P.print_stats()
# Visualize portfolio performance
P.plot()
# Access simulation data
print("Portfolio Simulation DataFrame (first 5 rows):")
print(P.sim_data.df.head())
print("\nPortfolio Aggregated DataFrame (first 5 rows):")
print(P.sim_data.agg_df.head())
Budgets('All Budgets', total=$3,000, {'High Performace': $1,000, 'Low Performance': $1,000, 'Stable Organic': $1,000})
Simulating Campaign('High Performace', budget=$1,000, duration=20, exp_roas=150%, cv=10%)
Simulating Campaign('Low Performance', budget=$1,000, duration=30, exp_roas=50%, cv=10%)
Simulating Campaign('Stable Organic', budget=$1,000, duration=90, exp_roas=100%, cv=0%)
group meta budget sales roas
metric name kind paid paid total paid total
0 Portfolio Expected $50,000 $45,000 $135,000 90% 270%
1 Portfolio Simulated $49,271 $44,632 $136,402 91% 277%
Portfolio Simulation DataFrame (first 5 rows):
date name seasonality base budget \
0 2025-01-01 Stable Organic 1.0 1000.0 1000.000565
1 2025-01-02 Stable Organic 1.0 1000.0 1000.000427
2 2025-01-03 Stable Organic 1.0 1000.0 1000.001450
3 2025-01-04 Stable Organic 1.0 1000.0 999.999268
4 2025-01-05 Stable Organic 1.0 1000.0 999.999955
elastic_budget elastic_returns imps convs sales is_organic \
0 1.000001 1.000000 100382.0 65.0 649.999866 True
1 1.000000 1.000000 99524.0 81.0 810.000592 True
2 1.000001 1.000001 100650.0 77.0 770.000795 True
3 0.999999 0.999999 100233.0 77.0 770.000925 True
4 1.000000 1.000000 99475.0 80.0 800.000148 True
roas
0 0.649999
1 0.810000
2 0.770000
3 0.770001
4 0.800000
Portfolio Aggregated DataFrame (first 5 rows):
Metric Budget \
Name High Performace Low Performance Stable Organic All
date
2025-01-01 00:00:00 0.0 0.0 0.0 0.0
2025-01-02 00:00:00 0.0 0.0 0.0 0.0
2025-01-03 00:00:00 0.0 0.0 0.0 0.0
2025-01-04 00:00:00 0.0 0.0 0.0 0.0
2025-01-05 00:00:00 0.0 0.0 0.0 0.0
Metric Sales
Name All
date
2025-01-01 00:00:00 649.999866
2025-01-02 00:00:00 810.000592
2025-01-03 00:00:00 770.000795
2025-01-04 00:00:00 770.000925
2025-01-05 00:00:00 800.000148
๐ฏ Advanced Portfolio Scenarios
This example demonstrates more complex portfolio scenarios with various campaign types and characteristics:
๐ Campaign Types in Advanced Portfolio:
- Noisy Organic Trend: Organic campaign with seasonal patterns
- One Time Organic Spike: Short-duration high-budget organic campaign
- High Performance Non-Elastic: High CVR but low elasticity
- Medium Performance Elastic: Balanced performance with good elasticity
- Low Performance Elastic: Lower CVR but responsive to budget changes
campaigns = [
Campaign(
name="Noisy Organic Trend",
start_date="2025-01-01",
duration=90,
budget=2000,
seasonality_cv=0.3,
is_organic=True,
),
Campaign(
name="One Time Organic Spike",
start_date="2025-02-01",
duration=3,
budget=10000,
seasonality_cv=1,
conv_delay=0.6,
conv_delay_duration=28,
is_organic=True,
),
Campaign(
name="High Performace Non-Elastic",
start_date="2025-01-01",
duration=90,
budget=1000,
cvr=0.0015,
elasticity=0.6,
),
Campaign(
name="Medium Performace Elastic",
start_date="2025-01-01",
duration=90,
budget=1000,
cvr=0.001,
elasticity=0.8,
),
Campaign(
name="Low Performance Elastic",
start_date="2025-01-01",
duration=90,
budget=1000,
cvr=0.0005,
elasticity=0.8,
),
]
P = Portfolio(campaigns)
# Display portfolio statistics
P.print_stats()
# Visualize portfolio performance
P.plot()
# Access simulation data
print("Advanced Portfolio Simulation DataFrame (first 5 rows):")
print(P.sim_data.df.head())
print("\nAdvanced Portfolio Aggregated DataFrame (first 5 rows):")
print(P.sim_data.agg_df.head())
Budgets('All Budgets', total=$15,000, {'High Performace Non-Elastic': $1,000, 'Medium Performace Elastic': $1,000, 'Low Performance Elastic': $1,000, 'Noisy Organic Trend': $2,000, 'One Time Organic Spike': $10,000})
Simulating Campaign('High Performace Non-Elastic', budget=$1,000, duration=90, exp_roas=150%, cv=10%)
Simulating Campaign('Medium Performace Elastic', budget=$1,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('Low Performance Elastic', budget=$1,000, duration=90, exp_roas=50%, cv=10%)
Simulating Campaign('Noisy Organic Trend', budget=$2,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('One Time Organic Spike', budget=$10,000, duration=3, exp_roas=100%, cv=10%)
group meta budget sales roas
metric name kind paid paid total paid total
0 Portfolio Expected $270,000 $270,000 $480,000 100% 178%
1 Portfolio Simulated $272,299 $267,292 $470,277 98% 173%
Advanced Portfolio Simulation DataFrame (first 5 rows):
date name seasonality base budget \
0 2025-01-01 High Performace Non-Elastic 0.702271 1000.0 661.935832
1 2025-01-01 Low Performance Elastic 0.931531 1000.0 854.011306
2 2025-01-01 Medium Performace Elastic 0.833052 1000.0 636.416261
3 2025-01-01 Noisy Organic Trend 0.607796 2000.0 1192.438161
4 2025-01-02 High Performace Non-Elastic 0.602950 1000.0 574.981623
elastic_budget elastic_returns imps convs sales is_organic \
0 0.661936 0.780710 76205.0 79.0 1020.004479 False
1 0.854011 0.881396 97647.0 39.0 361.154190 False
2 0.636416 0.696615 78609.0 53.0 526.351551 False
3 0.596219 0.661188 98963.0 79.0 846.659166 True
4 0.574982 0.717451 59007.0 72.0 704.151962 False
roas
0 1.540942
1 0.422892
2 0.827055
3 0.710024
4 1.224651
Advanced Portfolio Aggregated DataFrame (first 5 rows):
Metric Budget \
Name High Performace Non-Elastic Low Performance Elastic
date
2025-01-01 00:00:00 661.935832 854.011306
2025-01-02 00:00:00 574.981623 925.368919
2025-01-03 00:00:00 671.956746 1050.061300
2025-01-04 00:00:00 506.515796 836.507017
2025-01-05 00:00:00 595.779763 850.138304
Metric \
Name Medium Performace Elastic Noisy Organic Trend
date
2025-01-01 00:00:00 636.416261 0.0
2025-01-02 00:00:00 823.136665 0.0
2025-01-03 00:00:00 733.582761 0.0
2025-01-04 00:00:00 980.154547 0.0
2025-01-05 00:00:00 1024.326573 0.0
Metric Sales
Name One Time Organic Spike All All
date
2025-01-01 00:00:00 0.0 2152.363399 2754.169385
2025-01-02 00:00:00 0.0 2323.487207 2920.950222
2025-01-03 00:00:00 0.0 2455.600807 2676.413372
2025-01-04 00:00:00 0.0 2323.177359 3770.815142
2025-01-05 00:00:00 0.0 2470.244640 3491.831445
๐ฐ Budget Optimization
One of Marci's most powerful features is budget optimization. Let's explore how to optimize budget allocation across campaigns:
๐ฏ Optimization Process:
- Default Budgets: Start with current budget allocation
- Find Optimal: Use Marci's optimization algorithm to find the best allocation
- Simulate Results: Run simulations with optimized budgets
- Compare Performance: Analyze the improvement in ROI and sales
# Get default budget allocation
default_budgets = P.budgets
print("Default Budgets:")
print(default_budgets)
# Find optimal budget allocation with $3,000 total budget
optimal_budgets = P.find_optimal_budgets(3000)
print("\nOptimal Budgets (Total: $3,000):")
print(optimal_budgets)
# Simulate outcomes with optimal budgets
P.sim_outcomes(optimal_budgets)
# Display performance statistics with optimized budgets
P.print_stats(optimal_budgets)
# Visualize the optimized portfolio performance
P.plot()
Default Budgets:
Budgets('Default Budget', total=$3,000, {'High Performace Non-Elastic': $1,000, 'Medium Performace Elastic': $1,000, 'Low Performance Elastic': $1,000})
Optimal Budgets (Total: $3,000):
Budgets('Optimal Budget', total=$3,000, {'High Performace Non-Elastic': $1,577, 'Medium Performace Elastic': $1,380, 'Low Performance Elastic': $43})
Budgets('Optimal Budget', total=$15,000, {'High Performace Non-Elastic': $1,577, 'Medium Performace Elastic': $1,380, 'Low Performance Elastic': $43, 'Noisy Organic Trend': $2,000, 'One Time Organic Spike': $10,000})
Simulating Campaign('High Performace Non-Elastic', budget=$1,000, duration=90, exp_roas=150%, cv=10%)
Simulating Campaign('Medium Performace Elastic', budget=$1,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('Low Performance Elastic', budget=$1,000, duration=90, exp_roas=50%, cv=10%)
Simulating Campaign('Noisy Organic Trend', budget=$2,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('One Time Organic Spike', budget=$10,000, duration=3, exp_roas=100%, cv=10%)
Budgets('Optimal Budget', total=$15,000, {'High Performace Non-Elastic': $1,577, 'Medium Performace Elastic': $1,380, 'Low Performance Elastic': $43, 'Noisy Organic Trend': $2,000, 'One Time Organic Spike': $10,000})
Simulating Campaign('High Performace Non-Elastic', budget=$1,000, duration=90, exp_roas=150%, cv=10%)
Simulating Campaign('Medium Performace Elastic', budget=$1,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('Low Performance Elastic', budget=$1,000, duration=90, exp_roas=50%, cv=10%)
Simulating Campaign('Noisy Organic Trend', budget=$2,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('One Time Organic Spike', budget=$10,000, duration=3, exp_roas=100%, cv=10%)
group meta budget sales roas
metric name kind paid paid total paid total
0 Portfolio Expected $270,000 $297,515 $507,515 110% 188%
1 Portfolio Simulated $270,639 $295,977 $501,271 109% 185%
๐ High Budget Optimization
Let's explore what happens when we have a much larger budget to work with. This demonstrates how Marci scales with different budget constraints:
๐ก Key Insights:
- Elasticity Matters: Campaigns with higher elasticity get more budget allocation
- Diminishing Returns: Some campaigns may receive minimal allocation due to poor performance
- ROI Optimization: The algorithm maximizes overall portfolio ROI
# Get default budget allocation
default_budgets = P.budgets
print("Default Budgets:")
print(default_budgets)
# Find optimal budget allocation with $30,000 total budget
optimal_budgets = P.find_optimal_budgets(30000)
print("\nOptimal Budgets (Total: $30,000):")
print(optimal_budgets)
# Simulate outcomes with high budget optimization
P.sim_outcomes(optimal_budgets)
# Display performance statistics with high budget optimization
P.print_stats(optimal_budgets)
# Visualize the high-budget optimized portfolio performance
P.plot()
Default Budgets:
Budgets('Default Budget', total=$3,000, {'High Performace Non-Elastic': $1,000, 'Medium Performace Elastic': $1,000, 'Low Performance Elastic': $1,000})
Optimal Budgets (Total: $30,000):
Budgets('Optimal Budget', total=$30,000, {'High Performace Non-Elastic': $6,421, 'Medium Performace Elastic': $22,875, 'Low Performance Elastic': $704})
Budgets('Optimal Budget', total=$42,000, {'High Performace Non-Elastic': $6,421, 'Medium Performace Elastic': $22,875, 'Low Performance Elastic': $704, 'Noisy Organic Trend': $2,000, 'One Time Organic Spike': $10,000})
Simulating Campaign('High Performace Non-Elastic', budget=$1,000, duration=90, exp_roas=150%, cv=10%)
Simulating Campaign('Medium Performace Elastic', budget=$1,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('Low Performance Elastic', budget=$1,000, duration=90, exp_roas=50%, cv=10%)
Simulating Campaign('Noisy Organic Trend', budget=$2,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('One Time Organic Spike', budget=$10,000, duration=3, exp_roas=100%, cv=10%)
Budgets('Optimal Budget', total=$42,000, {'High Performace Non-Elastic': $6,421, 'Medium Performace Elastic': $22,875, 'Low Performance Elastic': $704, 'Noisy Organic Trend': $2,000, 'One Time Organic Spike': $10,000})
Simulating Campaign('High Performace Non-Elastic', budget=$1,000, duration=90, exp_roas=150%, cv=10%)
Simulating Campaign('Medium Performace Elastic', budget=$1,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('Low Performance Elastic', budget=$1,000, duration=90, exp_roas=50%, cv=10%)
Simulating Campaign('Noisy Organic Trend', budget=$2,000, duration=90, exp_roas=100%, cv=10%)
Simulating Campaign('One Time Organic Spike', budget=$10,000, duration=3, exp_roas=100%, cv=10%)
group meta budget sales roas
metric name kind paid paid total paid total
0 Portfolio Expected $270,000 $1,546,840 $1,756,840 573% 651%
1 Portfolio Simulated $2,706,257 $1,551,074 $1,768,631 57% 65%
๐ Understanding the Results
๐ฏ Key Metrics Explained:
Campaign Performance Metrics:
- Expected ROAS: Expected return on ad spend
- Simulated ROAS: Actual simulated performance
- Total Sales: Combined organic and paid sales
- Budget Allocation: How budget is distributed across campaigns
Portfolio Optimization Insights:
- Elasticity Impact: Higher elasticity campaigns receive more budget
- Performance Scaling: Better performing campaigns get priority
- ROI Maximization: Algorithm optimizes for maximum overall return
๐ Visualization Features:
- Timeline Plots: Show performance over time
- Elasticity Curves: Demonstrate response to budget changes
- Conversion Delay: Show realistic conversion timing
- Seasonality Patterns: Display seasonal variations
๐ง Advanced Features
๐ฏ Campaign Types and Use Cases:
Organic Campaigns:
- Set
is_organic=True - No CPM or CVR required
- Can have seasonality and conversion delays
- Represent organic traffic and brand awareness
Paid Campaigns:
- Require CPM, CVR, and AOV parameters
- Can have elasticity for budget optimization
- Support various performance characteristics
- Ideal for paid advertising channels
๐ Statistical Modeling:
Uncertainty Modeling:
- Coefficient of Variation (CV): Controls performance volatility
- Seasonality CV: Models seasonal patterns and trends
- Conversion Delay: Realistic conversion timing
- Elasticity: Response to budget changes
Distribution Support:
- Lognormal distributions for realistic performance modeling
- Poisson processes for conversion events
- Beta distributions for conversion rates
- Combined distributions for complex scenarios
๐ Getting Started with Your Own Data
๐ Step-by-Step Guide:
-
Define Your Campaigns:
campaigns = [ Campaign(name="Google Ads", cpm=20, cvr=0.001, aov=100, budget=5000), Campaign(name="Facebook", cpm=15, cvr=0.0008, aov=80, budget=3000), Campaign(name="Organic", is_organic=True, budget=2000), ]
-
Create Your Portfolio:
portfolio = Portfolio(campaigns)
-
Analyze Performance:
portfolio.print_stats() portfolio.plot()
-
Optimize Budgets:
optimal = portfolio.find_optimal_budgets(10000) portfolio.sim_outcomes(optimal)
๐ก Pro Tips:
- Start with simple campaigns and gradually add complexity
- Use realistic parameters based on your historical data
- Experiment with different elasticity values
- Consider seasonality for time-sensitive campaigns
- Use conversion delays for more realistic modeling
๐ API Reference
๐ฏ Core Classes:
Campaign:
Campaign(name, start_date, duration, budget, cpm, cvr, aov, cv, seasonality_cv, conv_delay, conv_delay_duration, elasticity, is_organic)print_stats(): Display campaign performance statisticsplot(): Visualize campaign performanceplot_elasticity_and_delay(): Show elasticity and conversion delay effectssim_data: Access simulation data
Portfolio:
Portfolio(campaigns): Create portfolio from list of campaignsprint_stats(budgets=None): Display portfolio statisticsplot(): Visualize portfolio performancefind_optimal_budgets(total_budget): Find optimal budget allocationsim_outcomes(budgets=None): Run simulations with given budgetssim_data: Access simulation data
๐ Data Structures:
Simulation Data (sim_data):
df: Detailed daily performance dataagg_df: Aggregated performance metrics
Budget Objects:
total_budget: Total budget amountcampaign_budgets: Dictionary of campaign-specific budgets
๐ค Contributing
We welcome contributions! Please see our Contributing Guidelines for details.
๐ Reporting Issues
If you find a bug or have a feature request, please open an issue on GitHub.
๐ Documentation
Help us improve the documentation by submitting pull requests or suggesting improvements.
๐ Acknowledgments
Thanks to all contributors and the open-source community for making this project possible!
Happy Marketing Analytics! ๐๐
Project details
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 marci-0.2.3.tar.gz.
File metadata
- Download URL: marci-0.2.3.tar.gz
- Upload date:
- Size: 53.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d91f3015efcdc63c0ed29644140e2908e77cc24af759104b055a8cd3eafc72a0
|
|
| MD5 |
a2bcac57eacdd91833aee7b591e827c8
|
|
| BLAKE2b-256 |
35eaa28c99f2099e1bacca6031bf64845080b3026c2e38a91d4ef2a904702b37
|
File details
Details for the file marci-0.2.3-py3-none-any.whl.
File metadata
- Download URL: marci-0.2.3-py3-none-any.whl
- Upload date:
- Size: 28.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
432768c5c6645b015a804b79211b0207aa7a3b671674c2fc752f0989160a0df3
|
|
| MD5 |
39a387102a2a4b43c4c17e626ea57a87
|
|
| BLAKE2b-256 |
f948ca5352ba8e20ef52da7e7179a73d8a85b832f40a5d2f014cdc2b13e1b14e
|