strategic-intelligence-mcp
Version:
Strategic Intelligence MCP Server - connecting technical progress to business outcomes with systematic strategic planning
760 lines • 33.6 kB
JavaScript
// Strategic reporting and export capabilities
import { v4 as uuidv4 } from 'uuid';
export class StrategicReporting {
reports = new Map();
templates = new Map();
constructor() {
this.initializeTemplates();
}
initializeTemplates() {
// Executive Summary Template
this.templates.set('executive-summary', {
id: 'executive-summary',
name: 'Executive Summary Report',
type: 'executive-summary',
sections: [
{ type: 'summary', title: 'Executive Overview', order: 1 },
{ type: 'metrics', title: 'Key Performance Indicators', order: 2 },
{ type: 'analysis', title: 'Strategic Highlights', order: 3 },
{ type: 'forecast', title: 'Outlook & Projections', order: 4 },
{ type: 'recommendations', title: 'Strategic Recommendations', order: 5 }
],
requiredData: ['milestones', 'goals', 'forecasts', 'competitiveIntel'],
confidentiality: 'board-only'
});
// Board Presentation Template
this.templates.set('board-presentation', {
id: 'board-presentation',
name: 'Board Presentation Report',
type: 'board-presentation',
sections: [
{ type: 'summary', title: 'Strategic Overview', order: 1 },
{ type: 'metrics', title: 'Business Performance', order: 2 },
{ type: 'analysis', title: 'Competitive Position', order: 3 },
{ type: 'forecast', title: 'Financial Projections', order: 4 },
{ type: 'recommendations', title: 'Board Actions Required', order: 5 },
{ type: 'appendix', title: 'Supporting Data', order: 6 }
],
requiredData: ['milestones', 'goals', 'forecasts', 'competitiveIntel', 'strategyGaps'],
confidentiality: 'board-only'
});
// Investor Update Template
this.templates.set('investor-update', {
id: 'investor-update',
name: 'Investor Update Report',
type: 'investor-update',
sections: [
{ type: 'summary', title: 'Company Highlights', order: 1 },
{ type: 'metrics', title: 'Growth Metrics', order: 2 },
{ type: 'analysis', title: 'Market Progress', order: 3 },
{ type: 'forecast', title: 'Revenue Outlook', order: 4 }
],
requiredData: ['milestones', 'goals', 'forecasts'],
confidentiality: 'confidential'
});
}
async generateReport(params) {
const template = params.templateId ? this.templates.get(params.templateId) : null;
const report = {
id: uuidv4(),
title: this.generateReportTitle(params.type, params.period),
type: params.type,
generated: new Date().toISOString(),
period: params.period,
sections: [],
metadata: {
generatedBy: 'Strategic CTO MCP Server',
version: '1.0.0',
confidentiality: template?.confidentiality || 'internal',
recipients: params.options?.recipients
},
format: params.options?.format || 'markdown'
};
// Generate sections based on template or type
if (template) {
report.sections = await this.generateSectionsFromTemplate(template, params.data, params.period);
}
else {
report.sections = await this.generateDefaultSections(params.type, params.data, params.period);
}
// Store report
this.reports.set(report.id, report);
// Export if requested
if (params.options?.format && params.options.format !== 'json') {
report.exportPath = await this.exportReport(report);
}
return report;
}
generateReportTitle(type, period) {
const startDate = new Date(period.start).toLocaleDateString('en-US', { month: 'short', year: 'numeric' });
const endDate = new Date(period.end).toLocaleDateString('en-US', { month: 'short', year: 'numeric' });
const titles = {
'executive-summary': `Executive Strategy Summary`,
'detailed-analysis': `Detailed Strategic Analysis`,
'board-presentation': `Board Strategic Review`,
'investor-update': `Investor Update`,
'team-dashboard': `Team Strategy Dashboard`
};
return `${titles[type] || 'Strategic Report'} | ${startDate} - ${endDate}`;
}
async generateSectionsFromTemplate(template, data, period) {
const sections = [];
for (const sectionTemplate of template.sections) {
const section = await this.generateSection(sectionTemplate.type, sectionTemplate.title, sectionTemplate.order, data, period);
sections.push(section);
}
return sections;
}
async generateDefaultSections(type, data, period) {
const sections = [];
// Always include executive summary
sections.push(await this.generateSection('summary', 'Executive Summary', 1, data, period));
// Add type-specific sections
switch (type) {
case 'executive-summary':
sections.push(await this.generateSection('metrics', 'Key Metrics', 2, data, period));
sections.push(await this.generateSection('forecast', 'Strategic Outlook', 3, data, period));
sections.push(await this.generateSection('recommendations', 'Recommendations', 4, data, period));
break;
case 'detailed-analysis':
sections.push(await this.generateSection('metrics', 'Performance Metrics', 2, data, period));
sections.push(await this.generateSection('analysis', 'Strategic Analysis', 3, data, period));
sections.push(await this.generateSection('forecast', 'Projections', 4, data, period));
sections.push(await this.generateSection('recommendations', 'Strategic Actions', 5, data, period));
sections.push(await this.generateSection('appendix', 'Supporting Data', 6, data, period));
break;
case 'board-presentation':
sections.push(await this.generateSection('metrics', 'Business Performance', 2, data, period));
sections.push(await this.generateSection('analysis', 'Market Position', 3, data, period));
sections.push(await this.generateSection('forecast', 'Financial Outlook', 4, data, period));
sections.push(await this.generateSection('recommendations', 'Board Actions', 5, data, period));
break;
}
return sections;
}
async generateSection(type, title, order, data, period) {
const section = {
id: uuidv4(),
title,
type,
order,
content: {},
visualizations: [],
tables: []
};
switch (type) {
case 'summary':
section.content = this.generateExecutiveSummary(data, period);
break;
case 'metrics':
section.content = this.generateMetricsSection(data, period);
section.visualizations = this.generateMetricsVisualizations(data);
section.tables = this.generateMetricsTables(data);
break;
case 'analysis':
section.content = this.generateAnalysisSection(data, period);
section.visualizations = this.generateAnalysisVisualizations(data);
break;
case 'forecast':
section.content = this.generateForecastSection(data, period);
section.visualizations = this.generateForecastVisualizations(data);
section.tables = this.generateForecastTables(data);
break;
case 'recommendations':
section.content = this.generateRecommendationsSection(data, period);
section.tables = this.generateRecommendationsTables(data);
break;
case 'appendix':
section.content = this.generateAppendixSection(data, period);
section.tables = this.generateAppendixTables(data);
break;
}
return section;
}
generateExecutiveSummary(data, period) {
const summary = {
overview: '',
keyHighlights: [],
criticalIssues: [],
strategicWins: []
};
// Milestone progress
if (data.milestones) {
const completed = data.milestones.filter((m) => m.status === 'completed').length;
const total = data.milestones.length;
summary.overview += `Technical Progress: ${completed}/${total} milestones completed (${Math.round(completed / total * 100)}%). `;
}
// Goal health
if (data.goals) {
const healthyGoals = data.goals.filter((g) => g.confidence >= 70).length;
const totalGoals = data.goals.length;
summary.overview += `Business Goals: ${healthyGoals}/${totalGoals} on track. `;
}
// Revenue projections
if (data.forecasts && data.forecasts.length > 0) {
const avgRevenue = data.forecasts.reduce((sum, f) => sum + f.businessMetrics.projectedRevenue.realistic, 0) / data.forecasts.length;
summary.overview += `Projected Revenue: $${Math.round(avgRevenue).toLocaleString()}. `;
}
// Key highlights
if (data.milestones) {
const criticalCompleted = data.milestones.filter((m) => m.status === 'completed' && m.businessContext.strategicImportance >= 80);
criticalCompleted.forEach((m) => {
summary.keyHighlights.push(`Completed: ${m.name} - ${m.businessContext.competitiveAdvantage}`);
});
}
// Critical issues
if (data.strategyGaps) {
const criticalGaps = data.strategyGaps.filter((g) => g.severity === 'critical');
criticalGaps.forEach((g) => {
summary.criticalIssues.push(`${g.description} (Impact: $${g.estimatedImpact.revenueAtRisk.toLocaleString()})`);
});
}
// Strategic wins
if (data.competitiveIntel) {
data.competitiveIntel.opportunityMapping.forEach((o) => {
if (o.potentialReturn > 100000) {
summary.strategicWins.push(`Opportunity: ${o.description} ($${o.potentialReturn.toLocaleString()} potential)`);
}
});
}
return summary;
}
generateMetricsSection(data, period) {
const metrics = {
technical: {},
business: {},
competitive: {}
};
// Technical metrics
if (data.milestones) {
metrics.technical = {
totalMilestones: data.milestones.length,
completed: data.milestones.filter((m) => m.status === 'completed').length,
inProgress: data.milestones.filter((m) => m.status === 'in-progress').length,
delayed: data.milestones.filter((m) => m.status === 'delayed').length,
velocity: this.calculateVelocity(data.milestones),
complexityDistribution: this.getComplexityDistribution(data.milestones)
};
}
// Business metrics
if (data.goals) {
metrics.business = {
totalGoals: data.goals.length,
activeGoals: data.goals.filter((g) => g.status === 'active').length,
averageConfidence: data.goals.reduce((sum, g) => sum + (g.confidence || 50), 0) / data.goals.length,
categoryBreakdown: this.getCategoryBreakdown(data.goals)
};
}
// Competitive metrics
if (data.competitiveIntel) {
metrics.competitive = {
threatLevel: data.competitiveIntel.threatAssessment.overallThreatLevel,
opportunities: data.competitiveIntel.opportunityMapping.length,
competitorCount: data.competitiveIntel.competitorProfiles.length,
marketPosition: data.competitiveIntel.marketAnalysis.competitiveIntensity
};
}
return metrics;
}
generateAnalysisSection(data, period) {
const analysis = {
strengths: [],
weaknesses: [],
opportunities: [],
threats: [],
strategicPosition: ''
};
// Analyze strengths
if (data.milestones) {
const highImpactCompleted = data.milestones.filter((m) => m.status === 'completed' && m.businessContext.revenueImplication > 50000);
highImpactCompleted.forEach((m) => {
analysis.strengths.push({
area: m.category,
description: m.businessContext.competitiveAdvantage,
impact: m.businessContext.revenueImplication
});
});
}
// Analyze weaknesses from gaps
if (data.strategyGaps) {
data.strategyGaps.forEach((gap) => {
analysis.weaknesses.push({
area: gap.category,
description: gap.description,
severity: gap.severity,
impact: gap.estimatedImpact.revenueAtRisk
});
});
}
// Opportunities from competitive intel
if (data.competitiveIntel) {
data.competitiveIntel.opportunityMapping.forEach((opp) => {
analysis.opportunities.push({
description: opp.description,
source: opp.sourceOfAdvantage,
potential: opp.potentialReturn,
investment: opp.investmentRequired
});
});
}
// Threats from competitive intel
if (data.competitiveIntel) {
data.competitiveIntel.threatAssessment.immediateThreats.forEach((threat) => {
analysis.threats.push({
source: threat.source,
description: threat.description,
probability: threat.probability,
impact: threat.potentialImpact.revenueAtRisk
});
});
}
// Strategic position summary
const strengthCount = analysis.strengths.length;
const threatCount = analysis.threats.length;
const opportunityCount = analysis.opportunities.length;
if (strengthCount > threatCount && opportunityCount > 2) {
analysis.strategicPosition = 'Strong position with growth opportunities';
}
else if (threatCount > strengthCount) {
analysis.strategicPosition = 'Defensive position requiring strategic action';
}
else {
analysis.strategicPosition = 'Balanced position with selective opportunities';
}
return analysis;
}
generateForecastSection(data, period) {
const forecast = {
scenarios: [],
weightedProjections: {},
confidenceIntervals: {},
assumptions: []
};
if (data.forecasts && data.forecasts.length > 0) {
// Scenario summaries
data.forecasts.forEach((scenario) => {
forecast.scenarios.push({
name: scenario.name,
confidence: scenario.confidence,
revenue: scenario.businessMetrics.projectedRevenue.realistic,
customers: scenario.businessMetrics.customerAcquisition.realistic,
marketShare: scenario.businessMetrics.marketShare.realistic,
keyAssumptions: scenario.assumptions.slice(0, 2).map((a) => a.description)
});
});
// Weighted projections (25%/50%/25%)
const weights = { conservative: 0.25, realistic: 0.5, optimistic: 0.25 };
const baseScenario = data.forecasts.find((f) => f.name.includes('Base')) || data.forecasts[0];
forecast.weightedProjections = {
revenue: Math.round(baseScenario.businessMetrics.projectedRevenue.conservative * weights.conservative +
baseScenario.businessMetrics.projectedRevenue.realistic * weights.realistic +
baseScenario.businessMetrics.projectedRevenue.optimistic * weights.optimistic),
customers: Math.round(baseScenario.businessMetrics.customerAcquisition.conservative * weights.conservative +
baseScenario.businessMetrics.customerAcquisition.realistic * weights.realistic +
baseScenario.businessMetrics.customerAcquisition.optimistic * weights.optimistic)
};
// Key assumptions
baseScenario.assumptions.forEach((assumption) => {
if (assumption.impactIfWrong === 'critical' || assumption.impactIfWrong === 'significant') {
forecast.assumptions.push({
description: assumption.description,
confidence: assumption.confidence,
impact: assumption.impactIfWrong
});
}
});
}
return forecast;
}
generateRecommendationsSection(data, period) {
const recommendations = {
immediate: [],
shortTerm: [],
strategic: []
};
// Immediate actions from strategy gaps
if (data.strategyGaps) {
data.strategyGaps
.filter((gap) => gap.urgency === 'critical' || gap.urgency === 'high')
.forEach((gap) => {
gap.recommendedActions.forEach((action) => {
recommendations.immediate.push({
action: action.action,
rationale: gap.description,
timeframe: action.timeframe,
cost: action.cost,
successProbability: action.successProbability
});
});
});
}
// Short-term from competitive intel
if (data.competitiveIntel) {
data.competitiveIntel.strategicRecommendations
.filter((rec) => rec.priority === 'high')
.forEach((rec) => {
recommendations.shortTerm.push({
recommendation: rec.recommendation,
category: rec.category,
rationale: rec.rationale,
timeframe: rec.timeframe,
effort: rec.resourceRequirement
});
});
}
// Strategic from reviews
if (data.reviews) {
data.reviews
.filter((review) => review.status === 'completed')
.forEach((review) => {
review.decisions.forEach((decision) => {
if (decision.impact === 'high') {
recommendations.strategic.push({
decision: decision.decision,
implementation: decision.implementation,
owner: decision.owner,
deadline: decision.deadline
});
}
});
});
}
return recommendations;
}
generateAppendixSection(data, period) {
return {
dataSourcesSummary: {
milestones: data.milestones?.length || 0,
goals: data.goals?.length || 0,
conversations: data.conversations?.length || 0,
forecasts: data.forecasts?.length || 0,
reviews: data.reviews?.length || 0
},
methodology: 'Data compiled from Strategic CTO MCP Server using balanced forecasting (25%/50%/25%) and 85% maximum confidence thresholds.',
glossary: [
{ term: 'Weighted Forecast', definition: 'Projection using 25% pessimistic, 50% realistic, 25% optimistic weightings' },
{ term: 'Strategy Gap', definition: 'Identified misalignment between current capabilities and strategic requirements' },
{ term: 'Confidence Cap', definition: 'Maximum 85% confidence to maintain realistic expectations' }
]
};
}
// Visualization generators
generateMetricsVisualizations(data) {
const visualizations = [];
if (data.milestones) {
visualizations.push({
id: uuidv4(),
type: 'chart',
title: 'Milestone Progress',
data: {
labels: ['Completed', 'In Progress', 'Planned', 'Delayed'],
datasets: [{
data: [
data.milestones.filter((m) => m.status === 'completed').length,
data.milestones.filter((m) => m.status === 'in-progress').length,
data.milestones.filter((m) => m.status === 'planned').length,
data.milestones.filter((m) => m.status === 'delayed').length
]
}]
},
config: { type: 'doughnut' }
});
}
if (data.goals) {
visualizations.push({
id: uuidv4(),
type: 'chart',
title: 'Goal Health Distribution',
data: {
labels: ['Excellent (80-100%)', 'Good (60-79%)', 'At Risk (40-59%)', 'Critical (<40%)'],
datasets: [{
data: [
data.goals.filter((g) => g.confidence >= 80).length,
data.goals.filter((g) => g.confidence >= 60 && g.confidence < 80).length,
data.goals.filter((g) => g.confidence >= 40 && g.confidence < 60).length,
data.goals.filter((g) => g.confidence < 40).length
]
}]
},
config: { type: 'bar' }
});
}
return visualizations;
}
generateAnalysisVisualizations(data) {
const visualizations = [];
if (data.competitiveIntel) {
visualizations.push({
id: uuidv4(),
type: 'scorecard',
title: 'Competitive Position',
data: {
metrics: [
{ label: 'Market Position', value: data.competitiveIntel.marketAnalysis.competitiveIntensity },
{ label: 'Threat Level', value: data.competitiveIntel.threatAssessment.overallThreatLevel },
{ label: 'Opportunities', value: data.competitiveIntel.opportunityMapping.length },
{ label: 'Advantages', value: data.competitiveIntel.competitorProfiles[0]?.weaknessAreas.length || 0 }
]
},
config: { style: 'grid' }
});
}
return visualizations;
}
generateForecastVisualizations(data) {
const visualizations = [];
if (data.forecasts && data.forecasts.length > 0) {
const scenarios = data.forecasts;
visualizations.push({
id: uuidv4(),
type: 'chart',
title: 'Revenue Scenarios',
data: {
labels: scenarios.map((s) => s.name),
datasets: [
{
label: 'Conservative',
data: scenarios.map((s) => s.businessMetrics.projectedRevenue.conservative)
},
{
label: 'Realistic',
data: scenarios.map((s) => s.businessMetrics.projectedRevenue.realistic)
},
{
label: 'Optimistic',
data: scenarios.map((s) => s.businessMetrics.projectedRevenue.optimistic)
}
]
},
config: { type: 'line' }
});
}
return visualizations;
}
// Table generators
generateMetricsTables(data) {
const tables = [];
if (data.milestones) {
const milestoneTable = {
id: uuidv4(),
title: 'Technical Milestone Summary',
headers: ['Milestone', 'Category', 'Status', 'Complexity', 'Revenue Impact'],
rows: data.milestones
.slice(0, 10)
.map((m) => [
m.name,
m.category,
m.status,
m.complexity,
`$${m.businessContext.revenueImplication.toLocaleString()}`
])
};
tables.push(milestoneTable);
}
return tables;
}
generateForecastTables(data) {
const tables = [];
if (data.forecasts && data.forecasts.length > 0) {
const forecastTable = {
id: uuidv4(),
title: 'Scenario Comparison',
headers: ['Scenario', 'Confidence', 'Revenue', 'Customers', 'Market Share'],
rows: data.forecasts.map((f) => [
f.name,
`${f.confidence}%`,
`$${f.businessMetrics.projectedRevenue.realistic.toLocaleString()}`,
f.businessMetrics.customerAcquisition.realistic,
`${f.businessMetrics.marketShare.realistic}%`
])
};
tables.push(forecastTable);
}
return tables;
}
generateRecommendationsTables(data) {
const tables = [];
const recommendations = [];
// Collect all recommendations
if (data.strategyGaps) {
data.strategyGaps.forEach((gap) => {
gap.recommendedActions.forEach((action) => {
recommendations.push({
source: 'Strategy Gap',
action: action.action,
timeframe: action.timeframe,
cost: action.cost,
priority: gap.urgency
});
});
});
}
if (recommendations.length > 0) {
const recTable = {
id: uuidv4(),
title: 'Strategic Recommendations',
headers: ['Source', 'Action', 'Timeframe', 'Cost', 'Priority'],
rows: recommendations
.slice(0, 10)
.map(r => [
r.source,
r.action,
r.timeframe,
`$${r.cost.toLocaleString()}`,
r.priority
])
};
tables.push(recTable);
}
return tables;
}
generateAppendixTables(data) {
const tables = [];
// Data summary table
const summaryTable = {
id: uuidv4(),
title: 'Data Sources Summary',
headers: ['Data Type', 'Count', 'Period Coverage'],
rows: [
['Technical Milestones', data.milestones?.length || 0, 'Full period'],
['Business Goals', data.goals?.length || 0, 'Current snapshot'],
['Strategic Conversations', data.conversations?.length || 0, 'Full period'],
['Forecasts', data.forecasts?.length || 0, 'Forward-looking'],
['Strategy Reviews', data.reviews?.length || 0, 'Full period']
]
};
tables.push(summaryTable);
return tables;
}
// Export functionality
async exportReport(report) {
const exportPath = `./reports/${report.id}-${report.type}-${new Date().toISOString().split('T')[0]}.${report.format}`;
switch (report.format) {
case 'markdown':
const markdown = this.convertToMarkdown(report);
// In real implementation, write to file
return exportPath;
case 'html':
const html = this.convertToHTML(report);
// In real implementation, write to file
return exportPath;
case 'pdf':
// In real implementation, generate PDF
return exportPath;
default:
return exportPath;
}
}
convertToMarkdown(report) {
let markdown = `# ${report.title}\n\n`;
markdown += `*Generated: ${new Date(report.generated).toLocaleString()}*\n\n`;
markdown += `*Period: ${new Date(report.period.start).toLocaleDateString()} - ${new Date(report.period.end).toLocaleDateString()}*\n\n`;
report.sections.forEach(section => {
markdown += `## ${section.title}\n\n`;
// Content
if (section.type === 'summary' && section.content) {
markdown += `${section.content.overview}\n\n`;
if (section.content.keyHighlights?.length > 0) {
markdown += `### Key Highlights\n`;
section.content.keyHighlights.forEach((h) => {
markdown += `- ${h}\n`;
});
markdown += '\n';
}
if (section.content.criticalIssues?.length > 0) {
markdown += `### Critical Issues\n`;
section.content.criticalIssues.forEach((i) => {
markdown += `- ⚠️ ${i}\n`;
});
markdown += '\n';
}
}
// Tables
section.tables?.forEach(table => {
markdown += `### ${table.title}\n\n`;
markdown += `| ${table.headers.join(' | ')} |\n`;
markdown += `| ${table.headers.map(() => '---').join(' | ')} |\n`;
table.rows.forEach(row => {
markdown += `| ${row.join(' | ')} |\n`;
});
markdown += '\n';
});
});
return markdown;
}
convertToHTML(report) {
// Simple HTML conversion - in real implementation would use templating
let html = `
<!DOCTYPE html>
<html>
<head>
<title>${report.title}</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { color: #333; }
h2 { color: #666; margin-top: 30px; }
table { border-collapse: collapse; width: 100%; margin: 20px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.highlight { background-color: #fffacd; }
.critical { color: #d32f2f; font-weight: bold; }
</style>
</head>
<body>
<h1>${report.title}</h1>
<p><em>Generated: ${new Date(report.generated).toLocaleString()}</em></p>
<p><em>Period: ${new Date(report.period.start).toLocaleDateString()} - ${new Date(report.period.end).toLocaleDateString()}</em></p>
`;
report.sections.forEach(section => {
html += `<h2>${section.title}</h2>\n`;
// Add section content...
});
html += `</body></html>`;
return html;
}
// Helper methods
calculateVelocity(milestones) {
const completed = milestones.filter(m => m.status === 'completed' && m.completionDate);
if (completed.length < 2)
return 0;
const dates = completed.map(m => new Date(m.completionDate).getTime()).sort();
const timeSpan = (dates[dates.length - 1] - dates[0]) / (1000 * 60 * 60 * 24 * 30); // months
return completed.length / Math.max(timeSpan, 1);
}
getComplexityDistribution(milestones) {
const distribution = {};
milestones.forEach(m => {
distribution[m.complexity] = (distribution[m.complexity] || 0) + 1;
});
return distribution;
}
getCategoryBreakdown(goals) {
const breakdown = {};
goals.forEach(g => {
breakdown[g.category] = (breakdown[g.category] || 0) + 1;
});
return breakdown;
}
getReport(reportId) {
return this.reports.get(reportId) || null;
}
getReports(filter) {
let reports = Array.from(this.reports.values());
if (filter) {
if (filter.type) {
reports = reports.filter(r => r.type === filter.type);
}
if (filter.startDate) {
reports = reports.filter(r => new Date(r.generated) >= new Date(filter.startDate));
}
if (filter.endDate) {
reports = reports.filter(r => new Date(r.generated) <= new Date(filter.endDate));
}
}
return reports.sort((a, b) => new Date(b.generated).getTime() - new Date(a.generated).getTime());
}
getTemplates() {
return Array.from(this.templates.values());
}
}
//# sourceMappingURL=strategicReporting.js.map