From 8948b1a5162482f4cc3d754ddd5c3bc60eff70a1 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 07:45:40 -0700 Subject: [PATCH 01/19] feat(queries): add FinOps KPI query catalog --- src/queries/INDEX.md | 34 ++++- src/queries/KPI.md | 83 +++++++++++ .../catalog/ai-cost-by-application.kql | 33 +++++ src/queries/catalog/ai-daily-trend.kql | 27 ++++ .../catalog/ai-model-cost-comparison.kql | 31 ++++ .../catalog/ai-token-usage-breakdown.kql | 35 +++++ .../catalog/allocation-accuracy-index.kql | 35 +++++ .../catalog/anomaly-detection-rate.kql | 53 +++++++ .../catalog/anomaly-variance-total.kql | 65 +++++++++ .../catalog/commitment-discount-waste.kql | 88 ++++++++++++ .../catalog/commitment-utilization-score.kql | 67 +++++++++ src/queries/catalog/compute-cost-per-core.kql | 43 ++++++ .../compute-spend-commitment-coverage.kql | 32 +++++ .../catalog/cost-optimization-index.kql | 51 +++++++ src/queries/catalog/cost-per-gb-stored.kql | 42 ++++++ src/queries/catalog/cost-visibility-delay.kql | 62 ++++++++ src/queries/catalog/data-update-frequency.kql | 39 +++++ .../macc-consumption-vs-commitment.kql | 59 ++++++++ .../catalog/percentage-unallocated-costs.kql | 42 ++++++ .../catalog/percentage-untagged-costs.kql | 29 ++++ .../catalog/storage-tier-distribution.kql | 58 ++++++++ .../catalog/tagging-policy-compliance.kql | 56 ++++++++ src/queries/finops-hub-database-guide.md | 133 ++++++++++-------- 23 files changed, 1132 insertions(+), 65 deletions(-) create mode 100644 src/queries/KPI.md create mode 100644 src/queries/catalog/ai-cost-by-application.kql create mode 100644 src/queries/catalog/ai-daily-trend.kql create mode 100644 src/queries/catalog/ai-model-cost-comparison.kql create mode 100644 src/queries/catalog/ai-token-usage-breakdown.kql create mode 100644 src/queries/catalog/allocation-accuracy-index.kql create mode 100644 src/queries/catalog/anomaly-detection-rate.kql create mode 100644 src/queries/catalog/anomaly-variance-total.kql create mode 100644 src/queries/catalog/commitment-discount-waste.kql create mode 100644 src/queries/catalog/commitment-utilization-score.kql create mode 100644 src/queries/catalog/compute-cost-per-core.kql create mode 100644 src/queries/catalog/compute-spend-commitment-coverage.kql create mode 100644 src/queries/catalog/cost-optimization-index.kql create mode 100644 src/queries/catalog/cost-per-gb-stored.kql create mode 100644 src/queries/catalog/cost-visibility-delay.kql create mode 100644 src/queries/catalog/data-update-frequency.kql create mode 100644 src/queries/catalog/macc-consumption-vs-commitment.kql create mode 100644 src/queries/catalog/percentage-unallocated-costs.kql create mode 100644 src/queries/catalog/percentage-untagged-costs.kql create mode 100644 src/queries/catalog/storage-tier-distribution.kql create mode 100644 src/queries/catalog/tagging-policy-compliance.kql diff --git a/src/queries/INDEX.md b/src/queries/INDEX.md index e49f28e14..30f7b7347 100644 --- a/src/queries/INDEX.md +++ b/src/queries/INDEX.md @@ -2,7 +2,9 @@ > **Note:** Refer to the [FinOps hub database documentation](./finops-hub-database-guide.md) for table and column definitions. -> **Tip:** If you do not find a more specific or suitable query for your analysis, start with the [`costs-enriched-base`](./catalog/costs-enriched-base.kql) query. It provides the full enrichment and savings logic for all cost columns and is the recommended foundation for custom analytics and reporting. +This catalog contains 37 scenario-specific FinOps Hub KQL queries used by the FinOps Toolkit agents and the Azure SRE Agent recipe. + +> **Tip:** Prefer the narrowest scenario-specific query that answers the question. Use [`costs-enriched-base`](./catalog/costs-enriched-base.kql) when you need an enriched row-level baseline for scoped custom analysis or repeated drill-downs. --- @@ -10,14 +12,18 @@ | Common FinOps Task / Scenario | Recommended Query Name/ID | Description / When to Use | How to Use | | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| View all available cost and enrichment columns for custom analysis | [costs-enriched-base](./catalog/costs-enriched-base.kql) | Use as a foundation for any custom analytics or reporting. | Set `startDate`/`endDate` to define analysis period; use as foundation for custom reports aligned with "Understand Cloud Usage & Cost" domain. | +| View all available cost and enrichment columns for scoped drill-down analysis | [costs-enriched-base](./catalog/costs-enriched-base.kql) | Use only when row-level enriched cost samples are required after narrower aggregate queries do not answer the question. | Set `startDate`/`endDate` to a narrow period; use for scoped row-level diagnostics aligned with the "Understand Usage & Cost" domain. | | Analyze monthly cost trends (e.g., for CIO/leadership reporting) | [monthly-cost-trend](./catalog/monthly-cost-trend.kql) | Track total billed and effective cost by month for trend analysis and executive reporting. | Set `startDate`/`endDate` for trend period; supports "Reporting and Analytics" capability for executive dashboards. | | Identify top cost-driving resource groups | [top-resource-groups-by-cost](./catalog/top-resource-groups-by-cost.kql) | Find which resource groups are responsible for the most spend in a given period. | Adjust `N` parameter (default: 5) for result count; set `startDate`/`endDate` for specific analysis periods. | | Report quarterly cost by resource group | [quarterly-cost-by-resource-group](./catalog/quarterly-cost-by-resource-group.kql) | Summarize effective cost by resource group for quarterly or multi-month reporting. | Set `startDate`/`endDate` for fiscal quarters; adjust `N` parameter (default: 5) for top resource groups shown. | -| Analyze cost by region for optimization | [cost-by-region-trend](./catalog/cost-by-region-trend.kql) | Break down effective cost by Azure region to identify regional cost drivers. | Set `startDate`/`endDate` for analysis period; supports "Workload Optimization" capability for region selection. | +| Analyze cost by region for optimization | [cost-by-region-trend](./catalog/cost-by-region-trend.kql) | Break down effective cost by Azure region to identify regional cost drivers. | Set `startDate`/`endDate` for analysis period; supports Usage Optimization and Architecting & Workload Placement for region selection. | | Identify top resource types by cost and usage | [top-resource-types-by-cost](./catalog/top-resource-types-by-cost.kql) | See which resource types (VMs, storage, etc.) are most used and most expensive. | Set `N` parameter (default: 10) for result count; set `startDate`/`endDate` for specific period analysis. | | Identify top services by cost | [top-services-by-cost](./catalog/top-services-by-cost.kql) | Find which Azure services (e.g., SQL, App Service) are driving the most cost. | Set `N` parameter (default: 10) for result count; set `startDate`/`endDate` for analysis period; key for cost visibility. | | Allocate cost by financial hierarchy (Billing Profile, Invoice Section, Team, Product, App) | [cost-by-financial-hierarchy](./catalog/cost-by-financial-hierarchy.kql) | For detailed allocation and showback/chargeback reporting. | Set `N` parameter (default: 5) for top results; set `startDate`/`endDate`; supports "Allocation" capability in FinOps framework. | +| Allocate Azure OpenAI cost by application, team, and environment | [ai-cost-by-application](./catalog/ai-cost-by-application.kql) | Break down Azure OpenAI costs by resource tags for showback, chargeback, and unit economics. | Set `startDate`/`endDate` for a complete month or analysis period; validate tag coverage before using results for chargeback. | +| Analyze daily Azure OpenAI cost and token trends | [ai-daily-trend](./catalog/ai-daily-trend.kql) | Track daily AI workload token consumption and effective cost. | Set `startDate`/`endDate` for the trend window; use for anomaly detection, forecasting, and run-rate discussions. | +| Compare Azure OpenAI model cost efficiency | [ai-model-cost-comparison](./catalog/ai-model-cost-comparison.kql) | Compare cost per 1K tokens, list cost, and discount percentage by model. | Set `startDate`/`endDate`; use with model selection, commitment, and rate optimization decisions. | +| Break down Azure OpenAI token usage by model and direction | [ai-token-usage-breakdown](./catalog/ai-token-usage-breakdown.kql) | Break token consumption and cost down by model and inferred input/output direction. | Set `startDate`/`endDate`; use for AI workload unit economics and prompt/output cost mix analysis. | | Benchmark service prices and savings (list, contracted, effective, negotiated, commitment) | [service-price-benchmarking](./catalog/service-price-benchmarking.kql) | Compare prices and savings by service for benchmarking and procurement. | Set `startDate`/`endDate` for benchmark period; supports "Benchmarking" capability in "Quantify Business Value" domain. | | Forecast future cloud spend | [cost-forecasting-model](./catalog/cost-forecasting-model.kql) | Project future costs for budgeting and planning. | Set `startDate`/`endDate` for historical data; adjust `forecastPeriods` (default: 90) and `interval` (default: 1d) for forecast horizon. | | Detect cost anomalies and spikes | [cost-anomaly-detection](./catalog/cost-anomaly-detection.kql) | Identify unusual cost spikes or drops for investigation. | Set `numberOfMonths` (default: 12) for lookback period; adjust `interval` (default: 1d) for detection granularity. | @@ -27,14 +33,30 @@ | List top commitment (RI/SP) transactions | [top-commitment-transactions](./catalog/top-commitment-transactions.kql) | Identify the largest reservation or savings plan purchases and their impact. | Set `N` parameter (default: 10) for result count; set `startDate`/`endDate` to analyze specific purchase periods. | | List top other (non-commitment, non-usage) transactions | [top-other-transactions](./catalog/top-other-transactions.kql) | Analyze large purchases not covered by RI/SP (e.g., support, marketplace, etc.). | Set `N` parameter (default: 10) for result count; set `startDate`/`endDate` to analyze non-usage spend. | | Analyze reservation recommendations and break-even points | [reservation-recommendation-breakdown](./catalog/reservation-recommendation-breakdown.kql) | Review Microsoft recommendations for new reservations and their projected savings. | Run without parameters for all recommendations; filter by service or region for targeted optimization. | - -> **Tip:** For any scenario not listed, start with [costs-enriched-base](./catalog/costs-enriched-base.kql) and customize as needed. +| Measure % of cost on resources with no tags (KPI: Untagged Costs) | [percentage-untagged-costs](./catalog/percentage-untagged-costs.kql) | FinOps Foundation KPI quantifying cost from resources that carry zero tags. | Set `startDate`/`endDate` for the KPI window; output column `PercentUntaggedCost` is ready for dashboards and SLO tracking. | +| Measure % of cost on resources lacking required allocation tags (KPI: Unallocated Costs) | [percentage-unallocated-costs](./catalog/percentage-unallocated-costs.kql) | FinOps Foundation KPI quantifying cost that cannot be allocated due to missing keys. | Edit `requiredKeys` to your allocation policy; pair with `allocation-accuracy-index` for the complement view. | +| Measure Allocation Accuracy Index (AAI) | [allocation-accuracy-index](./catalog/allocation-accuracy-index.kql) | Complement of unallocated-cost ratio expressed as a 0-1 index — FinOps Foundation KPI. | Edit `requiredKeys` to your allocation policy; identical input set to `percentage-unallocated-costs` so the two always sum to 1. | +| Measure tag policy compliance (KPI: Tagging Policy Compliance) | [tagging-policy-compliance](./catalog/tagging-policy-compliance.kql) | FinOps Foundation KPI measuring share of cost on resources satisfying mandatory tag keys. | Edit `requiredKeys` to your tagging policy; uses `mv-apply` to verify every required key is present. | +| Measure anomaly detection rate over a window (KPI: Anomaly Detection Rate) | [anomaly-detection-rate](./catalog/anomaly-detection-rate.kql) | FinOps Foundation KPI — count of anomalies detected per period via `series_decompose_anomalies`. | Set `numberOfMonths` and `interval` for granularity; adjust `sensitivity` (default 1.5) for tolerance. | +| Measure total monetary variance for anomaly events (KPI: Total Unpredicted Variance of Spend) | [anomaly-variance-total](./catalog/anomaly-variance-total.kql) | FinOps Foundation KPI — sum of absolute monetary variance for detected anomaly events. | Set `numberOfMonths` and `interval`; result `TotalUnpredictedVariance` aggregates absolute residual cost. | +| Measure cost data visibility delay (KPI: Cost Visibility Delay) | [cost-visibility-delay](./catalog/cost-visibility-delay.kql) | FinOps Foundation KPI — percentile latency between `BillingPeriodEnd` and ingestion time. | Adjust `pct` to choose percentile (default 90); use to monitor data-freshness SLOs. | +| Monitor cost data refresh cadence (KPI: Frequency of Data Updates) | [data-update-frequency](./catalog/data-update-frequency.kql) | FinOps Foundation KPI — last successful ingestion + average inter-update gap. | Inspect `LastUpdate` and `AvgGapHours` to validate the export schedule. | +| Measure commitment discount utilization (KPI: Commitment Utilization Score) | [commitment-utilization-score](./catalog/commitment-utilization-score.kql) | FinOps Foundation KPI — weighted ratio of utilized commitment quantity over purchased. | Set `startDate`/`endDate` covering full commitment periods; supports Rate Optimization domain. | +| Measure commitment discount waste (KPI: Commitment Discount Waste) | [commitment-discount-waste](./catalog/commitment-discount-waste.kql) | FinOps Foundation KPI — complement of utilization (unused commitment value / total). | Set `startDate`/`endDate` covering full commitment periods; use alongside `commitment-utilization-score` for both sides of the ledger. | +| Measure compute spend covered by commitments (KPI: Compute Spend Covered by Commitments) | [compute-spend-commitment-coverage](./catalog/compute-spend-commitment-coverage.kql) | FinOps Foundation KPI — share of compute `ContractedCost` backed by commitment discounts. | Set `startDate`/`endDate`; supports Rate Optimization and Commitment-Based Discount Management capabilities. | +| Measure effective and hourly compute cost per CPU core (KPI: Compute Cost per Core) | [compute-cost-per-core](./catalog/compute-cost-per-core.kql) | FinOps Foundation dual KPI — Effective Average and Hourly Cost per CPU Core for VM SKUs. | Set `startDate`/`endDate`; covers the canonical 3-step VM core-hour pattern. Pairs with `top-resource-types-by-cost` for rightsizing analysis. | +| Measure Cost Optimization Index (COIN) | [cost-optimization-index](./catalog/cost-optimization-index.kql) | FinOps Foundation KPI — accepted / total Microsoft cost recommendations. | Run without parameters; uses `Recommendations` table directly so no time window applies. | +| Measure cost per GB stored (KPI: Cost per Gigabytes Stored) | [cost-per-gb-stored](./catalog/cost-per-gb-stored.kql) | FinOps Foundation KPI — `BilledCost` over total GB-month for storage SKUs. | Set `startDate`/`endDate`; supports Usage Optimization for storage rightsizing. | +| Measure MACC consumption vs commitment drawdown (KPI: Consumption vs Commitment) | [macc-consumption-vs-commitment](./catalog/macc-consumption-vs-commitment.kql) | FinOps Foundation KPI — share of MACC commitment consumed in the current period. | Set `startDate`/`endDate` to align with a MACC term; supports Quantify Business Value reporting. | +| Measure storage tier distribution (KPI: Percent Storage on Frequent Access Tier) | [storage-tier-distribution](./catalog/storage-tier-distribution.kql) | FinOps Foundation KPI — distribution of storage cost across hot/cool/cold/archive tiers. | Set `startDate`/`endDate`; supports Usage Optimization decisions for tiering policy. | + +> **Tip:** For any scenario not listed, first look for a narrower aggregate query. Use [costs-enriched-base](./catalog/costs-enriched-base.kql) only when row-level enrichment is required for a scoped custom analysis. --- ## References -- [FinOps Framework (Microsoft Learn)](https://learn.microsoft.com/cloud-computing/finops/framework/finops-framework) +- [FinOps Framework (FinOps Foundation)](https://www.finops.org/framework/) - [Implementing FinOps Guide (Microsoft Learn)](https://learn.microsoft.com/cloud-computing/finops/implementing-finops-guide) - [Adopt FinOps on Azure (Microsoft Learn)](https://learn.microsoft.com/training/modules/adopt-finops-on-azure/) - [FinOps hub Database Documentation](./finops-hub-database-guide.md) diff --git a/src/queries/KPI.md b/src/queries/KPI.md new file mode 100644 index 000000000..b4b17b664 --- /dev/null +++ b/src/queries/KPI.md @@ -0,0 +1,83 @@ +| KPI | Formula | Capabilities | Technology Categories | Source | Toolkit Queries | +|-----|---------|--------------|-----------------------|--------|-----------------| +| Total Migration Cost Savings | [(Current Cost on existing Infra (DC / Private Cloud / existing public CSP) – Effective Cost on the target platform (new public cloud CSP)] + [Shared Effective Costs associated with existing tools & people effort required to manage current infrastructure – Shared effective costs associated with target state tools & people effort required to manage target architecture] | | | https://www.finops.org/kpi/total-migration-cost-savings/ | | +| Fixed Percentage Apportionment Validation | Total apportionment of shared Effective Costs / Total shared Effective costs | Allocation | | https://www.finops.org/kpi/fixed-percentage-apportionment-validation/ | | +| Percentage of Costs Associated with Unallocated CSP Cloud Resources | (Total Effective Costs Associated w/Unallocated CSP Cloud Resources During a Period of Time / Total CSP Cloud Costs During a Period of Time) | Allocation | | https://www.finops.org/kpi/percentage-of-costs-associated-with-unallocated-csp-cloud-resources/ | [percentage-unallocated-costs](catalog/percentage-unallocated-costs.kql) | +| Percentage of Costs Associated with Untagged CSP Cloud Resources | (Total Effective Costs Associated with Untagged CSP Cloud Resources During a Period of Time / Total CSP Effective Cost During a Period of Time) x 100 | Allocation | | https://www.finops.org/kpi/percentage-of-costs-associated-with-untagged-csp-cloud-resources/ | [percentage-untagged-costs](catalog/percentage-untagged-costs.kql) | +| Percentage of CSP Cloud Costs that are Tagging Policy Compliant | (Total Effective Costs Associated with Tagging Policy Compliant CSP Cloud Resources During a Period of Time / Total CSP Cloud Effective Costs During a Period of Time) x 100 | Allocation | | https://www.finops.org/kpi/percentage-of-csp-cloud-costs-that-are-tagging-policy-compliant/ | [tagging-policy-compliance](catalog/tagging-policy-compliance.kql) | +| Percentage of Unallocated Shared CSP Cloud Cost | Percentage of Unallocated Shared CSP Effective Cloud Cost = (Unallocated Shared CSP Effective Cloud Cost/Total CSP Effective Cloud Cost) | Allocation | | https://www.finops.org/kpi/percentage-of-unallocated-shared-csp-cloud-cost/ | | +| Usage or Spend Apportionment Validation | Total apportionment of Shared Costs / Total shared costs | Allocation | | https://www.finops.org/kpi/usage-or-spend-apportionment-validation/ | | +| Data Center Management Efficiency | Operational Load Factor = (FTEs × Hourly Rate) / (Managed Infrastructure Value) | Allocation; Data Ingestion; Reporting & Analytics; Unit Economics | | https://www.finops.org/kpi/data-center-management-efficiency/ | | +| Total Cost of Ownership per Workload | TCO per Workload = (Total Costs Over Lifecycle) / (Number of Workloads) | Allocation; Reporting & Analytics; Unit Economics | | https://www.finops.org/kpi/total-cost-of-ownership-per-workload/ | | +| Allocation Accuracy Index (AAI) | Allocation Accuracy Index (AAI) = (Directly Attributed Costs / Total Infrastructure Costs) × 100 | Allocation; Reporting & Analytics; Usage Optimization | | https://www.finops.org/kpi/allocation-accuracy-index-aai/ | [allocation-accuracy-index](catalog/allocation-accuracy-index.kql) | +| Anomaly-Detected Cost Avoidance | Total cost of the unpredicted & correctable amount of spend * Projected Amount of Days the anomaly could have occurred if the underlying issue was not addressed | Anomaly Management | | https://www.finops.org/kpi/anomaly-detected-cost-avoidance/ | | +| Total Unpredicted Variance of Spend | Total effective cost associated with all anomalies events detected less the predicted spend of the services related to the identified anomalies. | Anomaly Management | | https://www.finops.org/kpi/total-unpredicted-variance-of-spend/ | [anomaly-variance-total](catalog/anomaly-variance-total.kql) | +| Anomaly Detection Rate | Total Cost of Anomaly Spikes / Total AI Spend = Anomaly Cost % where (adjust for your needs): Green ( Yellow (2-7%): Warning. Minor anomaly trend Red (> 7%): Critical. You have a “runaway” costs. | Anomaly Management; Data Ingestion; Reporting & Analytics | | https://www.finops.org/kpi/anomaly-detection-rate/ | [anomaly-detection-rate](catalog/anomaly-detection-rate.kql) | +| Computational Waste Percentage | ((Unit Consumed by Failed Jobs + Idle Time + Technical Spillage) / Total Compute Units Consumed) x 100 | Anomaly Management; Reporting & Analytics; Usage Optimization | | https://www.finops.org/kpi/computational-waste-percentage/ | | +| Effective Scan Efficiency | Effective Scan Efficiency = (Units of Data Scanned / Total Units of Data in Table) x 100 | Anomaly Management; Usage Optimization | | https://www.finops.org/kpi/effective-scan-efficiency/ | | +| SaaS Optimization ROI | Optimization ROI = Savings from SaaS Optimization Actions / Implementation Cost | Architecting & Workload Placement; Data Ingestion; Licensing & SaaS; Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/saas-optimization-roi/ | | +| Redundant Application Coverage Percent | Redundant Application Coverage Percent = Spend on Overlapping Tools / Total SaaS Spend | Architecting & Workload Placement; Data Ingestion; Licensing & SaaS; Reporting & Analytics; Usage Optimization | | https://www.finops.org/kpi/redundant-application-coverage-percent/ | | +| CSP Cloud Budget Burn Rate | (Actual Cloud Spending / Time Period) | Budgeting | | https://www.finops.org/kpi/csp-cloud-budget-burn-rate/ | [monthly-cost-trend](catalog/monthly-cost-trend.kql) | +| Percentage Variance of Budgeted vs. Actual CSP Cloud Spend | ((Budgeted CSP Cloud Spend – Actual CSP Cloud Spend) / Budgeted CSP Cloud Spend) | Budgeting | | https://www.finops.org/kpi/percentage-variance-of-budgeted-vs-actual-csp-cloud-spend/ | | +| Percentage Variance of Budgeted vs. Forecasted CSP Cloud Spend | ((Budgeted CSP Effective Cost for a Time Period – Forecasted CSP Effective Cost for that Time Period) / Budgeted CSP Effective Cost for that Time Period) | Budgeting | | https://www.finops.org/kpi/percentage-variance-of-budgeted-vs-forecasted-csp-cloud-spend/ | | +| CSP Cloud Carbon Budget Burn Rate | (Allocated Cloud Emissions / Time Period) | Budgeting; Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/csp-cloud-carbon-budget-burn-rate/ | | +| Cost Visibility Delay | Cost Visibility Delay = Time of Displaying Cost – Time of Cost Generation | Data Ingestion | | https://www.finops.org/kpi/cost-visibility-delay/ | [cost-visibility-delay](catalog/cost-visibility-delay.kql) | +| ETL Processing Time | Processing Time = End Time – Start Time | Data Ingestion | | https://www.finops.org/kpi/etl-processing-time/ | | +| Frequency of Data Updates | Data Update Frequency = Time of Latest Cost Update – Time of Previous Cost Update | Data Ingestion | | https://www.finops.org/kpi/frequency-of-data-updates/ | [data-update-frequency](catalog/data-update-frequency.kql) | +| Consumption versus Commitment | Consumption versus Commitment = Actual Consumption Units / Committed Units | Data Ingestion; Forecasting; Licensing & SaaS; Rate Optimization; Reporting & Analytics | | https://www.finops.org/kpi/consumption-versus-commitment/ | [macc-consumption-vs-commitment](catalog/macc-consumption-vs-commitment.kql) | +| Feature Adoption Rate | Feature Adoption Rate = (Users Using Premium Features / Premium Licenses Assigned) x 100 | Data Ingestion; Licensing & SaaS; Rate Optimization; Reporting & Analytics | | https://www.finops.org/kpi/feature-adoption-rate/ | | +| License Utilisation Rate | License Utilisation Rate = (Assigned Licenses / Purchased Licenses) x 100 | Data Ingestion; Licensing & SaaS; Rate Optimization; Reporting & Analytics | | https://www.finops.org/kpi/license-utilisation-rate/ | | +| Active-to-Provisioned User Ratio | Active-to-Provisioned User Ratio = (Active Users / Provisioned Users) x 100 | Data Ingestion; Licensing & SaaS; Reporting & Analytics; Usage Optimization | Licences, SaaS | https://www.finops.org/kpi/active-to-provisioned-user-ratio/ | | +| Data Center Power Usage Effectiveness | Power Usage Effectiveness (PUE) = Total Facility Power / IT Equipment Power | Data Ingestion; Reporting & Analytics; Sustainability | | https://www.finops.org/kpi/data-center-power-usage-effectiveness/ | | +| Cost per Inference | Cost Per Inference = Total Inference Costs / Number of Inference Requests​ | Data Ingestion; Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/cost-per-inference/ | | +| Resource Utilization Efficiency | Resource Utilization Efficiency = Actual Resource Utilization / Provisioned Capacity​ | Data Ingestion; Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/resource-utilization-efficiency/ | | +| Token Consumption Metrics | Cost Per Token = Total Cost / Number of Tokens Used | Data Ingestion; Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/token-consumption-metrics/ | [ai-token-usage-breakdown](catalog/ai-token-usage-breakdown.kql), [ai-daily-trend](catalog/ai-daily-trend.kql), [ai-model-cost-comparison](catalog/ai-model-cost-comparison.kql) | +| Training Cost Efficiency | Training Cost Efficiency = Training Costs / Performance Metric | Data Ingestion; Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/training-cost-efficiency/ | | +| Count of FinOps Learning Opportunities Offered | Target number of courses grouped by time period | FinOps Education & Enablement | | https://www.finops.org/kpi/count-of-finops-learning-opportunities-offered-monthly-quarterly-annually/ | | +| Percentage of FinOps Personas Who Have Completed Training | (Target for certification – actual count certified ) / target for certification * 100 | FinOps Education & Enablement | | https://www.finops.org/kpi/percentage-of-stakeholders-all-finops-personas-who-have-completed-finops-training/ | | +| Forecast Accuracy Rate (Spend) | ((Forecasted Public Cloud Spend – Actual Public Cloud Spend) / Forecasted Public Cloud Spend) | Forecasting | | https://www.finops.org/kpi/forecast-accuracy-rate-spend/ | | +| Forecast Drift Rate | ((New Forecasted Cloud Infrastructure Spend – Previous Historic Forecasted Cloud Infrastructure Spend) / Previous Forecasted Cloud Infrastructure Spend) | Forecasting | | https://www.finops.org/kpi/forecast-drift-rate/ | | +| Forecast (Present) Actual Rate (Carbon) | ((Forecasted Public Cloud emissions – Actual Public Cloud emissions) / Forecasted Public Cloud emissions) | Forecasting; Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/forecast-present-actual-rate-carbon/ | | +| Time to Achieve Business Value | Time to Value (days) = Total Value associated with AI Service / daily Cost of Alternative solution | Forecasting; Planning & Estimating; Reporting & Analytics; Unit Economics | | https://www.finops.org/kpi/time-to-achieve-business-value/ | | +| Forecast Accuracy Rate (Usage) | Formula : For specific ServiceName or ServiceCategory or SKU ((Forecasted Resource Utilization – Actual Resource Utilization) / Forecasted Resource Utilization) | Forecasting; Sustainability | | https://www.finops.org/kpi/forecast-accuracy-rate-usage/ | | +| SaaS Unit Cost | SaaS Unit Cost = Total SaaS Cost / Total Units of Consumption | Intersecting Disciplines; Licensing & SaaS; Reporting & Analytics; Usage Optimization | | https://www.finops.org/kpi/saas-unit-cost/ | | +| Anomaly-Detected Carbon Avoidance | (Total emissions of the unpredicted & correctable amount of emissions) x (Projected Amount of Days the anomaly could have occurred if the underlying issue was not addressed) | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/anomaly-detected-carbon-avoidance/ | | +| Carbon Efficient Locations | (Count of active resources in low carbon region) / (total active resources) | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/carbon-efficient-locations/ | | +| Carbon per [Time] Compute Category | Compute CO2e per Time unit = Compute CO2e / Time Unit | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/carbon-per-time-compute-category/ | | +| Carbon per [Time] Storage Category | Storage CO2e per Time unit = Storage (CO2e/gigabytes) / Time unit | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/carbon-per-time-storage-category/ | | +| Carbon Waste / Carbon Efficiency | Carbon Waste Formula: (Carbon of currently allocated resource) – (Carbon of optimised resource for utilisation need) Carbon Efficiency Formula: (Carbon of optimized resource for utilization need) / (Carbon of currently allocated resource) | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/carbon-waste-carbon-efficiency/ | | +| Forecast Accuracy Rate for Carbon Emissions | ((Forecasted Public Cloud emissions – Actual Public Cloud emissions) / Forecasted Public Cloud emissions) | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/forecast-accuracy-rate-for-carbon-emissions/ | | +| Optimizing Electricity PUE, WUE, Between Regions, or Cloud Service Providers | PUE = Total Facility Energy / IT Equiment Energy WUE = Total Water Used by the Data Center / Total IT Equipment Energy Consumption (in kWh) | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/optimizing-electricity-pue-wue-between-regions-or-cloud-service-providers/ | | +| Percentage of Carbon Associated with Untagged CSP Cloud Resources | (Total emissions Associated with Untagged CSP Cloud Resources During a Period of Time / Total CSP Cloud emissions During a Period of Time) x 100 | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/percentage-of-carbon-associated-with-untagged-csp-cloud-resources/ | | +| Percentage of CSP Cloud Carbon that is Tagging Policy Compliant | (Total emissions Associated with Tagging Policy Compliant CSP Cloud Resources During a Period of Time / Total CSP Cloud Emissions During a Period of Time) x 100 | Intersecting Disciplines; Sustainability | | https://www.finops.org/kpi/percentage-of-csp-cloud-carbon-that-is-tagging-policy-compliant/ | | +| Carbon per Unit of Cloud Service SKU | Carbon per unit (kgCO2e) = Total Carbon Emissions (kgCO2e) / Total Resource Usage (SKU) | Intersecting Disciplines; Sustainability; Unit Economics | | https://www.finops.org/kpi/carbon-per-unit-of-cloud-service-sku/ | | +| Carbon per Unit of Cloud Spend | CO2e/unit of currency = Effective Cost / CO2e | Intersecting Disciplines; Sustainability; Unit Economics | | https://www.finops.org/kpi/carbon-per-unit-of-cloud-spend/ | | +| General Ledger Recharge Rate | (Total CSP Cloud Spend recorded as a Journal in the General Ledger) / (Total CSP* cloud spend for the month) | Invoicing & Chargeback | | https://www.finops.org/kpi/general-ledger-recharge-rate/ | | +| General Ledger Recharge Rate per Cost Center | (Total CSP* Cloud Spend per Cost Center recorded as a Journal in the General Ledger) / (Total CSP* cloud spend per Cost center for the month) | Invoicing & Chargeback | | https://www.finops.org/kpi/general-ledger-recharge-rate-per-cost-center/ | | +| Cloud Spend Percentage of Recurring Revenue | (Monthly total cloud invoice amount / Monthly Recurring Revenue) and/or (Annual total cloud invoice amount / Annual Recurring Revenue) | KPIs & Benchmarking; Planning & Estimating; Reporting & Analytics; Unit Economics | | https://www.finops.org/kpi/cloud-spend-percentage-of-recurring-revenue/ | | +| Value for AI Initiatives | Return On Investment = (Financial Benefits – Costs) / Costs * 100 | KPIs & Benchmarking; Reporting & Analytics; Unit Economics | AI | https://www.finops.org/kpi/value-for-ai-initiatives/ | | +| Data Value Density | Data Value Density = Total Business Revenue or Value Index / Total Data Platform TCO | Licensing & SaaS; Rate Optimization; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/data-value-density/ | | +| Time to First Prompt | Time to First Prompt = Deployment Date – Start Date of Initiative Development | Planning & Estimating; Reporting & Analytics | | https://www.finops.org/kpi/time-to-first-prompt/ | | +| Commitment Utilization Score | Commitment Utilization Score = (Used Commitment / Total Commitment) x 100 | Rate Optimization | | https://www.finops.org/kpi/commitment-utilization-score/ | [commitment-utilization-score](catalog/commitment-utilization-score.kql) | +| Effective Average Compute Cost per Core | (Effective Cost + Unused Commitment Discount Cost + Compute Cost) / Total number of Cores | Rate Optimization | | https://www.finops.org/kpi/effective-average-compute-cost-per-core/ | [compute-cost-per-core](catalog/compute-cost-per-core.kql) | +| Effective Savings Rate Percentage | Option 1: (CB Discount Savings – Cost to achieve CB Discount Savings) / Compute On-Demand Equivalent Spend Option 2: 1 – (Actual Spend with Discounts / Equivalent Spend at On Demand Rate) | Rate Optimization | | https://www.finops.org/kpi/effective-savings-rate-percentage/ | [savings-summary-report](catalog/savings-summary-report.kql) | +| Percent of Compute Spend Covered by Commitment Discounts | Compute Cost after Commitment Discount / On-Demand Compute Cost | Rate Optimization | | https://www.finops.org/kpi/percent-of-compute-spend-covered-by-commitment-based-discounts/ | [compute-spend-commitment-coverage](catalog/compute-spend-commitment-coverage.kql) | +| Percentage of Commitment Discount Waste | (Cost of Commitment Discount unused / total cost Commitment Discount) x 100 | Rate Optimization | | https://www.finops.org/kpi/percentage-of-commitment-based-discount-waste/ | [commitment-discount-waste](catalog/commitment-discount-waste.kql) | +| Cost Optimization Index (COIN) | COIN Score = [1 – (Total Savings Opportunity / Total Cost)] * 100 The resulting score from 0-100 serves as an objective benchmark for cost efficiency. Total Cost is based on the aggregate cost of any relevant scope of infrastructure and measured in any desired currency. Total Savings Opportunity is based on the sum of individual Savings Opportunities. Savings Opportunities are usage patterns within that scope of infrastructure which indicate expected areas of inefficiency and waste. These are calculated as projected savings in the same currency as Total Cost. Each Savings Opportunity will need it’s own cost model to identify potential savings. This scoring system can help: Identify areas to save money within run rate Compare teams, services, org or organizations cost efficiency Identify priority savings opportunities to target across the broader organization | Rate Optimization; Usage Optimization | | https://www.finops.org/kpi/cost-optimization-index-coin/ | [cost-optimization-index](catalog/cost-optimization-index.kql) | +| Pipeline Jobs Waste | Pipeline Jobs Waste = (Failed\|\|Error\|\|Cancelled\|\|Timed_out) Job Cost / Total Job Cost | Rate Optimization; Usage Optimization | | https://www.finops.org/kpi/pipeline-jobs-waste/ | | +| Storage Decay Ratio | Storage Decay Ratio = (Volume of Unaccessed Data / Total Data Volume) x 100 | Rate Optimization; Usage Optimization | | https://www.finops.org/kpi/storage-decay-ratio/ | | +| CPI – Cost Performance Indicator | CPI = Earned Value / Effective Cost at time period Where, Earned Value = Budgeted Cost per selected time period * % Complete And where, % Complete = Expected Unit Economic per selected time period / Actual Unit Economic per selected time period * 100 | Reporting & Analytics | | https://www.finops.org/kpi/cpi-cost-performance-indicator/ | | +| Number of Monthly Active Users (MAU) for Cost Insight Products | Number = Raw count of Monthly Active User (MAU), or any one single user accessing any insight Cost Insight Products | Reporting & Analytics | | https://www.finops.org/kpi/number-of-monthly-active-users-mau-for-cost-insight-products/ | | +| Percentage of Normalized, Queryable Data within Repository | Spend included in queryable data warehouse (or similar) / Total Cloud Spend | Reporting & Analytics | | https://www.finops.org/kpi/percentage-of-normalized-queryable-data-within-repository/ | | +| Cost per API Call | Cost Per API Call = Total API Costs / Number of API Calls | Reporting & Analytics; Unit Economics | | https://www.finops.org/kpi/cost-per-api-call/ | | +| Efficiency & Performance ROI | Optimization ROI = (Cost Savings + Performance Gains) / Implementation Cost | Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/efficiency-performance-roi/ | | +| IT Lifecycle Waste Efficiency | Efficiency KPI = ($ Potential Savings from Identified Waste) / (Total IT Cost in Scope) | Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/it-lifecycle-waste-efficiency/ | | +| Unified Cost & Usage Visibility | Reporting & Analytics Integration Completeness = (Integrated Usage & Cost Sources) / (Total Usage & Cost Sources) × 100 | Reporting & Analytics; Unit Economics; Usage Optimization | | https://www.finops.org/kpi/unified-cost-usage-visibility/ | | +| Auto-scaling Efficiency Rate | Auto-scaling efficiency rate = Maximum capacity cost of running workload to meet workload demand / Cost of running workload with auto-scaling to meet same workload demand. The higher the efficiency rate the more effective the auto-scaling is. Effective Cost can be used in this formula, or the List Cost metric can be used to eliminate the effect of discounts and focus entirely on the scaling effect. | Sustainability; Usage Optimization | | https://www.finops.org/kpi/auto-scaling-efficiency-rate/ | | +| Percent of Unused Resources | Volumes: Pricing Quantity of Unattached Volumes / Total Number of Volumes Number of Snapshots not accessed over a defined period of time / total # of Snapshots EIPS: Quantity of unattached Elastic IPs / Total Elastic IP’s | Sustainability; Usage Optimization | | https://www.finops.org/kpi/percent-of-unused-resources/ | | +| Percent Storage on Frequent Access Tier | Number of GB in Standard (or “frequently accessed” tiers vs. total GBs stored) | Sustainability; Usage Optimization | | https://www.finops.org/kpi/percent-storage-on-frequent-access-tier/ | [storage-tier-distribution](catalog/storage-tier-distribution.kql) | +| Percentage of Legacy Resource | Number of instances on ‘legacy’ resource types / total number of instances (can be done by app, account, total) | Sustainability; Usage Optimization | | https://www.finops.org/kpi/percentage-of-legacy-resource/ | | +| Percentage Resource Utilization | Compute: CPU Utilization Rate (total consumed quantity in core-hrs or cpu-hrs / Total CPUs Allocated), Memory Utilization Rate (Total Usage in GB / Total Memory Allocated) Volumes: Throughput Utilized / Throughput Provisioned, IOPS Utilized / IOPS provisioned, Storage Utilized / Storage Provisioned (per volume) | Sustainability; Usage Optimization | | https://www.finops.org/kpi/percentage-resource-utilization/ | | +| Power Schedule Adherence Rate | Power schedule adherence percentage per month = (Total number of hours the system is required to run/Total number of hours the system is running) | Sustainability; Usage Optimization | | https://www.finops.org/kpi/power-schedule-adherence-rate/ | | +| Cost per Gigabytes Stored | Cloud Storage Costs / Number of GB stored | Unit Economics | | https://www.finops.org/kpi/cost-per-gigabytes-stored/ | [cost-per-gb-stored](catalog/cost-per-gb-stored.kql) | +| Hourly Cost per CPU Core | Hourly Cost / Number of CPU cores | Unit Economics | | https://www.finops.org/kpi/hourly-cost-per-cpu-core/ | [compute-cost-per-core](catalog/compute-cost-per-core.kql) | diff --git a/src/queries/catalog/ai-cost-by-application.kql b/src/queries/catalog/ai-cost-by-application.kql new file mode 100644 index 000000000..a3a08cd35 --- /dev/null +++ b/src/queries/catalog/ai-cost-by-application.kql @@ -0,0 +1,33 @@ +// ============================================================================ +// Query: Azure OpenAI Cost by Application +// Description: +// Breaks down Azure OpenAI costs by application, cost center, team, and environment tags. +// Useful for AI workload showback, chargeback, and unit economics analysis. +// Author: FinOps Toolkit Team +// Parameters: +// startDate: Start date for the reporting period (e.g., startofmonth(ago(30d))) +// endDate: End date for the reporting period (e.g., startofmonth(now())) +// Output: +// Each row represents a tagged Azure OpenAI cost grouping with token count and cost metrics. +// Usage: +// Use this query to allocate Azure OpenAI usage and cost to applications, teams, and environments. +// Last Updated: 2026-05-26 +// ============================================================================ + +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where x_SkuMeterSubcategory has "OpenAI" +| extend parsedTags = parse_json(Tags) +| extend Application = tostring(parsedTags["application"]) +| extend CostCenter = tostring(parsedTags["CostCenter"]) +| extend Environment = tostring(parsedTags["environment"]) +| extend Team = tostring(parsedTags["team"]) +| summarize + TokenCount = sum(ConsumedQuantity), + EffectiveCost = sum(EffectiveCost), + BilledCost = sum(BilledCost) + by Application, CostCenter, Team, Environment, ResourceName, x_SkuMeterSubcategory +| extend CostPer1KTokens = iff(TokenCount == 0, 0.0, EffectiveCost / TokenCount * 1000) +| order by EffectiveCost desc diff --git a/src/queries/catalog/ai-daily-trend.kql b/src/queries/catalog/ai-daily-trend.kql new file mode 100644 index 000000000..e9ece83bc --- /dev/null +++ b/src/queries/catalog/ai-daily-trend.kql @@ -0,0 +1,27 @@ +// ============================================================================ +// Query: Azure OpenAI Daily Cost and Token Trend +// Description: +// Returns daily Azure OpenAI token consumption and effective cost. +// Useful for AI workload anomaly detection, forecasting, and trend reporting. +// Author: FinOps Toolkit Team +// Parameters: +// startDate: Start date for the reporting period (e.g., ago(30d)) +// endDate: End date for the reporting period (e.g., now()) +// Output: +// Each row represents one day with token count, cost, and cost per 1K tokens. +// Usage: +// Use this query to monitor AI workload consumption trends and detect daily cost spikes. +// Last Updated: 2026-05-26 +// ============================================================================ + +let startDate = ago(30d); +let endDate = now(); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where x_SkuMeterSubcategory has "OpenAI" +| summarize + DailyTokens = sum(ConsumedQuantity), + DailyCost = sum(EffectiveCost) + by bin(ChargePeriodStart, 1d) +| extend CostPer1KTokens = iff(DailyTokens == 0, 0.0, DailyCost / DailyTokens * 1000) +| order by ChargePeriodStart asc diff --git a/src/queries/catalog/ai-model-cost-comparison.kql b/src/queries/catalog/ai-model-cost-comparison.kql new file mode 100644 index 000000000..7371f18a0 --- /dev/null +++ b/src/queries/catalog/ai-model-cost-comparison.kql @@ -0,0 +1,31 @@ +// ============================================================================ +// Query: Azure OpenAI Model Cost Comparison +// Description: +// Compares token volume, effective cost, list cost, and discount percentage by model. +// Useful for AI model cost efficiency analysis and rate optimization. +// Author: FinOps Toolkit Team +// Parameters: +// startDate: Start date for the reporting period (e.g., startofmonth(ago(30d))) +// endDate: End date for the reporting period (e.g., startofmonth(now())) +// Output: +// Each row represents one Azure OpenAI model or SKU description with cost per 1K tokens. +// Usage: +// Use this query to compare model economics and identify where model or commitment changes may reduce AI spend. +// Last Updated: 2026-05-26 +// ============================================================================ + +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where x_SkuMeterSubcategory has "OpenAI" +| extend Model = x_SkuDescription +| summarize + TokenCount = sum(ConsumedQuantity), + EffectiveCost = sum(EffectiveCost), + ListCost = sum(ListCost) + by Model +| extend CostPer1KTokens = iff(TokenCount == 0, 0.0, EffectiveCost / TokenCount * 1000) +| extend ListPer1KTokens = iff(TokenCount == 0, 0.0, ListCost / TokenCount * 1000) +| extend DiscountPercent = iff(ListCost == 0, 0.0, (ListCost - EffectiveCost) / ListCost * 100) +| order by EffectiveCost desc diff --git a/src/queries/catalog/ai-token-usage-breakdown.kql b/src/queries/catalog/ai-token-usage-breakdown.kql new file mode 100644 index 000000000..98e675bac --- /dev/null +++ b/src/queries/catalog/ai-token-usage-breakdown.kql @@ -0,0 +1,35 @@ +// ============================================================================ +// Query: Azure OpenAI Token Usage Breakdown +// Description: +// Breaks Azure OpenAI token consumption down by model version and input/output direction. +// Calculates effective unit cost per token and cost per 1K tokens. +// Author: FinOps Toolkit Team +// Parameters: +// startDate: Start date for the reporting period (e.g., startofmonth(ago(30d))) +// endDate: End date for the reporting period (e.g., startofmonth(now())) +// Output: +// Each row represents one model and direction with token count and cost metrics. +// Usage: +// Use this query to analyze AI workload unit economics, token direction mix, and model cost efficiency. +// Last Updated: 2026-05-26 +// ============================================================================ + +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where x_SkuMeterSubcategory has "OpenAI" +| extend Model = x_SkuDescription +| extend Direction = case( + Model contains "Input", "Input", + Model contains "Output", "Output", + "Other") +| summarize + TokenCount = sum(ConsumedQuantity), + EffectiveCost = sum(EffectiveCost), + BilledCost = sum(BilledCost), + ListCost = sum(ListCost) + by Model, Direction, x_SkuDescription +| extend UnitCostPerToken = iff(TokenCount == 0, 0.0, EffectiveCost / TokenCount) +| extend CostPer1KTokens = UnitCostPerToken * 1000 +| order by EffectiveCost desc diff --git a/src/queries/catalog/allocation-accuracy-index.kql b/src/queries/catalog/allocation-accuracy-index.kql new file mode 100644 index 000000000..297c9c232 --- /dev/null +++ b/src/queries/catalog/allocation-accuracy-index.kql @@ -0,0 +1,35 @@ +// ============================================================================ +// Query: Allocation Accuracy Index +// Description: +// Calculates the percentage of total effective cost that is directly attributed using a +// three-signal heuristic: allocation rule, cost center, or ownership-tag evidence. +// KPI: Allocation Accuracy Index (AAI) +// Formula: Allocation Accuracy Index (AAI) = (Directly Attributed Costs / Total Infrastructure Costs) × 100 +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; start date for the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; end date for the reporting period (default: startofmonth(now())) +// allocationEvidenceTagKeys: dynamic; tag keys treated as ownership evidence (default: dynamic(['cost-center','team','owner','application','product'])) +// Output: +// Each row represents one BillingCurrency and returns DirectlyAttributedCost, TotalEffectiveCost, +// and AAI for Hub-visible CSP costs in the reporting window. +// Usage: +// Use this query to measure how much effective cost is directly attributable within FinOps Hub. +// Scope Notes: Hub-only AAI. Does not include on-prem, SaaS, or other infrastructure outside Hub schema. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let allocationEvidenceTagKeys = dynamic(['cost-center','team','owner','application','product']); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) +| extend tmp_IsAttributed = isnotempty(x_CostAllocationRuleName) + or isnotempty(x_CostCenter) + or array_length(set_intersect(bag_keys(Tags), allocationEvidenceTagKeys)) > 0 +| summarize + DirectlyAttributedCost = todouble(sumif(EffectiveCost, tmp_IsAttributed)), + TotalEffectiveCost = todouble(sum(EffectiveCost)) + by BillingCurrency +| extend AAI = iff(TotalEffectiveCost == 0, 0.0, DirectlyAttributedCost / TotalEffectiveCost * 100.0) +| project BillingCurrency, DirectlyAttributedCost, TotalEffectiveCost, AAI diff --git a/src/queries/catalog/anomaly-detection-rate.kql b/src/queries/catalog/anomaly-detection-rate.kql new file mode 100644 index 000000000..ee0fb6d97 --- /dev/null +++ b/src/queries/catalog/anomaly-detection-rate.kql @@ -0,0 +1,53 @@ +// ============================================================================ +// Query: Anomaly Detection Rate +// Description: +// Calculates the percentage of effective spend attributable to anomaly-flagged days. +// Builds daily cost series per service category and billing currency, then applies time-series anomaly detection. +// KPI: Anomaly Detection Rate +// Formula: Total Cost of Anomaly Spikes / Total Spend = Anomaly Cost % +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; Start date for the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; End date for the reporting period (default: startofmonth(now())) +// sensitivity: real; Anomaly detection sensitivity for series_decompose_anomalies() (default: 1.5) +// Output: +// Each row returns a BillingCurrency and ServiceCategory pair (plus an Overall rollup row) with AnomalyCost, TotalCost, and AnomalyRatePercent as double values. +// Usage: +// Use this query to quantify how much effective spend falls on anomaly-flagged days by service category and by billing currency. +// Scope Notes: +// Treats both positive spikes and negative drops as anomalies (AnomalyFlags != 0); the Overall row is per BillingCurrency only. +// Missing days are zero-filled via make-series default=0.0, and commitment purchase rows are excluded to avoid amortization double-counting. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 13 rows returned (per service category) +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let sensitivity = 1.5; +let expanded = materialize( + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) + | summarize DailyCost = sum(todouble(EffectiveCost)) + by bin(ChargePeriodStart, 1d), ServiceCategory, BillingCurrency + | make-series CostSeries = sum(DailyCost) default=0.0 + on ChargePeriodStart from startDate to endDate step 1d + by ServiceCategory, BillingCurrency + | extend AnomalyFlags = series_decompose_anomalies(CostSeries, sensitivity) + | mv-expand CostSeries to typeof(double), AnomalyFlags to typeof(int) +); +let perCategory = + expanded + | summarize + AnomalyCost = todouble(sumif(CostSeries, AnomalyFlags != 0)), + TotalCost = todouble(sum(CostSeries)) + by BillingCurrency, ServiceCategory + | extend AnomalyRatePercent = todouble(iff(TotalCost == 0.0, 0.0, AnomalyCost / TotalCost * 100.0)); +let overall = + expanded + | summarize + AnomalyCost = todouble(sumif(CostSeries, AnomalyFlags != 0)), + TotalCost = todouble(sum(CostSeries)) + by BillingCurrency + | extend ServiceCategory = 'Overall' + | extend AnomalyRatePercent = todouble(iff(TotalCost == 0.0, 0.0, AnomalyCost / TotalCost * 100.0)); +union perCategory, overall +| project BillingCurrency, ServiceCategory, AnomalyCost, TotalCost, AnomalyRatePercent diff --git a/src/queries/catalog/anomaly-variance-total.kql b/src/queries/catalog/anomaly-variance-total.kql new file mode 100644 index 000000000..fdf8d1912 --- /dev/null +++ b/src/queries/catalog/anomaly-variance-total.kql @@ -0,0 +1,65 @@ +// ============================================================================ +// Query: Total Unpredicted Variance of Spend +// Description: +// Calculates the net unpredicted variance between actual effective cost and the anomaly baseline +// for anomaly-flagged daily buckets by service category and billing currency. +// KPI: Total Unpredicted Variance of Spend +// Formula: Total effective cost associated with all anomaly events detected less the predicted spend of the services related to the identified anomalies. +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; start of the reporting period (default: startofmonth(ago(12 * 30d))) +// endDate: datetime; end of the reporting period (default: now()) +// anomalyThreshold: real; anomaly detection sensitivity threshold (default: 1.5) +// Output: +// Each row returns BillingCurrency, ServiceCategory, AnomalyEventCount, UnpredictedVarianceSigned, +// and UnpredictedVarianceAbs for anomaly-detected daily buckets; "(All Services)" rows provide +// per-currency totals across all service categories. +// Usage: +// Use this query to quantify net anomalous overspend or underspend by service category and currency. +// Scope Notes: +// Per-group anomaly detection runs independently per (ServiceCategory, BillingCurrency), and groups +// with sparse history are filtered when no anomaly baseline is produced. Each BillingCurrency is +// reported separately and must not be summed across currencies without FX conversion. The default +// 12-month window supports STL seasonality decomposition, and UnpredictedVarianceAbs is defined as +// abs(sum(actual - baseline)) rather than sum(abs(actual - baseline)). +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 13 rows returned (per service category) +// ========================================================================= +let startDate = startofmonth(ago(12 * 30d)); +let endDate = now(); +let anomalyThreshold = 1.5; +let anomalyBuckets = + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) + | summarize DailyCost = sum(EffectiveCost) by ServiceCategory, BillingCurrency, bin(ChargePeriodStart, 1d) + | make-series CostSeries = sum(DailyCost) default=0.0 on ChargePeriodStart from startDate to endDate step 1d by ServiceCategory, BillingCurrency + | extend (ad_flag, ad_score, ad_baseline) = series_decompose_anomalies(CostSeries, anomalyThreshold) + | mv-expand ChargePeriodStart to typeof(datetime), CostSeries to typeof(real), ad_flag to typeof(real), ad_score to typeof(real), ad_baseline to typeof(real) + | extend ad_flag = toint(ad_flag), CostSeries = toreal(CostSeries), ad_score = toreal(ad_score), ad_baseline = toreal(ad_baseline) + | where isnotnull(ad_baseline) + | where ad_flag != 0 + | extend Variance = todouble(CostSeries) - todouble(ad_baseline); +union +( + anomalyBuckets + | summarize + AnomalyEventCount = count(), + UnpredictedVarianceSigned = todouble(sum(Variance)), + UnpredictedVarianceAbs = todouble(abs(sum(Variance))) + by BillingCurrency, ServiceCategory +), +( + anomalyBuckets + | summarize + AnomalyEventCount = count(), + UnpredictedVarianceSigned = todouble(sum(Variance)), + UnpredictedVarianceAbs = todouble(abs(sum(Variance))) + by BillingCurrency + | extend ServiceCategory = "(All Services)" +) +| project + BillingCurrency, + ServiceCategory, + AnomalyEventCount, + UnpredictedVarianceSigned = todouble(UnpredictedVarianceSigned), + UnpredictedVarianceAbs = todouble(UnpredictedVarianceAbs) diff --git a/src/queries/catalog/commitment-discount-waste.kql b/src/queries/catalog/commitment-discount-waste.kql new file mode 100644 index 000000000..fc75c6657 --- /dev/null +++ b/src/queries/catalog/commitment-discount-waste.kql @@ -0,0 +1,88 @@ +// ============================================================================ +// Query: Percentage of Commitment Discount Waste +// Description: +// Computes the percentage of commitment discount waste for each commitment by +// comparing unused amortized EffectiveCost to total commitment EffectiveCost. +// Includes a grand-total row per BillingCurrency across all commitments in the +// reporting window. +// KPI: Percentage of Commitment Discount Waste +// Formula: (Cost of Commitment Discount unused / total cost Commitment Discount) x 100 +// Author: FinOps toolkit +// Parameters: +// startDate: datetime = startofmonth(ago(30d)) +// endDate: datetime = startofmonth(now()) +// Output: +// BillingCurrency: string. Billing currency for the commitment or grand-total row. +// CommitmentDiscountId: string. Commitment identifier; empty string on the grand-total row. +// CommitmentDiscountName: string. Commitment name; '(All Commitments)' on the grand-total row. +// CommitmentDiscountType: string. Commitment type; empty string on the grand-total row. +// UnusedCost: double. Sum of EffectiveCost for rows where CommitmentDiscountStatus == 'Unused'. +// TotalCost: double. Sum of EffectiveCost across all commitment rows after filters. +// WastePercent: double. Percentage of TotalCost represented by UnusedCost. +// Usage: +// Use this query to identify underutilized commitment discounts and quantify waste by commitment and billing currency. +// Scope Notes: +// - Double-counting prevention: This query operates on amortized-style rows only +// (purchase rows excluded). +// - Unused row semantics: CommitmentDiscountStatus == 'Unused' rows represent +// wasted amortized commitment cost for the charge period. +// - CommitmentDiscountStatus values: Only 'Used' and 'Unused' are expected. +// - Currency mixing: Grand-total output is scoped per BillingCurrency; cross- +// currency aggregation is out of scope. +// - Period window: Default startDate/endDate cover one calendar month; adjust +// the let bindings for rolling windows. +// - KPI limitation vs canonical definition: This implementation uses +// EffectiveCost as the cost basis for commitment-discount waste analytics. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS_SCHEMA_WITH_DATA_GAP — query executed and returned expected columns; the hub has 0 commitment-discount rows in the test window, so value semantics require re-UAT on a commitment-active hub. +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let filteredCosts = + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where isnotempty(CommitmentDiscountId) + | where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)); +let commitmentWaste = + filteredCosts + | summarize + UnusedCost = sum(iff(CommitmentDiscountStatus == 'Unused', EffectiveCost, real(0))), + TotalCost = sum(EffectiveCost) + by BillingCurrency, CommitmentDiscountId, CommitmentDiscountName, CommitmentDiscountType + | extend WastePercent = iff(TotalCost == 0.0, 0.0, todouble(UnusedCost) / todouble(TotalCost) * 100.0) + | project + BillingCurrency, + CommitmentDiscountId, + CommitmentDiscountName, + CommitmentDiscountType, + UnusedCost = todouble(UnusedCost), + TotalCost = todouble(TotalCost), + WastePercent = todouble(WastePercent); +let grandTotals = + filteredCosts + | summarize + UnusedCost = sum(iff(CommitmentDiscountStatus == 'Unused', EffectiveCost, real(0))), + TotalCost = sum(EffectiveCost) + by BillingCurrency + | extend + CommitmentDiscountId = '', + CommitmentDiscountName = '(All Commitments)', + CommitmentDiscountType = '' + | extend WastePercent = iff(TotalCost == 0.0, 0.0, todouble(UnusedCost) / todouble(TotalCost) * 100.0) + | project + BillingCurrency, + CommitmentDiscountId, + CommitmentDiscountName, + CommitmentDiscountType, + UnusedCost = todouble(UnusedCost), + TotalCost = todouble(TotalCost), + WastePercent = todouble(WastePercent); +union commitmentWaste, grandTotals +| order by BillingCurrency asc, WastePercent desc, CommitmentDiscountName asc +| project + BillingCurrency, + CommitmentDiscountId, + CommitmentDiscountName, + CommitmentDiscountType, + UnusedCost, + TotalCost, + WastePercent diff --git a/src/queries/catalog/commitment-utilization-score.kql b/src/queries/catalog/commitment-utilization-score.kql new file mode 100644 index 000000000..42e51d920 --- /dev/null +++ b/src/queries/catalog/commitment-utilization-score.kql @@ -0,0 +1,67 @@ +// ============================================================================ +// Query: Commitment Utilization Score +// Description: +// Computes commitment utilization by commitment discount ID over the reporting window. +// Returns per-commitment and per-currency grand-total utilization amount, potential, and score. +// KPI: Commitment Utilization Score +// Formula: Commitment Utilization Score = (Used Commitment / Total Commitment) x 100 +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; start date for the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; end date for the reporting period (default: startofmonth(now())) +// Output: +// Each row represents one commitment or a per-currency grand total with BillingCurrency, +// CommitmentDiscountId, CommitmentDiscountName, CommitmentDiscountCategory, +// CommitmentDiscountType, UtilizationAmount, UtilizationPotential, and UtilizationScore. +// Usage: +// Use this query to monitor how fully Azure commitment discounts were utilized during the reporting window. +// Scope Notes: +// Microsoft Azure commitments only; score is window-based, grand totals are per BillingCurrency, +// and Usage-category quantities remain ConsumedUnit-dependent but valid as a ratio within each commitment. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS_SCHEMA_WITH_DATA_GAP — query executed and returned expected columns; the hub has 0 commitment-discount rows in the test window, so value semantics require re-UAT on a commitment-active hub. +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let commitmentRows = materialize( + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where isnotempty(CommitmentDiscountId) + | extend x_CommitmentDiscountUtilizationPotential = case( + ChargeCategory == 'Purchase', toreal(0), + ProviderName == 'Microsoft' and isnotempty(CommitmentDiscountCategory), toreal(EffectiveCost), + CommitmentDiscountCategory == 'Usage', toreal(ConsumedQuantity), + CommitmentDiscountCategory == 'Spend', toreal(EffectiveCost), + toreal(0)) + | extend x_CommitmentDiscountUtilizationAmount = iff(CommitmentDiscountStatus == 'Used', x_CommitmentDiscountUtilizationPotential, toreal(0)) +); +let commitmentSummary = + commitmentRows + | summarize + UtilizationAmount = todouble(sum(x_CommitmentDiscountUtilizationAmount)), + UtilizationPotential = todouble(sum(x_CommitmentDiscountUtilizationPotential)) + by BillingCurrency, CommitmentDiscountId, CommitmentDiscountName, CommitmentDiscountCategory, CommitmentDiscountType + | extend UtilizationScore = iff(UtilizationPotential > 0, todouble(UtilizationAmount / UtilizationPotential) * 100.0, todouble(0)); +union + commitmentSummary, + ( + commitmentSummary + | summarize + UtilizationAmount = todouble(sum(UtilizationAmount)), + UtilizationPotential = todouble(sum(UtilizationPotential)) + by BillingCurrency + | extend + CommitmentDiscountId = '(All)', + CommitmentDiscountName = '(Grand Total)', + CommitmentDiscountCategory = '', + CommitmentDiscountType = '', + UtilizationScore = iff(UtilizationPotential > 0, todouble(UtilizationAmount / UtilizationPotential) * 100.0, todouble(0)) + ) +| project + BillingCurrency, + CommitmentDiscountId, + CommitmentDiscountName, + CommitmentDiscountCategory, + CommitmentDiscountType, + UtilizationAmount, + UtilizationPotential, + UtilizationScore diff --git a/src/queries/catalog/compute-cost-per-core.kql b/src/queries/catalog/compute-cost-per-core.kql new file mode 100644 index 000000000..96102d3e9 --- /dev/null +++ b/src/queries/catalog/compute-cost-per-core.kql @@ -0,0 +1,43 @@ +// ============================================================================ +// Query: Effective Average Compute Cost per Core and Hourly Cost per CPU Core +// Description: +// Computes two compute-efficiency KPIs from FinOps Hub cost records in one pass over Costs(). +// It summarizes compute usage cost, unused commitment cost, and computed core-hours by billing currency. +// KPI: Effective Average Compute Cost per Core; Hourly Cost per CPU Core +// Formula: +// HourlyCostPerCore = sum(EffectiveCost for compute usage rows) / sum(x_ConsumedCoreHours for compute usage rows) +// EffectiveAverageCostPerCore = (sum(EffectiveCost for compute usage rows) + sum(EffectiveCost where CommitmentDiscountStatus=='Unused' AND isnotempty(CommitmentDiscountCategory))) / sum(x_ConsumedCoreHours for compute usage rows) +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; start of the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; end of the reporting period, exclusive (default: startofmonth(now())) +// Output: +// One row per BillingCurrency with BillingCurrency, TotalEffectiveCostUSDLike, UnusedCommitmentCost, TotalCoreHours, HourlyCostPerCore, and EffectiveAverageCostPerCore. +// Usage: +// Use this query to compare amortized compute spend per consumed vCPU-hour with and without unused commitment cost. +// Scope Notes: +// Azure-only VM usage detection uses x_SkuMeterCategory in ('Virtual Machines', 'Virtual Machine Licenses') with ChargeCategory == 'Usage'. +// UnusedCommitmentCost is restricted to unused compute commitments (CommitmentDiscountStatus == 'Unused' AND the +// commitment SKU is itself in the compute meter categories), so non-compute commitment waste does not inflate +// compute unit economics. Wave-boundary fix (T-3000.12 cross-model review): gpt-5.5 flagged that the prior +// un-scoped predicate mixed non-compute waste into the compute denominator. +// Core counts reflect billed VCPUs/vCores from x_SkuDetails, and all monetary values remain denominated in BillingCurrency rather than normalized USD. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned; HourlyCostPerCore=0.019 USD +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) +| extend tmp_IsVMUsage = x_SkuMeterCategory in ('Virtual Machines', 'Virtual Machine Licenses') and ChargeCategory == 'Usage' +| extend tmp_IsComputeCommitment = x_SkuMeterCategory in ('Virtual Machines', 'Virtual Machine Licenses') +| extend x_SkuCoreCount = iff(tmp_IsVMUsage, toint(coalesce(x_SkuDetails.VCPUs, x_SkuDetails.vCores)), toint('')) +| extend x_ConsumedCoreHours = iff(tmp_IsVMUsage and isnotempty(x_SkuCoreCount), toreal(x_SkuCoreCount * ConsumedQuantity), toreal('')) +| summarize + TotalEffectiveCostUSDLike = todouble(sumif(EffectiveCost, tmp_IsVMUsage)), + UnusedCommitmentCost = todouble(sumif(EffectiveCost, CommitmentDiscountStatus == 'Unused' and isnotempty(CommitmentDiscountCategory) and tmp_IsComputeCommitment)), + TotalCoreHours = todouble(sum(x_ConsumedCoreHours)) + by BillingCurrency +| extend HourlyCostPerCore = todouble(iff(isnull(TotalCoreHours) or TotalCoreHours == 0.0, 0.0, TotalEffectiveCostUSDLike / TotalCoreHours)) +| extend EffectiveAverageCostPerCore = todouble(iff(isnull(TotalCoreHours) or TotalCoreHours == 0.0, 0.0, (TotalEffectiveCostUSDLike + UnusedCommitmentCost) / TotalCoreHours)) +| project BillingCurrency, TotalEffectiveCostUSDLike, UnusedCommitmentCost, TotalCoreHours, HourlyCostPerCore, EffectiveAverageCostPerCore diff --git a/src/queries/catalog/compute-spend-commitment-coverage.kql b/src/queries/catalog/compute-spend-commitment-coverage.kql new file mode 100644 index 000000000..816d3e979 --- /dev/null +++ b/src/queries/catalog/compute-spend-commitment-coverage.kql @@ -0,0 +1,32 @@ +// ============================================================================ +// Query: Percent of Compute Spend Covered by Commitment Discounts +// Description: +// Computes the share of compute spend covered by commitment discounts over a selected reporting window. +// Uses effective cost for commitment-backed compute spend and contracted cost for the compute baseline. +// KPI: Percent of Compute Spend Covered by Commitment Discounts +// Formula: Compute Cost after Commitment Discount / On-Demand Compute Cost +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; start of the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; end of the reporting period, exclusive (default: startofmonth(now())) +// Output: +// One row per BillingCurrency with BillingCurrency, CommittedComputeEffectiveCost, TotalComputeContractedCost, and CoveragePercent. +// Usage: +// Use this query to measure how much compute spend is covered by commitment discounts without mixing currencies. +// Scope Notes: +// Denominator uses ContractedCost as the post-negotiated, pre-commitment baseline rather than public retail pricing. +// Scope is limited to ServiceCategory == 'Compute', excludes commitment purchase rows, and groups results by BillingCurrency. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned (CoveragePercent=0; expected given commitment data gap) +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) +| where ServiceCategory == 'Compute' +| summarize + CommittedComputeEffectiveCost = todouble(sumif(EffectiveCost, isnotempty(CommitmentDiscountCategory))), + TotalComputeContractedCost = todouble(sum(ContractedCost)) + by BillingCurrency +| extend CoveragePercent = todouble(iff(TotalComputeContractedCost == 0.0, 0.0, 100.0 * CommittedComputeEffectiveCost / TotalComputeContractedCost)) +| project BillingCurrency, CommittedComputeEffectiveCost, TotalComputeContractedCost, CoveragePercent diff --git a/src/queries/catalog/cost-optimization-index.kql b/src/queries/catalog/cost-optimization-index.kql new file mode 100644 index 000000000..9dce0219c --- /dev/null +++ b/src/queries/catalog/cost-optimization-index.kql @@ -0,0 +1,51 @@ +// ============================================================================ +// Query: Cost Optimization Index (COIN) +// Description: +// Calculates the Cost Optimization Index by comparing total reservation recommendation savings opportunity +// against amortized total cost for the reporting window. Reported as a single hub-wide score because the +// Hub `Recommendations()` table does not carry a `BillingCurrency` dimension and savings cannot be safely +// attributed back to a specific currency. +// KPI: Cost Optimization Index (COIN) +// Formula: COIN Score = [1 – (Total Savings Opportunity / Total Cost)] * 100 +// Author: FinOps toolkit +// Parameters: +// startDate: datetime = startofmonth(ago(30d)) +// endDate: datetime = startofmonth(now()) +// Output: +// ReportingCurrencyScope: string ("HubWide") — single-row scope flag; see Scope Notes for multi-currency hubs. +// TotalSavingsOpportunity: double total RI/SP savings opportunity from Recommendations() for the reporting window. +// TotalCost: double amortized effective cost from Costs() for the reporting window, excluding commitment purchases. +// COINScore: double Cost Optimization Index score clamped to 0 when total cost is 0 or the computed score is negative. +// Usage: +// Use this query to estimate how optimized current spend is relative to reservation and savings plan opportunities in FinOps Hub. +// Scope Notes: +// COIN as computed here reflects ONLY commitment-discount (RI/SP) savings opportunities from Microsoft Azure Advisor. +// Does NOT include rightsizing, idle resources, or workload optimization. +// Wave-boundary fix (T-3000.13 cross-model review): gpt-5.5 flagged that grouping by `BillingCurrency` repeated the +// single global savings scalar against each currency's cost, producing misleading per-currency COIN values for +// multi-currency hubs. Recommendations() has no BillingCurrency column, so we now report one hub-wide row. For +// multi-currency hubs operators should normalize Costs() to a single reporting currency before consuming COINScore. +// Time-grain fix (post-UAT, 2026-05-28): Recommendations() has NO RELIABLE BUSINESS TIME GRAIN. The +// `x_RecommendationDate` column is documented but commonly null in live Hubs (verified null on every row in trey-hub +// 2026-05-28 UAT), and `x_IngestionTime` is the ingestion timestamp, not an applicability period. Reservation +// recommendations are point-in-time optimization snapshots, not dated events, so we aggregate the entire current +// recommendation set and compare against the windowed Cost amortization. Filtering Recommendations() by a date +// column would silently drop all unstamped rows (false COIN=100). Cost denominator remains windowed. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned (COIN≈97.66 with $18,976.30 reservation-recommendation savings opportunity captured after time-grain fix) +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let totalSavingsOpportunity = toscalar( + Recommendations() + | where x_SourceType == 'ReservationRecommendations' + | summarize TotalSavingsOpportunity = todouble(sum(x_EffectiveCostSavings)) +); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) +| summarize TotalCost = todouble(sum(EffectiveCost)) +| extend ReportingCurrencyScope = 'HubWide' +| extend TotalSavingsOpportunity = todouble(coalesce(totalSavingsOpportunity, 0.0)) +| extend RawCOINScore = iff(TotalCost == 0.0, 0.0, (1.0 - TotalSavingsOpportunity / TotalCost) * 100.0) +| extend COINScore = todouble(iff(RawCOINScore < 0.0, 0.0, RawCOINScore)) +| project ReportingCurrencyScope, TotalSavingsOpportunity = todouble(TotalSavingsOpportunity), TotalCost = todouble(TotalCost), COINScore diff --git a/src/queries/catalog/cost-per-gb-stored.kql b/src/queries/catalog/cost-per-gb-stored.kql new file mode 100644 index 000000000..19b61f24d --- /dev/null +++ b/src/queries/catalog/cost-per-gb-stored.kql @@ -0,0 +1,42 @@ +// ============================================================================ +// Query: Cost Per Gigabytes Stored +// Description: +// Computes the period-average storage cost per normalized GB-month for storage usage rows. +// It summarizes amortized storage cost and normalized storage consumption by billing currency. +// KPI: Cost per Gigabytes Stored +// Formula: Cloud Storage Costs / Number of GB stored +// Author: FinOps toolkit +// Parameters: +// startDate: datetime (default: startofmonth(ago(30d))) - Start date for the reporting period +// endDate: datetime (default: startofmonth(now())) - End date for the reporting period +// Output: +// Each row returns BillingCurrency, TotalStorageCost, TotalGBMonths, and CostPerGBMonth for qualifying storage usage in the reporting window. +// Usage: +// Use this query to measure the average amortized storage cost rate per GB-month over a reporting period. +// Scope Notes: ConsumedQuantity for storage represents GB-months over the billed period (time-weighted average), not point-in-time GB at rest. CostPerGBMonth is a period-average rate. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where ServiceCategory == 'Storage' and ChargeCategory == 'Usage' +| where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) +| extend x_NormalizedGB = case( + ConsumedUnit endswith 'TB', todouble(ConsumedQuantity) * 1024.0, + ConsumedUnit endswith 'PB', todouble(ConsumedQuantity) * 1048576.0, + ConsumedUnit endswith 'MB', todouble(ConsumedQuantity) / 1024.0, + todouble(ConsumedQuantity) +) +| extend ConsumedUnitBucket = case( + ConsumedUnit endswith 'TB', 'TB→GB (×1024)', + ConsumedUnit endswith 'PB', 'PB→GB (×1048576)', + ConsumedUnit endswith 'MB', 'MB→GB (÷1024)', + 'GB (pass-through)' +) +| summarize + TotalStorageCost = todouble(sum(EffectiveCost)), + TotalGBMonths = todouble(sum(x_NormalizedGB)) + by BillingCurrency +| extend CostPerGBMonth = todouble(iff(TotalGBMonths == 0.0 or isnull(TotalGBMonths), todouble(0), TotalStorageCost / TotalGBMonths)) +| project BillingCurrency, TotalStorageCost, TotalGBMonths, CostPerGBMonth diff --git a/src/queries/catalog/cost-visibility-delay.kql b/src/queries/catalog/cost-visibility-delay.kql new file mode 100644 index 000000000..4ca17fa9f --- /dev/null +++ b/src/queries/catalog/cost-visibility-delay.kql @@ -0,0 +1,62 @@ +// ============================================================================ +// Query: Cost Visibility Delay +// Description: +// Computes the delay between when cost data was generated and when it became visible in the FinOps Hub. +// Aggregates median, p90, p99, and max delay by billing account and reporting month in hours and days. +// KPI: Cost Visibility Delay +// Formula: Cost Visibility Delay = Time of Displaying Cost – Time of Cost Generation +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; start date for the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; end date for the reporting period (default: startofmonth(now())) +// Output: +// BillingAccountId: Billing account identifier for the aggregated bucket. +// ReportingMonth: startofmonth(ChargePeriodStart) reporting bucket. +// RowCount: Count of rows included after filtering out NULL x_IngestionTime values. +// P50DelayHours: Median visibility delay in hours. +// P90DelayHours: 90th percentile visibility delay in hours. +// P99DelayHours: 99th percentile visibility delay in hours. +// MaxDelayHours: Maximum visibility delay in hours. +// P50DelayDays: Median visibility delay in days. +// P90DelayDays: 90th percentile visibility delay in days. +// P99DelayDays: 99th percentile visibility delay in days. +// MaxDelayDays: Maximum visibility delay in days. +// Usage: +// Use this query to measure how quickly cost records become visible in the Hub after the charge period closes. +// Scope Notes: +// BillingCurrency is listed in the spec inputs but omitted from the required output grouping, so results aggregate by BillingAccountId and ReportingMonth only. +// Negative delays are retained to surface anomalies where ingestion precedes ChargePeriodEnd, and legacy hubs with NULL x_IngestionTime return no rows after filtering. +// This KPI is satisfied entirely from Costs() with no cross-table joins and no commitment-purchase exclusion. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS_WITH_NOTE — 1 row returned; 11 cols returned (7 spec-required + 4 documented *DelayDays extras per Output header) +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where isnotnull(x_IngestionTime) +| extend ReportingMonth = startofmonth(ChargePeriodStart) +| extend DelayHours = todouble((x_IngestionTime - ChargePeriodEnd) / 1h) +| summarize + RowCount = count(), + P50DelayHours = todouble(percentile(DelayHours, 50)), + P90DelayHours = todouble(percentile(DelayHours, 90)), + P99DelayHours = todouble(percentile(DelayHours, 99)), + MaxDelayHours = todouble(max(DelayHours)) + by BillingAccountId, ReportingMonth +| extend + P50DelayDays = todouble(P50DelayHours / 24.0), + P90DelayDays = todouble(P90DelayHours / 24.0), + P99DelayDays = todouble(P99DelayHours / 24.0), + MaxDelayDays = todouble(MaxDelayHours / 24.0) +| project + BillingAccountId, + ReportingMonth, + RowCount, + P50DelayHours, + P90DelayHours, + P99DelayHours, + MaxDelayHours, + P50DelayDays, + P90DelayDays, + P99DelayDays, + MaxDelayDays diff --git a/src/queries/catalog/data-update-frequency.kql b/src/queries/catalog/data-update-frequency.kql new file mode 100644 index 000000000..967a0b7f2 --- /dev/null +++ b/src/queries/catalog/data-update-frequency.kql @@ -0,0 +1,39 @@ +// ============================================================================ +// Query: Frequency of Data Updates +// Description: +// Computes the cadence of Hub cost-data ingestion updates for each billing account +// by measuring the gaps between consecutive distinct x_IngestionTime values. +// KPI: Frequency of Data Updates +// Formula: Data Update Frequency = Time of Latest Cost Update – Time of Previous Cost Update +// Author: FinOps toolkit +// Parameters: +// None. This query intentionally uses the full available ingestion history from Costs(). +// Output: +// Each row represents one billing account with its latest ingestion timestamp, distinct +// update count, and median, P90, and maximum update intervals in hours. +// Usage: +// Use this query to measure ingestion freshness cadence and identify stale billing accounts. +// Scope Notes: +// Measures Hub ingestion cadence from x_IngestionTime, not the timing of underlying charges. +// Accounts with only one distinct ingestion timestamp return null interval statistics. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned +// ========================================================================= +Costs() +| summarize + LastUpdate = max(x_IngestionTime), + UpdateCount = dcount(x_IngestionTime), + ingestion_times = make_set(x_IngestionTime) + by BillingAccountId +| mv-expand ingestion_time = ingestion_times to typeof(datetime) +| sort by BillingAccountId asc, ingestion_time asc +| serialize +| extend prev_account = prev(BillingAccountId), prev_t = prev(ingestion_time) +| extend interval_hours = iff(BillingAccountId == prev_account, todouble((ingestion_time - prev_t) / 1h), real(null)) +| summarize + LastUpdate = max(LastUpdate), + UpdateCount = max(UpdateCount), + MedianIntervalHours = todouble(percentile(interval_hours, 50)), + P90IntervalHours = todouble(percentile(interval_hours, 90)), + MaxIntervalHours = todouble(max(interval_hours)) + by BillingAccountId +| project BillingAccountId, LastUpdate, UpdateCount, MedianIntervalHours, P90IntervalHours, MaxIntervalHours diff --git a/src/queries/catalog/macc-consumption-vs-commitment.kql b/src/queries/catalog/macc-consumption-vs-commitment.kql new file mode 100644 index 000000000..ba3526443 --- /dev/null +++ b/src/queries/catalog/macc-consumption-vs-commitment.kql @@ -0,0 +1,59 @@ +// ============================================================================ +// Query: Consumption Versus Commitment +// Description: +// Calculates monthly actual consumption versus monetary commitment for Microsoft Azure Consumption Commitment (MACC) billing accounts. +// Uses EffectiveCost from Costs() as the consumption numerator and x_MonetaryCommitment from Transactions() as the commitment denominator. +// KPI: Consumption versus Commitment +// Formula: Consumption versus Commitment = Actual Consumption Units / Committed Units +// Author: FinOps toolkit +// Parameters: +// startDate: datetime = startofmonth(ago(30d)) +// endDate: datetime = startofmonth(now()) +// Output: +// Each row represents one billing profile + currency + calendar month with ConsumptionAmount, CommitmentAmount, ConsumptionVsCommitmentRatio, and CommitmentBurnPercent. Per-profile CommitmentAmount and ConsumptionAmount sum to account-level totals; the ratio is uniform within an account by construction of the proportional allocation. +// Usage: +// Use this query to monitor monthly MACC burn against committed spend for billing accounts in the active FinOps Hub. +// Scope Notes: +// MACC-only: Query targets Microsoft Azure Consumption Commitment (MACC) customers. Non-MACC billing accounts will join to zero CommitmentAmount and emit a ratio of 0.0. +// OPEN: x_MonetaryCommitment aggregation semantics need validation against a MACC-active FinOps Hub; if Transactions() repeats balances per billing period, replace sum() with max() or a deduplicated latest-event scan. +// Per-profile commitment allocation: x_BillingProfileId is unavailable in Transactions(), so the commitment is +// collected at the BillingAccountId level and then allocated PROPORTIONALLY across profiles by each profile's +// share of account consumption in the reporting window. This preserves the spec output contract (BillingProfileId +// in output) while keeping per-profile ratios analytically meaningful: the sum of CommitmentAmount across all +// profiles in an account equals the account-level commitment, and each profile's ratio represents that profile's +// share of MACC drawdown. Wave-boundary fix (T-3000.15 cross-model review): opus-4.6 flagged BillingAccountId in +// output (spec deviation); gpt-5.5 flagged that naive broadcasting would duplicate commitment per profile. The +// allocation pattern below resolves both findings. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS_SCHEMA_WITH_DATA_GAP — 1 row returned; test hub has 0 Transactions() rows and 0 x_MonetaryCommitment rows, so MACC value semantics require re-UAT on a MACC-active hub. +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let profileConsumption = + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) + | extend ReportingMonth = startofmonth(ChargePeriodStart) + | summarize ProfileConsumption = todouble(sum(EffectiveCost)) by BillingCurrency, BillingAccountId, x_BillingProfileId, ReportingMonth; +let accountCommitment = + Transactions() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where x_TransactionType in ('MACC', 'MonetaryCommitment', 'Microsoft Azure Consumption Commitment') + or isnotnull(x_MonetaryCommitment) + | extend ReportingMonth = startofmonth(ChargePeriodStart) + // VALIDATE on a MACC-active hub: sum(x_MonetaryCommitment) represents the total MACC obligation for the window. + // If the Hub deployment records this repeatedly per billing period instead of once per purchase, + // switch to max() or scan for the most-recent MACC event per period. + | summarize AccountCommitment = todouble(sum(x_MonetaryCommitment)) by BillingCurrency, BillingAccountId, ReportingMonth; +profileConsumption +| join kind=leftouter ( + profileConsumption + | summarize AccountConsumption = sum(ProfileConsumption) by BillingCurrency, BillingAccountId, ReportingMonth +) on BillingCurrency, BillingAccountId, ReportingMonth +| join kind=leftouter accountCommitment on BillingCurrency, BillingAccountId, ReportingMonth +| extend AccountCommitment = todouble(coalesce(AccountCommitment, 0.0)) +| extend ProfileShare = iff(AccountConsumption == 0.0, 0.0, ProfileConsumption / AccountConsumption) +| extend ConsumptionAmount = ProfileConsumption +| extend CommitmentAmount = AccountCommitment * ProfileShare +| extend ConsumptionVsCommitmentRatio = iff(CommitmentAmount == 0.0, 0.0, ConsumptionAmount / CommitmentAmount) +| extend CommitmentBurnPercent = ConsumptionVsCommitmentRatio * 100.0 +| project BillingCurrency, BillingProfileId = x_BillingProfileId, ReportingMonth, ConsumptionAmount, CommitmentAmount, ConsumptionVsCommitmentRatio, CommitmentBurnPercent diff --git a/src/queries/catalog/percentage-unallocated-costs.kql b/src/queries/catalog/percentage-unallocated-costs.kql new file mode 100644 index 000000000..b2d145fd6 --- /dev/null +++ b/src/queries/catalog/percentage-unallocated-costs.kql @@ -0,0 +1,42 @@ +// ============================================================================ +// Query: Percentage of Unallocated Costs +// Description: +// Computes the share of EffectiveCost with no allocation evidence in Costs() using a +// heuristic: no cost allocation rule, no cost center, and no ownership tag key match. +// KPI: Percentage of Costs Associated with Unallocated CSP Cloud Resources +// Formula: (Total Effective Costs Associated with Unallocated CSP Cloud Resources During a Period of Time / Total CSP Cloud Costs During a Period of Time) +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; start of the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; end of the reporting period (default: startofmonth(now())) +// allocationEvidenceTagKeys: dynamic; tag keys that count as allocation evidence +// (default: dynamic(['cost-center','team','owner','application','product'])) +// Output: +// BillingCurrency: billing currency for the summarized row. +// UnallocatedEffectiveCost: total EffectiveCost for rows classified as unallocated. +// TotalEffectiveCost: total EffectiveCost for all rows after commitment-purchase exclusion. +// UnallocatedPercent: unallocated share on a 0-100 scale. +// Usage: +// Use this query to estimate how much spend remains unallocated by billing currency. +// Scope Notes: +// Heuristic-based; the canonical 'allocated/unallocated' classification depends on each +// organization's allocation rules. Parameterize allocationEvidenceTagKeys to match local +// convention. ResourceId is intentionally not used because the spec did not define whether +// non-resource charges should be excluded from the KPI denominator. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned (SEM0019 fixed: decimal(0)→real(0)) +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let allocationEvidenceTagKeys = dynamic(['cost-center','team','owner','application','product']); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) +| extend tmp_TagKeys = coalesce(bag_keys(Tags), dynamic([])) +| extend tmp_HasAllocationEvidenceTag = array_length(set_intersect(tmp_TagKeys, allocationEvidenceTagKeys)) > 0 +| extend tmp_IsUnallocated = isempty(x_CostAllocationRuleName) and isempty(x_CostCenter) and not(tmp_HasAllocationEvidenceTag) +| summarize + UnallocatedEffectiveCost = todouble(sum(iff(tmp_IsUnallocated, EffectiveCost, real(0)))), + TotalEffectiveCost = todouble(sum(EffectiveCost)) + by BillingCurrency +| extend UnallocatedPercent = todouble(iff(TotalEffectiveCost == 0.0, 0.0, UnallocatedEffectiveCost / TotalEffectiveCost * 100.0)) +| project BillingCurrency, UnallocatedEffectiveCost, TotalEffectiveCost, UnallocatedPercent diff --git a/src/queries/catalog/percentage-untagged-costs.kql b/src/queries/catalog/percentage-untagged-costs.kql new file mode 100644 index 000000000..4a0f8d6e4 --- /dev/null +++ b/src/queries/catalog/percentage-untagged-costs.kql @@ -0,0 +1,29 @@ +// ============================================================================ +// Query: Percentage of Untagged Costs +// Description: +// Calculates the percentage of EffectiveCost attributable to CSP resources with no tags. +// Results are grouped by BillingCurrency and exclude commitment purchases to avoid double-counting amortized costs. +// KPI: Percentage of Costs Associated with Untagged CSP Cloud Resources +// Formula: (Total Effective Costs Associated with Untagged CSP Cloud Resources During a Period of Time / Total CSP Effective Cost During a Period of Time) x 100 +// Author: FinOps toolkit +// Parameters: +// startDate: datetime = startofmonth(ago(30d)) +// endDate: datetime = startofmonth(now()) +// Output: +// Each row represents one BillingCurrency and returns UntaggedEffectiveCost, TotalEffectiveCost, and UntaggedPercent for the selected period. +// Usage: +// Use this query to measure how much effective cloud spend is associated with untagged CSP resources. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) +| extend isUntagged = isnull(Tags) or array_length(bag_keys(Tags)) == 0 +| summarize + UntaggedEffectiveCost = todouble(sumif(EffectiveCost, isUntagged)), + TotalEffectiveCost = todouble(sum(EffectiveCost)) + by BillingCurrency +| extend UntaggedPercent = todouble(iff(TotalEffectiveCost == 0.0, 0.0, UntaggedEffectiveCost / TotalEffectiveCost * 100.0)) +| project BillingCurrency, UntaggedEffectiveCost, TotalEffectiveCost, UntaggedPercent diff --git a/src/queries/catalog/storage-tier-distribution.kql b/src/queries/catalog/storage-tier-distribution.kql new file mode 100644 index 000000000..6027ae3e9 --- /dev/null +++ b/src/queries/catalog/storage-tier-distribution.kql @@ -0,0 +1,58 @@ +// ============================================================================ +// Query: Storage Tier Distribution +// Description: +// Summarizes storage usage by access-tier bucket and shows the share of spend and normalized GB-months +// on Frequent, Infrequent, and Unclassified storage tiers for each billing currency. +// KPI: Percent Storage on Frequent Access Tier +// Formula: Number of GB in Standard (or 'frequently accessed' tiers) vs. total GBs stored +// Author: FinOps toolkit +// Parameters: +// startDate: datetime = startofmonth(ago(30d)) +// endDate: datetime = startofmonth(now()) +// Output: +// Each row represents one BillingCurrency and TierBucket pair with EffectiveCost, normalized GBMonths, +// CostPercent, and GBPercent for that bucket within the currency. +// Usage: +// Use this query to measure how much storage cost and GB-month usage remains on frequently accessed tiers. +// Scope Notes: +// Tier classification uses x_SkuTier with fallback to x_SkuMeterSubcategory keyword matching. +// ConsumedQuantity for storage typically represents GB-months over the billed period (time-weighted), not raw GB at a point in time. +// Unclassified rows are intentionally preserved so users can extend the tier-matching logic for uncovered SKUs. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 2 rows returned (Frequent + other tiers) +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let bucketedCosts = + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where ServiceCategory == 'Storage' and ChargeCategory == 'Usage' + | extend TierBucket = case( + x_SkuTier in ('Hot', 'Standard', 'Premium'), 'Frequent', + x_SkuTier in ('Cool', 'Cold', 'Archive'), 'Infrequent', + x_SkuMeterSubcategory has_any ('Hot LRS', 'Hot ZRS', 'Hot GRS', 'Standard', 'Premium', 'Frequent'), 'Frequent', + x_SkuMeterSubcategory has_any ('Cool', 'Cold', 'Archive'), 'Infrequent', + 'Unclassified') + | extend GBMonths = todouble(case( + ConsumedUnit contains 'PB', todouble(ConsumedQuantity) * 1048576.0, + ConsumedUnit contains 'TB', todouble(ConsumedQuantity) * 1024.0, + ConsumedUnit contains 'MB', todouble(ConsumedQuantity) / 1024.0, + todouble(ConsumedQuantity))); +let totalsByCurrency = + bucketedCosts + | summarize + TotalEffectiveCost = sum(EffectiveCost), + TotalGBMonths = sum(GBMonths) + by BillingCurrency; +bucketedCosts +| summarize + EffectiveCost = todouble(sum(EffectiveCost)), + GBMonths = todouble(sum(GBMonths)) + by BillingCurrency, TierBucket +| join kind=inner totalsByCurrency on BillingCurrency +| project + BillingCurrency, + TierBucket, + EffectiveCost, + GBMonths, + CostPercent = todouble(iff(todouble(TotalEffectiveCost) == 0.0, 0.0, EffectiveCost / todouble(TotalEffectiveCost) * 100.0)), + GBPercent = todouble(iff(TotalGBMonths == 0.0, 0.0, GBMonths / TotalGBMonths * 100.0)) diff --git a/src/queries/catalog/tagging-policy-compliance.kql b/src/queries/catalog/tagging-policy-compliance.kql new file mode 100644 index 000000000..026c69d72 --- /dev/null +++ b/src/queries/catalog/tagging-policy-compliance.kql @@ -0,0 +1,56 @@ +// ============================================================================ +// Query: Tagging Policy Compliance +// Description: +// Computes the FinOps Foundation KPI for Tagging Policy Compliance — +// the percentage of effective cloud costs associated with resources that +// satisfy all required tag keys with non-empty values. +// KPI: Percentage of CSP Cloud Costs that are Tagging Policy Compliant +// Formula: (Total Effective Costs Associated with Tagging Policy Compliant CSP Cloud Resources During a Period of Time +// / Total CSP Cloud Effective Costs During a Period of Time) x 100 +// Author: FinOps toolkit +// Parameters: +// startDate: datetime; Start date for the reporting period (default: startofmonth(ago(30d))) +// endDate: datetime; End date for the reporting period (default: startofmonth(now())) +// requiredTagKeys: dynamic; Array of tag key strings that must all be present and non-empty +// (default: dynamic(['cost-center', 'environment', 'owner'])) +// Output: +// BillingCurrency: string; Currency for the billing period; one row per distinct currency. +// CompliantEffectiveCost: double; Sum of effective cost for rows where all required tag keys are present with non-empty values. +// TotalEffectiveCost: double; Sum of effective cost for all rows in scope, excluding commitment purchases. +// CompliancePercent: double; Percentage of total effective cost that is tagging-policy compliant. +// Usage: +// Use to measure and track tag policy adherence across cloud spend over time. +// Scope Notes: +// Policy is defined by the requiredTagKeys parameter. Caller is responsible for +// keeping it in sync with their organization's tag policy. Resources with null Tags +// or missing/empty required-key values are treated as non-compliant. +// Last Tested: 2026-05-28 against msbwftktreyhub.westus.kusto.windows.net/Hub (1,366,763 cost rows in 2026-04 window). UAT result: PASS — 1 row returned in 3.04 seconds after distinct-tag optimization +// ========================================================================= +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let requiredTagKeys = dynamic(['cost-center', 'environment', 'owner']); +let base = materialize( + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where not(ChargeCategory == 'Purchase' and isnotempty(CommitmentDiscountCategory)) + | project BillingCurrency, EffectiveCost = todouble(EffectiveCost), Tags, tmp_TagsString = tostring(Tags) +); +let tag_compliance = materialize( + base + | summarize Tags = take_any(Tags) by tmp_TagsString + | extend tmp_TagKeys = coalesce(bag_keys(Tags), dynamic([])) + | extend tmp_AllKeysPresent = array_length(set_intersect(tmp_TagKeys, requiredTagKeys)) == array_length(requiredTagKeys) + | mv-apply k = requiredTagKeys to typeof(string) on ( + summarize tmp_AnyValueEmpty = countif(isempty(tostring(Tags[k]))) > 0 + ) + | extend tmp_IsCompliant = tmp_AllKeysPresent and not(tmp_AnyValueEmpty) + | project tmp_TagsString, tmp_IsCompliant +); +base +| join kind=leftouter tag_compliance on tmp_TagsString +| summarize + CompliantEffectiveCost = todouble(sumif(EffectiveCost, tmp_IsCompliant)), + TotalEffectiveCost = todouble(sum(EffectiveCost)) + by BillingCurrency +| extend CompliancePercent = iff(TotalEffectiveCost == 0, 0.0, CompliantEffectiveCost / TotalEffectiveCost * 100.0) +| project BillingCurrency, CompliantEffectiveCost, TotalEffectiveCost, CompliancePercent diff --git a/src/queries/finops-hub-database-guide.md b/src/queries/finops-hub-database-guide.md index a04e8efb1..aebefa758 100644 --- a/src/queries/finops-hub-database-guide.md +++ b/src/queries/finops-hub-database-guide.md @@ -91,8 +91,8 @@ The FinOps hubs database is designed to support advanced cost and usage analytic ## Query Best Practices -- **Start with the [`costs-enriched-base`](./catalog/costs-enriched-base.kql) query:** - Use this query as your base for any cost or usage analytics. It provides the full enrichment and savings logic for all cost columns and is the recommended foundation for custom analytics and reporting. +- **Prefer scenario-specific aggregate queries first:** + Use the query catalog to find the narrowest query that answers the question. Use [`costs-enriched-base`](./catalog/costs-enriched-base.kql) when you need scoped row-level enrichment or repeated drill-downs. - **Use KQL (Kusto Query Language):** All queries should be written in KQL for compatibility with Azure Data Explorer. @@ -362,6 +362,9 @@ Costs() > **Note:** > All columns prefixed with `x_` are toolkit enrichment columns, providing additional context for FinOps analysis. +> **Numeric column types — live Hub behavior:** +> Columns documented below as `real` are exposed by the live Hub as `real` (a 64-bit floating-point type, equivalent to KQL `double` / .NET `System.Double`). Earlier versions of this guide listed numeric columns as `decimal`, but the deployed Hub schemas across `Costs()`, `Prices()`, and `Recommendations()` use `real`. When writing literal numeric defaults in KQL queries (for example the `false`-branch of an `iff(...)` aggregate), use `real(0)` — not `decimal(0)` — to avoid `SEM0019` arithmetic type-mismatch errors. + Below are the column definitions for the main analytic tables in the FinOps hubs database. These definitions are based on Microsoft Learn, FinOps best practices, and common cloud cost management terminology. --- @@ -373,7 +376,7 @@ The following table lists the columns produced in the `All available columns` qu | Column Name | Data Type | Description | | ---------------------------------------- | --------- | --------------------------------------------------------------------------------- | | AvailabilityZone | string | Availability zone of the resource, if applicable. | -| BilledCost | decimal | The cost billed for the resource or usage. | +| BilledCost | real | The cost billed for the resource or usage. | | BillingAccountId | string | Unique identifier for the billing account. | | BillingAccountName | string | Name of the billing account. | | BillingAccountType | string | Type of billing account (e.g., EA, MCA). | @@ -391,16 +394,16 @@ The following table lists the columns produced in the `All available columns` qu | CommitmentDiscountName | string | Name of the commitment discount. | | CommitmentDiscountStatus | string | Status of the commitment discount (e.g., Used, Unused). | | CommitmentDiscountType | string | The specific type of discount (e.g., RI, SP). | -| ConsumedQuantity | decimal | Amount of resource usage consumed. | +| ConsumedQuantity | real | Amount of resource usage consumed. | | ConsumedUnit | string | Unit of measure for consumed quantity. | -| ContractedCost | decimal | Negotiated cost for the resource or usage. | -| ContractedUnitPrice | decimal | Negotiated unit price for the resource. | -| EffectiveCost | decimal | Actual cost after all discounts and credits. | +| ContractedCost | real | Negotiated cost for the resource or usage. | +| ContractedUnitPrice | real | Negotiated unit price for the resource. | +| EffectiveCost | real | Actual cost after all discounts and credits. | | InvoiceIssuerName | string | Name of the invoice issuer. | -| ListCost | decimal | List (retail) cost for the resource or usage. | -| ListUnitPrice | decimal | List (retail) unit price for the resource. | +| ListCost | real | List (retail) cost for the resource or usage. | +| ListUnitPrice | real | List (retail) unit price for the resource. | | PricingCategory | string | Category of pricing (e.g., Standard, Spot). | -| PricingQuantity | decimal | Quantity used for pricing. | +| PricingQuantity | real | Quantity used for pricing. | | PricingUnit | string | Unit of measure for pricing. | | ProviderName | string | Name of the cloud provider. | | PublisherName | string | Name of the publisher. | @@ -420,40 +423,40 @@ The following table lists the columns produced in the `All available columns` qu | x_AccountId | string | Enriched account identifier. | | x_AccountName | string | Enriched account name. | | x_AccountOwnerId | string | Owner ID for the account. | -| x_BilledCostInUsd | decimal | Billed cost converted to USD. | -| x_BilledUnitPrice | decimal | Billed unit price. | +| x_BilledCostInUsd | real | Billed cost converted to USD. | +| x_BilledUnitPrice | real | Billed unit price. | | x_BillingAccountAgreement | string | Billing agreement reference. | | x_BillingAccountId | string | Enriched billing account ID. | | x_BillingAccountName | string | Enriched billing account name. | -| x_BillingExchangeRate | decimal | Exchange rate used for billing. | +| x_BillingExchangeRate | real | Exchange rate used for billing. | | x_BillingExchangeRateDate | datetime | Date of the exchange rate. | | x_BillingProfileId | string | Billing profile identifier. | | x_BillingProfileName | string | Name of the billing profile. | | x_ChargeId | string | Unique identifier for the charge. | -| x_ContractedCostInUsd | decimal | Contracted cost converted to USD. | +| x_ContractedCostInUsd | real | Contracted cost converted to USD. | | x_CostAllocationRuleName | string | Name of the cost allocation rule. | | x_CostCategories | dynamic | Cost categories as a dynamic object. | | x_CostCenter | string | Cost center for the transaction. | | x_Credits | dynamic | Credits applied as a dynamic object. | | x_CostType | string | Type of cost (e.g., Amortized, Principal). | -| x_CurrencyConversionRate | decimal | Currency conversion rate used. | +| x_CurrencyConversionRate | real | Currency conversion rate used. | | x_CustomerId | string | Customer identifier. | | x_CustomerName | string | Name of the customer. | | x_Discount | dynamic | Discount details as a dynamic object. | -| x_EffectiveCostInUsd | decimal | Effective cost converted to USD. | -| x_EffectiveUnitPrice | decimal | Final unit price after all discounts. | +| x_EffectiveCostInUsd | real | Effective cost converted to USD. | +| x_EffectiveUnitPrice | real | Final unit price after all discounts. | | x_ExportTime | datetime | Time the record was exported. | | x_IngestionTime | datetime | Timestamp when the record was ingested. | | x_InvoiceId | string | Invoice identifier. | | x_InvoiceIssuerId | string | Invoice issuer identifier. | | x_InvoiceSectionId | string | Invoice section identifier. | | x_InvoiceSectionName | string | Invoice section name. | -| x_ListCostInUsd | decimal | List cost converted to USD. | +| x_ListCostInUsd | real | List cost converted to USD. | | x_Location | string | Location of the resource. | | x_Operation | string | Operation performed. | | x_PartnerCreditApplied | string | Whether partner credit was applied. | | x_PartnerCreditRate | string | Partner credit rate. | -| x_PricingBlockSize | decimal | Block size for pricing. | +| x_PricingBlockSize | real | Block size for pricing. | | x_PricingCurrency | string | Currency for pricing. | | x_PricingSubcategory | string | Subcategory for pricing. | | x_PricingUnitDescription | string | Description of the pricing unit. | @@ -495,23 +498,23 @@ The following table lists the columns produced in the `All available columns` qu | x_SkuUsageType | string | Usage type for the SKU. | | x_SkuImageType | string | Image type for the SKU. | | x_SkuType | string | Service type for the SKU. | -| x_ConsumedCoreHours | decimal | Total core hours consumed. | +| x_ConsumedCoreHours | real | Total core hours consumed. | | x_SkuLicenseStatus | string | License status for the SKU. | | x_SkuLicenseType | string | License type for the SKU. | | x_SkuLicenseQuantity | long | License quantity for the SKU. | | x_SkuLicenseUnit | string | License unit for the SKU. | | x_SkuLicenseUnusedQuantity | long | Unused license quantity for the SKU. | | x_CommitmentDiscountKey | string | Key for commitment discount utilization. | -| x_CommitmentDiscountUtilizationPotential | decimal | Potential utilization for commitment discount. | -| x_CommitmentDiscountUtilizationAmount | decimal | Actual utilization amount for commitment discount. | +| x_CommitmentDiscountUtilizationPotential | real | Potential utilization for commitment discount. | +| x_CommitmentDiscountUtilizationAmount | real | Actual utilization amount for commitment discount. | | x_SkuTermLabel | string | Human-readable label for SKU term. | | x_AmortizationCategory | string | Amortization category (e.g., Principal, Amortized Charge). | -| x_CommitmentDiscountSavings | decimal | Realized savings from commitment discounts (actual savings applied to your bill). | -| x_NegotiatedDiscountSavings | decimal | Realized savings from negotiated discounts (actual savings applied to your bill). | -| x_TotalSavings | decimal | Realized total savings (negotiated + commitment, as actually applied). | -| x_CommitmentDiscountPercent | decimal | Percent savings from commitment discount. | -| x_NegotiatedDiscountPercent | decimal | Percent savings from negotiated discount. | -| x_TotalDiscountPercent | decimal | Total percent savings. | +| x_CommitmentDiscountSavings | real | Realized savings from commitment discounts (actual savings applied to your bill). | +| x_NegotiatedDiscountSavings | real | Realized savings from negotiated discounts (actual savings applied to your bill). | +| x_TotalSavings | real | Realized total savings (negotiated + commitment, as actually applied). | +| x_CommitmentDiscountPercent | real | Percent savings from commitment discount. | +| x_NegotiatedDiscountPercent | real | Percent savings from negotiated discount. | +| x_TotalDiscountPercent | real | Total percent savings. | | x_ToolkitTool | string | Toolkit tool name. | | x_ToolkitVersion | string | Toolkit version. | | x_ResourceParentId | string | Resource parent identifier. | @@ -538,34 +541,34 @@ The following table lists the columns produced in the `All available columns` qu | ChargeCategory | string | Category of the charge (e.g., Usage, Purchase). | | CommitmentDiscountCategory | string | Type of commitment discount. | | CommitmentDiscountType | string | Specific type of discount. | -| ContractedUnitPrice | decimal | Negotiated unit price for the resource. | -| ListUnitPrice | decimal | List (retail) unit price for the resource. | +| ContractedUnitPrice | real | Negotiated unit price for the resource. | +| ListUnitPrice | real | List (retail) unit price for the resource. | | PricingCategory | string | Category of pricing (e.g., Standard, Spot). | | PricingUnit | string | Unit of measure for pricing (e.g., hours, GB). | | SkuId | string | Unique identifier for the SKU. | | SkuPriceId | string | Unique identifier for the SKU price. | | SkuPriceIdv2 | string | Alternate identifier for the SKU price. | -| x_BaseUnitPrice | decimal | Base unit price before discounts. | +| x_BaseUnitPrice | real | Base unit price before discounts. | | x_BillingAccountAgreement | string | Billing agreement reference. | | x_BillingAccountId | string | Enriched billing account ID. | | x_BillingProfileId | string | Billing profile identifier. | | x_CommitmentDiscountSpendEligibility | string | Eligibility for spend-based discounts. | | x_CommitmentDiscountUsageEligibility | string | Eligibility for usage-based discounts. | -| x_ContractedUnitPriceDiscount | decimal | Discount amount from contracted price. | -| x_ContractedUnitPriceDiscountPercent | decimal | Discount percent from contracted price. | +| x_ContractedUnitPriceDiscount | real | Discount amount from contracted price. | +| x_ContractedUnitPriceDiscountPercent | real | Discount percent from contracted price. | | x_EffectivePeriodEnd | datetime | End of the effective pricing period. | | x_EffectivePeriodStart | datetime | Start of the effective pricing period. | -| x_EffectiveUnitPrice | decimal | Final unit price after all discounts. | -| x_EffectiveUnitPriceDiscount | decimal | Discount amount from effective price. | -| x_EffectiveUnitPriceDiscountPercent | decimal | Discount percent from effective price. | +| x_EffectiveUnitPrice | real | Final unit price after all discounts. | +| x_EffectiveUnitPriceDiscount | real | Discount amount from effective price. | +| x_EffectiveUnitPriceDiscountPercent | real | Discount percent from effective price. | | x_IngestionTime | datetime | Timestamp when the record was ingested. | -| x_PricingBlockSize | decimal | Block size for pricing (e.g., 1000 units). | +| x_PricingBlockSize | real | Block size for pricing (e.g., 1000 units). | | x_PricingCurrency | string | Currency for pricing. | | x_PricingSubcategory | string | Subcategory for pricing. | | x_PricingUnitDescription | string | Description of the pricing unit. | | x_SkuDescription | string | Description of the SKU. | | x_SkuId | string | Enriched SKU ID. | -| x_SkuIncludedQuantity | decimal | Quantity included at no extra cost. | +| x_SkuIncludedQuantity | real | Quantity included at no extra cost. | | x_SkuMeterCategory | string | Meter category for the SKU. | | x_SkuMeterId | string | Meter ID for the SKU. | | x_SkuMeterName | string | Meter name for the SKU. | @@ -578,32 +581,43 @@ The following table lists the columns produced in the `All available columns` qu | x_SkuOfferId | string | Offer ID for the SKU. | | x_SkuPartNumber | string | Part number for the SKU. | | x_SkuTerm | int | Term length for the SKU (months). | -| x_SkuTier | decimal | Tier for the SKU (e.g., Standard, Premium). | +| x_SkuTier | real | Tier for the SKU (e.g., Standard, Premium). | | x_SourceName | string | Name of the data source. | | x_SourceProvider | string | Provider of the data source. | | x_SourceType | string | Type of data source. | | x_SourceVersion | string | Version of the data source. | -| x_TotalUnitPriceDiscount | decimal | Total discount amount. | -| x_TotalUnitPriceDiscountPercent | decimal | Total discount percent. | +| x_TotalUnitPriceDiscount | real | Total discount amount. | +| x_TotalUnitPriceDiscountPercent | real | Total discount percent. | --- ### Recommendations() -| Column Name | Data Type | Description | -| ----------------------- | --------- | ------------------------------------------------- | -| ProviderName | string | Name of the cloud provider. | -| SubAccountId | string | Identifier for the sub-account or subscription. | -| x_IngestionTime | datetime | Timestamp when the record was ingested. | -| x_EffectiveCostAfter | decimal | Projected cost after applying the recommendation. | -| x_EffectiveCostBefore | decimal | Cost before applying the recommendation. | -| x_EffectiveCostSavings | decimal | Estimated cost savings from the recommendation. | -| x_RecommendationDate | datetime | Date the recommendation was generated. | -| x_RecommendationDetails | dynamic | Details of the recommendation (dynamic object). | -| x_SourceName | string | Name of the data source. | -| x_SourceProvider | string | Provider of the data source. | -| x_SourceType | string | Type of data source. | -| x_SourceVersion | string | Version of the data source. | +> **Sparsely-populated columns:** +> The `Recommendations()` function is sourced from upstream optimization recommenders (for example, Azure Advisor reservation recommendations). Many string identifier columns below (`ResourceId`, `ResourceName`, `SubAccountId`, `SubAccountName`, `x_RecommendationId`, `x_RecommendationDescription`, `x_ResourceGroupName`) may be empty strings in practice if the source recommender does not surface them. Verify population with `Recommendations() | summarize count() by isnotempty()` before relying on a column as a join key or filter. + +| Column Name | Data Type | Description | +| ---------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ProviderName | string | Name of the cloud provider. | +| ResourceId | string | Unique identifier for the resource the recommendation applies to. | +| ResourceName | string | Display name of the resource. | +| ResourceType | string | Type of the resource (e.g., `virtualmachines`). | +| SubAccountId | string | Identifier for the sub-account or subscription. | +| SubAccountName | string | Display name of the sub-account or subscription. | +| x_EffectiveCostAfter | real | Projected cost after applying the recommendation. | +| x_EffectiveCostBefore | real | Cost before applying the recommendation. | +| x_EffectiveCostSavings | real | Estimated cost savings from the recommendation. | +| x_IngestionTime | datetime | Timestamp when the record was ingested. Always populated. | +| x_RecommendationCategory | string | Category of the recommendation (e.g., `ReservationRecommendations`, `SavingsPlanRecommendations`). | +| x_RecommendationDate | datetime | Date the recommendation was generated by the source recommender. **Commonly null in live Hubs** — the upstream recommender may not stamp this field. Do not filter `Recommendations()` by `x_RecommendationDate` with a date-window predicate (e.g., `where x_RecommendationDate >= startDate`) — KQL `null >= datetime(…)` evaluates false, silently dropping every row. Use `x_IngestionTime` as the time anchor. | +| x_RecommendationDescription | string | Human-readable description of the recommendation. | +| x_RecommendationDetails | dynamic | Structured details of the recommendation (dynamic object — shape varies by category). | +| x_RecommendationId | string | Unique identifier for the recommendation. | +| x_ResourceGroupName | string | Resource group containing the resource (Azure only). | +| x_SourceName | string | Name of the data source. | +| x_SourceProvider | string | Provider of the data source. | +| x_SourceType | string | Type of data source. | +| x_SourceVersion | string | Version of the data source. | --- @@ -675,10 +689,11 @@ The following table lists the columns produced in the `All available columns` qu ## Change log -| Date | Version | Author | Notes | -| ---------- | ------- | ------------------- | ------------------------------------- | -| 2025-05-16 | 1.0 | FinOps Toolkit Team | Initial documentation | -| 2025-05-16 | 1.1 | FinOps Toolkit Team | Expanded schema, glossary, references | +| Date | Version | Author | Notes | +| ---------- | ------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 2025-05-16 | 1.0 | FinOps Toolkit Team | Initial documentation | +| 2025-05-16 | 1.1 | FinOps Toolkit Team | Expanded schema, glossary, references | +| 2026-05-28 | 1.2 | Sprint 3000 UAT | Live-Hub schema audit (msbwftktreyhub): `Costs()`, `Prices()`, `Recommendations()` numeric columns retyped from `decimal` to `real` to match deployed Hub schema (cause of SEM0019 errors). `Recommendations()` table expanded from 12 to 20 columns to add the 8 columns present in the live schema. `x_RecommendationDate` documented as commonly-null in live Hubs (root cause of T-3000.13). | --- From 87443aa749d6e265dadde982f6c60887d2a61c74 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 07:46:43 -0700 Subject: [PATCH 02/19] feat(sre-agent): add FinOps recipe content --- .gitmodules | 3 + .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 1056 +++++++++++++++++ src/templates/sre-agent/.gitattributes | 1 + src/templates/sre-agent/.gitignore | 3 + src/templates/sre-agent/.upstream-pin | 5 + src/templates/sre-agent/AGENTS.md | 31 + src/templates/sre-agent/CATALOG.md | 256 ++++ src/templates/sre-agent/README.md | 243 ++++ src/templates/sre-agent/bin/build-extras.py | 477 ++++++++ src/templates/sre-agent/bin/verify-agent.sh | 548 +++++++++ .../sre-agent/recipes/finops-hub/README.md | 33 + .../sre-agent/recipes/finops-hub/agent.json | 21 + .../advisor-suppression-review.yaml | 80 ++ .../ai-workload-cost-analysis.yaml | 194 +++ .../scheduled-tasks/alert-coverage-audit.yaml | 84 ++ .../benefit-recommendation-review.yaml | 84 ++ .../budget-coverage-audit.yaml | 80 ++ .../capacity-daily-monitor.yaml | 134 +++ .../capacity-monthly-planning.yaml | 166 +++ .../capacity-quarterly-strategy.yaml | 163 +++ .../capacity-weekly-supply-review.yaml | 149 +++ .../compute-utilization-trend.yaml | 84 ++ .../scheduled-tasks/cost-optimization.yaml | 333 ++++++ .../scheduled-tasks/db-quota-audit.yaml | 60 + .../scheduled-tasks/hubs-health-check.yaml | 106 ++ .../monitoring-scope-validation.yaml | 88 ++ .../scheduled-tasks/monthly-report.yaml | 193 +++ .../non-compute-quota-audit.yaml | 81 ++ .../sku-availability-audit.yaml | 86 ++ .../storage-paas-growth-forecast.yaml | 87 ++ .../scheduled-tasks/yoy-report.yaml | 186 +++ .../finops-hub/config/built-in-tools.json | 40 + .../skills/azure-capacity-management/SKILL.md | 1 + .../azure-capacity-management/references/docs | 1 + .../references/scripts | 1 + .../skills/azure-cost-management/README.md | 48 + .../skills/azure-cost-management/SKILL.md | 195 +++ .../references/Get-BenefitRecommendations.ps1 | 76 ++ .../references/azure-advisor.md | 259 ++++ .../references/azure-anomaly-alerts.md | 292 +++++ .../references/azure-budgets.md | 188 +++ .../azure-commitment-discount-decision.md | 218 ++++ .../references/azure-cost-exports.md | 178 +++ .../references/azure-credits.md | 163 +++ .../references/azure-macc.md | 122 ++ .../references/azure-orphaned-resources.md | 329 +++++ .../references/azure-reservations.md | 353 ++++++ .../references/azure-retail-prices.md | 263 ++++ .../references/azure-savings-plans.md | 424 +++++++ .../references/azure-vm-rightsizing.md | 293 +++++ .../config/skills/finops-toolkit/README.md | 103 ++ .../config/skills/finops-toolkit/SKILL.md | 373 ++++++ .../references/cost-anomaly-detection.md | 171 +++ .../references/cost-comparison.md | 293 +++++ .../references/cost-spike-investigation.md | 192 +++ .../references/cost-trend-analysis.md | 186 +++ .../references/custom-dimension-analysis.md | 153 +++ .../references/finops-hubs-deployment.md | 323 +++++ .../finops-toolkit/references/finops-hubs.md | 130 ++ .../skills/finops-toolkit/references/queries | 1 + .../references/service-cost-deep-dive.md | 374 ++++++ .../references/settings-format.md | 71 ++ .../references/tag-coverage-analysis.md | 219 ++++ .../references/top-cost-drivers.md | 183 +++ .../understand-finops-hub-context.md | 138 +++ .../references/workflows/ftk-hubs-connect.md | 98 ++ .../workflows/ftk-hubs-healthCheck.md | 31 + .../subagents/azure-capacity-manager.yaml | 122 ++ .../subagents/chief-financial-officer.yaml | 45 + .../config/subagents/finops-practitioner.yaml | 86 ++ .../config/subagents/ftk-database-query.yaml | 146 +++ .../config/subagents/ftk-hubs-agent.yaml | 110 ++ .../config/tools/benefit-recommendations.yaml | 186 +++ .../tools/capacity-reservation-groups.yaml | 199 ++++ .../config/tools/data-freshness-check.yaml | 454 +++++++ .../config/tools/db-service-quotas.yaml | 562 +++++++++ .../config/tools/deploy-anomaly-alert.yaml | 114 ++ .../config/tools/deploy-budget.yaml | 176 +++ .../tools/deploy-bulk-anomaly-alerts.yaml | 153 +++ .../config/tools/deploy-bulk-budgets.yaml | 202 ++++ .../config/tools/non-compute-quotas.yaml | 505 ++++++++ .../config/tools/resource-graph-query.yaml | 129 ++ .../config/tools/sku-availability.yaml | 247 ++++ .../suppress-advisor-recommendations.yaml | 161 +++ .../config/tools/vm-quota-usage.yaml | 196 +++ .../recipes/finops-hub/connectors.json | 13 + .../recipes/finops-hub/expected-config.json | 217 ++++ .../knowledge/chart-artifact-verification.md | 57 + .../finops-hub/knowledge/document-index.md | 25 + .../knowledge/known-issues-and-workarounds.md | 249 ++++ .../knowledge/onboarding-recommendations.md | 88 ++ .../knowledge/teams-notification-guide.md | 63 + .../sre-agent/recipes/finops-hub/roles.yaml | 17 + src/templates/sre-agent/submodules/azcapman | 1 + 94 files changed, 16121 insertions(+) create mode 100644 .gitmodules create mode 100644 src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 create mode 100644 src/templates/sre-agent/.gitattributes create mode 100644 src/templates/sre-agent/.gitignore create mode 100644 src/templates/sre-agent/.upstream-pin create mode 100644 src/templates/sre-agent/AGENTS.md create mode 100644 src/templates/sre-agent/CATALOG.md create mode 100644 src/templates/sre-agent/README.md create mode 100755 src/templates/sre-agent/bin/build-extras.py create mode 100755 src/templates/sre-agent/bin/verify-agent.sh create mode 100644 src/templates/sre-agent/recipes/finops-hub/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/agent.json create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/ai-workload-cost-analysis.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-daily-monitor.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-monthly-planning.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-quarterly-strategy.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-weekly-supply-review.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/cost-optimization.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/db-quota-audit.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/hubs-health-check.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monthly-report.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/non-compute-quota-audit.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/sku-availability-audit.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/storage-paas-growth-forecast.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/built-in-tools.json create mode 120000 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md create mode 120000 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs create mode 120000 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/SKILL.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-budgets.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-commitment-discount-decision.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-cost-exports.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-credits.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-macc.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-orphaned-resources.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-reservations.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-retail-prices.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-savings-plans.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-vm-rightsizing.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/SKILL.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-anomaly-detection.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-comparison.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-spike-investigation.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-trend-analysis.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/custom-dimension-analysis.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs-deployment.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs.md create mode 120000 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/queries create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/service-cost-deep-dive.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/settings-format.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/top-cost-drivers.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/understand-finops-hub-context.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-connect.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-healthCheck.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/subagents/azure-capacity-manager.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/subagents/chief-financial-officer.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/subagents/finops-practitioner.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-database-query.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml create mode 100644 src/templates/sre-agent/recipes/finops-hub/connectors.json create mode 100644 src/templates/sre-agent/recipes/finops-hub/expected-config.json create mode 100644 src/templates/sre-agent/recipes/finops-hub/knowledge/chart-artifact-verification.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/knowledge/document-index.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/knowledge/known-issues-and-workarounds.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/knowledge/onboarding-recommendations.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/roles.yaml create mode 160000 src/templates/sre-agent/submodules/azcapman diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d982686fe --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/templates/sre-agent/submodules/azcapman"] + path = src/templates/sre-agent/submodules/azcapman + url = https://github.com/microsoft/azcapman.git diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 new file mode 100644 index 000000000..6874aac05 --- /dev/null +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -0,0 +1,1056 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'SRE Agent deploy template' { + BeforeAll { + $script:RepoRoot = (Get-Item -Path $PSScriptRoot).Parent.Parent.Parent.Parent.FullName + $script:DeployScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/deploy.sh' + $script:ApplyExtrasScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh' + $script:PostProvisionScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/post-provision.sh' + $script:VerifyScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh' + $script:RecipeDir = Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub' + $script:ScheduledTaskDir = Join-Path $script:RecipeDir 'automations/scheduled-tasks' + $script:OutputStylePath = Join-Path $script:RepoRoot 'src/templates/claude-plugin/output-styles/ftk-output-style.md' + $script:ReadmePath = Join-Path $script:RepoRoot 'src/templates/sre-agent/README.md' + $script:DocsPath = Join-Path $script:RepoRoot 'docs-mslearn/toolkit/sre-agent/deploy.md' + $script:AgentJsonPath = Join-Path $script:RecipeDir 'agent.json' + $script:SkipBash = -not (Get-Command bash -ErrorAction SilentlyContinue) + + function Invoke-BashCommand { + param( + [Parameter(Mandatory)] + [string] $Command + ) + + Push-Location $script:RepoRoot + try { + $output = & bash -lc $Command 2>&1 + [pscustomobject]@{ + ExitCode = $LASTEXITCODE + Output = ($output -join "`n") + } + } + finally { + Pop-Location + } + } + + function Invoke-BashCommandWithPath { + param( + [Parameter(Mandatory)] + [string] $Command, + + [Parameter(Mandatory)] + [string] $PathPrefix + ) + + Push-Location $script:RepoRoot + try { + $originalPath = $env:PATH + $env:PATH = "${PathPrefix}:$originalPath" + $output = & bash -c $Command 2>&1 + [pscustomobject]@{ + ExitCode = $LASTEXITCODE + Output = ($output -join "`n") + } + } + finally { + $env:PATH = $originalPath + Pop-Location + } + } + + function Set-BashStub { + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [string] $Content + ) + + $utf8NoBom = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, ($Content -replace "`r`n", "`n"), $utf8NoBom) + & chmod +x $Path + } + } + + Context 'bash availability' { + It 'has bash available for hermetic tests' { + if ($script:SkipBash) { + Set-ItResult -Skipped -Because 'bash is unavailable' + } + $true | Should -BeTrue + } + } + + Context 'help and parsing' { + It 'prints help with portal labels and required flags' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --help" + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Resource group' + $result.Output | Should -Match 'Agent name' + $result.Output | Should -Match 'Region' + $result.Output | Should -Match 'Subscription' + $result.Output | Should -Match '--cluster-uri' + } + + It 'documents the same help lines in README and docs' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $help = Invoke-BashCommand "bash '$script:DeployScript' --help" + $help.ExitCode | Should -Be 0 + $readme = Get-Content -Path $script:ReadmePath -Raw + $docs = Get-Content -Path $script:DocsPath -Raw + + @( + '--recipe ', + '--resource-group ', + '--name ', + '--location ', + '--subscription ', + '--cluster-uri ', + '--cluster-resource-id ', + '--deploy-name ' + ) | ForEach-Object { + $escaped = [regex]::Escape($_) + $help.Output | Should -Match $escaped + $readme | Should -Match $escaped + $docs | Should -Match $escaped + } + } + + It 'errors for each missing required recipe flag' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $cases = @( + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --dry-run" + Match = 'subscription' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 --dry-run" + Match = 'resource-group' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x --dry-run" + Match = 'name' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x -n a --dry-run" + Match = 'location' + } + ) + + foreach ($case in $cases) { + $result = Invoke-BashCommand $case.Command + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match $case.Match + } + } + + It 'errors on unknown flags' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipes '$script:RecipeDir' --dry-run" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown flag' + } + + It 'errors when a value-taking flag is missing its value' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' -g -n foo --dry-run" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'requires a value' + } + + It 'errors when verify-agent expected config is missing its value' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --expected" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'flag --expected requires a value' + $result.Output | Should -Not -Match 'unbound variable' + } + + It 'rejects unknown verify-agent arguments before Azure calls' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --bogus" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match "unknown argument '--bogus'" + $result.Output | Should -Not -Match 'Could not resolve agent endpoint' + } + + It 'rejects the positional footgun' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --dry-run rg-test" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown argument' + } + + It 'shows customer values and not maintainer defaults on happy-path dry-run' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'rg-test-customer' + $result.Output | Should -Match 'customer-sre-agent' + $result.Output | Should -Match 'westus3' + $result.Output | Should -Not -Match 'rg-finops-sre-agent|finops-sre-agent|eastus2' + } + + It 'uses a deterministic default deployment name across dry-runs' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-deploy-name-" + [guid]::NewGuid().ToString('N')) + try { + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" + $first = Invoke-BashCommand $command + $second = Invoke-BashCommand $command + + $first.ExitCode | Should -Be 0 + $second.ExitCode | Should -Be 0 + $firstPath = [regex]::Match($first.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() + $secondPath = [regex]::Match($second.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() + + $firstPath | Should -Be $secondPath + $firstPath | Should -Match 'sre-agent-customer-sre-agent-[a-f0-9]{12}' + + $parameters = Get-Content -Path $firstPath -Raw | ConvertFrom-Json + $parameters.parameters.upgradeChannel.value | Should -Be 'Preview' + $parameters.parameters.experimentalSettings.value.EnableSandboxGroup | Should -BeTrue + $parameters.parameters.experimentalSettings.value.EnableWorkspaceTools | Should -BeTrue + $parameters.parameters.monthlyAgentUnitLimit.value | Should -Be 10000 + } + finally { + Remove-Item -Path $deployRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'requires cluster resource ID for dry-run when a Kusto URI is provided' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --dry-run" + + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match '--cluster-resource-id is required with --cluster-uri for --dry-run' + } + + It 'auto-resolves the Kusto cluster resource ID before deployment' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-resolve-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $deployRoot = Join-Path $tempRoot 'deploy' + New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +if [[ "$*" == *"resource list"* ]]; then + exit 0 +fi + +if [[ "$*" == *"graph query"* ]]; then + cat <<'JSON' +{ + "data": [ + { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example" + } + ] +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub show"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub create"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"provider register"*|*"version"*) + exit 0 + ;; +esac + +exit 0 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then + cat > "$out" <<'JSON' +{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then + [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" + cat > "$out" <<'JSON' +{ + "type": "ExtendedAgent", + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +cat > "$out" <<'JSON' +{ + "files": [ + { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, + { "name": "document-index-md", "isIndexed": true, "errorReason": null }, + { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, + { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, + { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, + { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } + ], + "continuationToken": "" +} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://example.westus3.kusto.windows.net/Hub" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Resolving Kusto cluster resource ID from --cluster-uri' + $result.Output | Should -Match '/providers/Microsoft\.Kusto/clusters/example' + + $parametersFile = (Get-ChildItem -Path $deployRoot -Recurse -Filter 'deploy.parameters.json' | Select-Object -First 1).FullName + $parametersFile | Should -Not -BeNullOrEmpty + $parameters = Get-Content -Path $parametersFile -Raw | ConvertFrom-Json + $parameters.parameters.finopsHubKustoClusterResourceId.value | Should -Be '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example' + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'warns but continues when the Kusto cluster denies public query access' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-private-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $deployRoot = Join-Path $tempRoot 'deploy' + New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +if [[ "$*" == *"resource show"* ]]; then + cat <<'JSON' +{ + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx", + "properties": { + "uri": "https://privateadx.westus.kusto.windows.net", + "publicNetworkAccess": "Disabled", + "privateEndpointConnections": [ + { + "name": "privateadx-ep", + "properties": { + "privateLinkServiceConnectionState": { + "status": "Approved" + } + } + } + ] + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub show"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub create"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"provider register"*|*"version"*) + exit 0 + ;; +esac + +exit 0 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then + cat > "$out" <<'JSON' +{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* || "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +cat > "$out" <<'JSON' +{} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $clusterId = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx' + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://privateadx.westus.kusto.windows.net/Hub --cluster-resource-id $clusterId" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Warning: The Kusto cluster denies public query access' + $result.Output | Should -Match 'private endpoint ADX blocks direct KQL queries' + $result.Output | Should -Match 'https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations' + $result.Output | Should -Match 'SRE Agent ready' + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'routes deploy through the copied starter-lab infra and apply-extras path' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployContent = Get-Content -Path $script:DeployScript -Raw + $deployContent | Should -Match 'INFRA_DIR=.*infra' + $deployContent | Should -Match '\$\{INFRA_DIR\}/main\.bicep' + $deployContent | Should -Match 'apply-extras\.sh' + $deployContent | Should -Not -Match 'bicep/assemble-agent|hydrate-extensions' + + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') | Should -BeTrue + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh') | Should -BeTrue + } + } + + Context 'repo invariants' { + It 'removes shipped recipe identity defaults' { + $agentJson = Get-Content -Path $script:AgentJsonPath -Raw + $agentJson | Should -Not -Match '"identity"' + } + + It 'uses the current SRE Agent API, model provider, and sandbox configuration' { + $agentJson = Get-Content -Path $script:AgentJsonPath -Raw | ConvertFrom-Json + $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $sreAgentBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/modules/sre-agent.bicep') -Raw + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $agentJson.upgradeChannel | Should -Be 'Preview' + $agentJson.defaultModelProvider | Should -Be 'MicrosoftFoundry' + $agentJson.defaultModelName | Should -Be 'Automatic' + $agentJson.experimentalSettings.EnableSandboxGroup | Should -BeTrue + $agentJson.experimentalSettings.EnableWorkspaceTools | Should -BeTrue + $sreAgentBicep | Should -Match 'Microsoft\.App/agents@2026-01-01' + $sreAgentBicep | Should -Not -Match 'Microsoft\.App/agents@2025-05-01-preview' + $sreAgentBicep | Should -Match 'defaultModel:' + $sreAgentBicep | Should -Match 'provider: defaultModelProvider' + $sreAgentBicep | Should -Match 'name: defaultModelName' + $sreAgentBicep | Should -Match 'upgradeChannel: upgradeChannel' + $mainBicep | Should -Match 'defaultModelProvider' + $mainBicep | Should -Match 'defaultModelName' + $mainBicep | Should -Match 'EnableSandboxGroup' + $mainBicep | Should -Match 'EnableWorkspaceTools' + $verifyScript | Should -Match 'API_VERSION="2026-01-01"' + } + + It 'limits legacy config env-var references to the allowlist' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" + $result.ExitCode | Should -Be 0 + + $paths = $result.Output -split "`n" | + Where-Object { $_ } | + ForEach-Object { ($_ -split ':', 2)[0] } | + Sort-Object -Unique + + $paths | Should -Be @( + 'docs-mslearn/toolkit/sre-agent/deploy.md', + 'src/templates/sre-agent/bin/build-extras.py', + 'src/templates/sre-agent/README.md', + 'src/templates/sre-agent/recipes/finops-hub/connectors.json' + ) + } + + It 'keeps connectors.secrets.env out of scripts' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'connectors\.secrets\.env' -- src/templates/sre-agent/bin src/templates/sre-agent/infra" + $result.ExitCode | Should -Be 1 + } + + It 'removes the legacy custom bicep deployment surface' { + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bicep') | Should -BeFalse + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/hydrate-extensions.sh') | Should -BeFalse + } + + It 'uses deterministic subscription and resource group identity for support resource names' { + $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $resourcesBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/resources.bicep') -Raw + + $mainBicep | Should -Match "agentResourceGroupId = subscriptionResourceId\('Microsoft\.Resources/resourceGroups', resourceGroupName\)" + $mainBicep | Should -Match 'namingSeed = toLower' + $mainBicep | Should -Match 'subscription\(\)\.subscriptionId' + $mainBicep | Should -Match 'agentResourceGroupId' + $mainBicep | Should -Match 'agentName' + + $resourcesBicep | Should -Match 'param namingSeed string' + $resourcesBicep | Should -Match 'uniqueSuffix = uniqueString\(namingSeed\)' + $resourcesBicep | Should -Not -Match 'resourceGroup\(\)\.id|deployment\(\)\.name' + } + + It 'applies subagents after their local handoff targets' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-post-provision-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $buildDir = Join-Path $tempRoot 'build' + $logPath = Join-Path $tempRoot 'agent-apply.log' + New-Item -ItemType Directory -Force -Path $binDir, $buildDir | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"version"*) + exit 0 + ;; +esac + +exit 1 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "type": "KnowledgeItem", + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then + [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" + cat > "$out" <<'JSON' +{ + "type": "ExtendedAgent", + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +cat > "$out" <<'JSON' +{ + "files": [ + { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, + { "name": "document-index-md", "isIndexed": true, "errorReason": null }, + { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, + { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, + { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, + { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } + ], + "continuationToken": "" +} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $command = "AGENT_APPLY_LOG='$logPath' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:PostProvisionScript' --endpoint https://example.azuresre.ai --subscription 00000000-0000-0000-0000-000000000000 --resource-group rg-test-customer --name customer-sre-agent --recipe '$script:RecipeDir' --build-dir '$buildDir'" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + + $order = @(Get-Content -Path $logPath) + [array]::IndexOf($order, 'chief-financial-officer') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + [array]::IndexOf($order, 'ftk-database-query') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + [array]::IndexOf($order, 'ftk-hubs-agent') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'derives expected recipe connectors for verification' { + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $verifyScript | Should -Match 'connectors\.json' + $verifyScript | Should -Match 'EXPECTED_CONNECTORS' + $verifyScript | Should -Match 'EXP_CONN_CT=.*EXPECTED_CONNECTORS' + $verifyScript | Should -Match 'EXP_CONN_NAMES=.*EXPECTED_CONNECTORS' + } + + It 'uploads the shared FinOps output style as a portal knowledge source' { + $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw + $buildExtrasScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/build-extras.py') -Raw + + Test-Path $script:OutputStylePath | Should -BeTrue + $buildExtrasScript | Should -Match 'claude-plugin/output-styles/ftk-output-style\.md' + $buildExtrasScript | Should -Match 'Output style knowledge document not found' + $applyExtrasScript | Should -Match 'knowledgeItems' + $applyExtrasScript | Should -Match '/api/v2/extendedAgent/connectors' + $applyExtrasScript | Should -Match 'Knowledge sources failed to index' + $applyExtrasScript | Should -Match 'KnowledgeFile' + $applyExtrasScript | Should -Not -Match ('sr' + 'ectl') + $applyExtrasScript | Should -Not -Match '/api/v1/agentmemory/files' + } + + It 'requires expected knowledge sources and verifies indexing' { + $expectedConfig = Get-Content -Path (Join-Path $script:RecipeDir 'expected-config.json') -Raw | ConvertFrom-Json + $verifyScript = Get-Content -Path $script:VerifyScript -Raw + + $expectedConfig.knowledgeSources.Count | Should -Be 6 + $expectedConfig.knowledgeSources | Should -Contain 'ftk-output-style.md' + $expectedConfig.PSObject.Properties.Name | Should -Not -Contain 'knowledgeDocs' + $verifyScript | Should -Match '/api/v2/extendedAgent/connectors' + $verifyScript | Should -Match '\$expected\[\] \| \. as \$name \| select\(\$actual \| index\(\$name\)\)' + $verifyScript | Should -Match 'Knowledge sources expected' + $verifyScript | Should -Match 'Knowledge sources indexed' + $verifyScript | Should -Match 'Unindexed knowledge sources' + $verifyScript | Should -Not -Match '/api/v1/agentmemory' + $verifyScript | Should -Not -Match '"knowledge_" \+' + $verifyScript | Should -Not -Match 'Knowledge connector rows' + } + + It 'does not duplicate response plan verification with dead incident-filter scan state' { + $verifyScript = Get-Content -Path $script:VerifyScript -Raw + + ([regex]::Matches($verifyScript, 'check "Filter names"')).Count | Should -Be 1 + $verifyScript | Should -Not -Match 'EXP_FILTERS' + $verifyScript | Should -Not -Match 'automations/incident-filters' + } + + It 'requires every scheduled task to apply the shared output style' { + $taskFiles = @(Get-ChildItem -Path $script:ScheduledTaskDir -Filter '*.yaml') + $taskFiles.Count | Should -Be 19 + + $expectedInstruction = [regex]::Escape('Output style: Apply `ftk-output-style.md`') + foreach ($file in $taskFiles) { + $content = Get-Content -Path $file.FullName -Raw + $content | Should -Match $expectedInstruction + } + } + + It 'deletes existing scheduled tasks before applying manifests' { + $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $applyExtrasScript | Should -Match 'delete_existing_scheduled_tasks' + $applyExtrasScript | Should -Match '/api/v1/scheduledtasks' + $applyExtrasScript | Should -Match 'dataplane_put_extended "scheduledtasks"' + $verifyScript | Should -Match 'Scheduled task duplicates' + $verifyScript | Should -Match '0 duplicates' + } + + It 'extends the shared output style for Azure capacity management' { + $outputStyle = Get-Content -Path $script:OutputStylePath -Raw + + $outputStyle | Should -Match 'Azure capacity management reporting' + $outputStyle | Should -Match 'Forecast' + $outputStyle | Should -Match 'Procure' + $outputStyle | Should -Match 'Allocate' + $outputStyle | Should -Match 'Monitor' + $outputStyle | Should -Match 'Capacity reservation group' + $outputStyle | Should -Match 'Quota group' + $outputStyle | Should -Match 'Logical zone' + $outputStyle | Should -Match 'CRG utilization' + } + } + + Context 'copy-and-update deployment contract' { + It 'rejects what-if because the copied starter-lab flow deploys directly' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test -n test-agent -l westus3 --what-if" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown flag' + } + + It 'documents that azd is not used' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nF 'azd' -- src/templates/sre-agent/bin src/templates/sre-agent/infra docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent/README.md" + $result.Output | Should -Match 'azd' + $result.Output | Should -Match 'not used|doesn''t use' + } + } +} diff --git a/src/templates/sre-agent/.gitattributes b/src/templates/sre-agent/.gitattributes new file mode 100644 index 000000000..dfdb8b771 --- /dev/null +++ b/src/templates/sre-agent/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf diff --git a/src/templates/sre-agent/.gitignore b/src/templates/sre-agent/.gitignore new file mode 100644 index 000000000..c60cffcaa --- /dev/null +++ b/src/templates/sre-agent/.gitignore @@ -0,0 +1,3 @@ + +.gate/ +!bin/ diff --git a/src/templates/sre-agent/.upstream-pin b/src/templates/sre-agent/.upstream-pin new file mode 100644 index 000000000..e3b8a9b46 --- /dev/null +++ b/src/templates/sre-agent/.upstream-pin @@ -0,0 +1,5 @@ +upstream_repo=https://github.com/microsoft/sre-agent +upstream_path=labs/starter-lab/ +pinned_sha=a401e003a3874c374f5fff5278123a1f603fe270 +pinned_date=2026-05-25 +pinned_version=1.0.0 diff --git a/src/templates/sre-agent/AGENTS.md b/src/templates/sre-agent/AGENTS.md new file mode 100644 index 000000000..1bdb1778e --- /dev/null +++ b/src/templates/sre-agent/AGENTS.md @@ -0,0 +1,31 @@ +# Agent instructions + +**⛔ PROHIBITED: Manual Azure resource intervention.** Do not run Azure control-plane or data-plane commands against live SRE Agent resources outside the canonical entry point `bin/deploy.sh` and its owned helper scripts in `infra/`, `bin/apply-extras.sh`, and the deprecated compatibility wrapper `bin/post-provision.sh`. All Azure changes go through the release process. No exceptions. + +Load the `azure-sre-agent` skill at session start and after every compaction or summarization. + +## Template inventory + +| Component | Count | Details | +|-----------|-------|---------| +| Custom agents | 5 | `finops-practitioner` orchestrator plus four delegated subagents: `azure-capacity-manager`, `chief-financial-officer`, `ftk-database-query`, `ftk-hubs-agent` | +| Tool-bearing delegated subagents | 3 | `azure-capacity-manager`, `ftk-database-query`, `ftk-hubs-agent`; `finops-practitioner` and `chief-financial-officer` have no tools | +| Skills | 3 | `azure-capacity-management`, `azure-cost-management`, `finops-toolkit` | +| Tools | 50 | 37 generated Kusto tools from `src/queries/catalog/` plus 13 Python tools under `recipes/finops-hub/config/tools/` | +| Scheduled tasks | 19 | All owned by `finops-practitioner`; specialist agents are delegated by prompt, not scheduled directly | +| Connectors | 1 | Kusto connector to FinOps Hub ADX cluster | +| Knowledge docs | 6 | Five recipe knowledge files plus `ftk-output-style.md` from the Claude plugin output styles | + +## Key references + +- [README.md](README.md) — Deployment guide and architecture +- [CATALOG.md](CATALOG.md) — Authoritative FinOps Framework alignment, inventory, tool ownership, and scheduled-task catalog +- `bin/deploy.sh` — Canonical deployment entry point copied from the Microsoft starter-lab setup flow and updated for no-azd FinOps deployment +- `infra/` — Copied-and-updated Microsoft starter-lab Bicep baseline +- `recipes/finops-hub/` — Recipe content +- `../claude-plugin/output-styles/ftk-output-style.md` — Uploaded as SRE Agent knowledge and referenced by every scheduled task for report formatting +- `.upstream-pin` — Upstream canonical template pin + +## Scheduled task Teams delivery + +Scheduled-task entrypoint agents that deliver results must have explicit access to the Teams connector tools: `PostTeamsMessage`, `ReplyToTeamsMessage`, and `GetTeamsMessages`. When a Teams connector/channel is configured, results must be delivered through that configured Teams channel. diff --git a/src/templates/sre-agent/CATALOG.md b/src/templates/sre-agent/CATALOG.md new file mode 100644 index 000000000..ee224e796 --- /dev/null +++ b/src/templates/sre-agent/CATALOG.md @@ -0,0 +1,256 @@ +# FinOps toolkit SRE Agent - framework alignment catalog + +This catalog is the controlling reference for aligning the `recipes/finops-hub/` SRE Agent template to the FinOps Framework. Azure capacity-management content is included as implementation guidance under the relevant FinOps capabilities, not as a separate operating model. Framework names were checked against the FinOps Foundation references below on 2026-05-26. Keep the recipe content aligned to this file: + +- Agent defaults: `recipes/finops-hub/agent.json` +- Expected inventory: `recipes/finops-hub/expected-config.json` +- Custom agents: `recipes/finops-hub/config/subagents/*.yaml` +- Skills: `recipes/finops-hub/config/skills/*/` +- Tools: generated Kusto tools from `src/queries/catalog/*.kql` plus Python tools from `recipes/finops-hub/config/tools/*.yaml` +- Scheduled tasks: `recipes/finops-hub/automations/scheduled-tasks/*.yaml` +- Output style knowledge: `../claude-plugin/output-styles/ftk-output-style.md` + +## Implemented inventory + +| Component | Count | Source | +|-----------|------:|--------| +| Custom agents | 5 | Practitioner orchestrator plus four delegated subagents in `config/subagents/*.yaml` | +| Skills | 3 | `config/skills/*/` | +| Tools | 50 | 37 generated Kusto tools from `src/queries/catalog/*.kql` plus 13 Python tools from `config/tools/*.yaml` | +| Tool overrides | 9 | `config/built-in-tools.json` | +| Scheduled tasks | 19 | All set `spec.agent: finops-practitioner` in `automations/scheduled-tasks/*.yaml` | +| Connectors | 1 | `connectors.json`: FinOps Hub Kusto | +| Knowledge docs | 6 | Five recipe knowledge files plus `../claude-plugin/output-styles/ftk-output-style.md` | + +Tool mix: + +| Tool type | Count | +|-----------|------:| +| KustoTool | 37 | +| PythonTool | 13 | +| MCP tool namespaces | 0 | + +## Framework anchors + +The recipe maps to these external operating models: + +- FinOps Framework domains: Understand Usage & Cost, Quantify Business Value, Optimize Usage & Cost, and Manage the FinOps Practice. +- FinOps Framework capabilities: Data Ingestion, Allocation, Reporting & Analytics, Anomaly Management, Planning & Estimating, Forecasting, Budgeting, KPIs & Benchmarking, Unit Economics, Architecting & Workload Placement, Rate Optimization, Usage Optimization, Sustainability, Licensing & SaaS, FinOps Practice Operations, Governance, Policy & Risk, FinOps Assessment, Automation, Tools, & Services, FinOps Education & Enablement, Invoicing & Chargeback, and Intersecting Disciplines. +- Capabilities directly automated by this recipe: Data Ingestion, Allocation, Reporting & Analytics, Anomaly Management, Planning & Estimating, Forecasting, Budgeting, KPIs & Benchmarking, Unit Economics, Architecting & Workload Placement, Usage Optimization, Rate Optimization, FinOps Practice Operations, Governance, Policy & Risk, Automation, Tools, & Services, and Invoicing & Chargeback. +- Capabilities present as guidance or consultative context only: Sustainability, Licensing & SaaS, FinOps Assessment, FinOps Education & Enablement, and Intersecting Disciplines. The recipe does not ship scheduled tasks or specialist tools that directly implement these capabilities. +- Executive strategy alignment is treated as a leadership reporting outcome, not as a FinOps Framework capability. +- FinOps Framework principles: Teams need to collaborate, Business value drives technology decisions, Everyone takes ownership for their technology usage, FinOps data should be accessible, timely, and accurate, FinOps should be enabled centrally, and Take advantage of the variable cost model of the cloud. +- FinOps Framework personas: FinOps Practitioner coordinates the practice; Engineering owns technical usage and implementation; Finance and Leadership provide planning, decision rights, and business context; Product and Procurement contribute demand, value, and commitment context. +- FinOps Framework phases: Inform, Optimize, and Operate are iterative lenses applied to capabilities. They are not a replacement taxonomy and not a serial deployment order. +- Azure capacity management: capacity tooling is mapped into Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization, Governance, Policy & Risk, and Automation, Tools, & Services. Capacity reservations guarantee supply; reservations and savings plans reduce rate. These are coordinated but not interchangeable. + +Primary references: + +- FinOps Framework domains: +- FinOps Framework capabilities: +- FinOps Framework principles: +- FinOps Framework personas: +- FinOps Framework phases: +- Azure SRE Agent workflow automation: +- Azure SRE Agent scheduled tasks: +- Azure SRE Agent custom agents: +- Azure SRE Agent connectors: +- Microsoft SRE Agent repository and templates: +- Azure capacity governance for ISVs: + +## Agent operating model + +Azure SRE Agent automation is modeled as connector-provided tools, custom agents with scoped tool access, and scheduled tasks that trigger the selected custom agent. Knowledge files are reference material; they do not grant tools. This recipe follows that model by assigning custom tools to the specialist that owns the capability, then routing every scheduled task to `finops-practitioner` so the practitioner owns the operating rhythm and delegates evidence collection. + +The recipe defaults the parent Azure SRE Agent to the Azure OpenAI provider (`MicrosoftFoundry` in ARM) with `Automatic` model routing. SRE Agent selects the model within the provider for each task. Custom agents in this recipe do not declare their own model providers or pinned model names because the documented SRE Agent configuration surface is provider-level on the parent agent. + +All tool-bearing specialist agents include `SearchMemory` so they can read uploaded Knowledge Sources, including `ftk-output-style.md`, known issues, and prior operational notes. Specialist ownership still controls action scope: Kusto, capacity, and hubs responsibilities remain separated. The practitioner has no direct tools and delegates all evidence, visualization, delivery, and remediation work. `chief-financial-officer` has no tools and receives packaged evidence through practitioner handoff. + +Scheduled reports must classify gaps before recommending action: product or deployment defects, data sufficiency limits, or customer-owned delegation. Sparse UAT Hub history, empty transaction diagnostics, or missing multi-period trigger evidence reduce confidence and should not be reported as product failure by themselves. The deployment owns Reader access for the deployment subscription by default. Broader management group, billing, quota, or cross-subscription access is customer-owned delegation unless this template explicitly owns that role assignment. + +| Custom agent | Role in the operating model | Direct tool policy | FinOps / capacity alignment | +|----------|-----------------------------|--------------------|----------------------------| +| `finops-practitioner` | Practice lead and scheduled-report orchestrator. Owns the FinOps operating rhythm, applies the output style, frames business questions, routes evidence requests, and turns specialist outputs into actions. | No direct tools. Delegates Kusto evidence to `ftk-database-query`, capacity evidence to `azure-capacity-manager`, Hub platform and infrastructure checks to `ftk-hubs-agent`, and executive decision framing to `chief-financial-officer`. | FinOps Practitioner persona; central enablement; collaboration; Reporting & Analytics, Governance, Policy & Risk, Usage Optimization, Rate Optimization, and leadership strategy alignment. | +| `ftk-database-query` | FinOps Hub evidence specialist. Owns all Kusto/FOCUS query execution, Kusto result interpretation, schema guidance, and query diagnostics. | Owns every generated `KustoTool` from `src/queries/catalog/*.kql`. Does not own Azure CLI, Python capacity, infrastructure health, or remediation tools. No scheduled-task ownership. | Understand Usage & Cost; Data Ingestion, Allocation, Reporting & Analytics, Anomaly Management, pricing, recommendation, KPI, unit economics, and commitment evidence. | +| `azure-capacity-manager` | Engineering and platform capacity specialist. Owns quota, region, zone, SKU, CRG, non-compute quota, database quota, AKS readiness, and capacity-to-rate coordination. | Owns capacity Python tools only. Does not own Kusto, Resource Graph, Hub freshness, Azure CLI, or remediation deployment tools. | Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Governance, Policy & Risk, and Automation, Tools, & Services. | +| `chief-financial-officer` | Consultative finance and leadership persona. Frames budget, forecast, commitment, risk, and investment tradeoffs for executive audiences. | Should not own scheduled tasks or raw data collection. Consumes evidence packages from `finops-practitioner` and specialists. | Finance and Leadership personas; Quantify Business Value; leadership strategy alignment; Budgeting, Forecasting, Unit Economics, investment decisions. | +| `ftk-hubs-agent` | FinOps Hub platform specialist. Owns hub health, deployment, upgrade, connector, export freshness, monitoring scope, and analytics-backend readiness. | Owns platform discovery, Resource Graph inventory, `data-freshness-check`, ADX SKU preflight, hub troubleshooting tools, and explicit remediation deployment tools. Does not own business cost-analysis reports. | Data Ingestion and Reporting & Analytics foundation; Automation, Tools, & Services; Governance, Policy & Risk. | + +Hard boundaries: + +- `finops-practitioner` must never query Kusto directly. Any prompt that needs `Costs()`, `Prices()`, `Recommendations()`, `Transactions()`, or a Kusto tool must delegate that evidence request to `ftk-database-query`. +- `finops-practitioner` has no direct tools. It must use handoffs for Kusto, capacity Python, Resource Graph, Hub infrastructure checks, visualization, delivery, and remediation. +- Every scheduled task must set `spec.agent: finops-practitioner`. Specialist agents are delegated subagents, not scheduled-task entrypoints. +- `chief-financial-officer` must not run autonomous scheduled tasks. Finance is a consulted persona for decisions and executive packaging, not the worker that gathers evidence. +- Capacity tasks must keep pricing commitments and capacity guarantees distinct. Use `azure-capacity-manager` for quota/CRG/access/SKU evidence and `ftk-database-query` for Kusto-backed rate and cost evidence. +- Remediation tools such as budget deployment, anomaly alert deployment, and Advisor suppression are interactive or explicitly approved remediation actions. Scheduled audits may recommend them but must not silently execute them. + +## Source lineage + +The SRE Agent recipe is an orchestration layer over the toolkit and azcapman assets, not a separate FinOps model. + +| Source | Role in this recipe | +|--------|---------------------| +| `src/templates/claude-plugin/agents/*.md` and `src/templates/copilot-plugin/agents/*.agent.md` | Canonical toolkit agent personas for FinOps practitioner, FinOps Hub database, CFO, capacity, and hubs specialists. | +| `src/templates/agent-skills/finops-toolkit/` | Canonical FinOps Toolkit skill content and query catalog guidance used by the SRE recipe. | +| `src/templates/agent-skills/azure-cost-management/` | Canonical Azure Cost Management skill content for Advisor, budgets, anomaly alerts, savings plans, reservations, and related cost workflows. | +| `src/templates/sre-agent/submodules/azcapman/agents/azure-capacity-manager.md` | Canonical azcapman capacity specialist persona. | +| `src/templates/sre-agent/submodules/azcapman/skills/azure-capacity-management/` | Canonical azcapman capacity skill and references. The recipe uses symlinks; do not duplicate this content. | +| `src/queries/` | Canonical FinOps Hub Kusto query catalog. All custom Kusto tools are generated from this catalog; explicit recipe YAML Kusto definitions are rejected so `src/queries/catalog/*.kql` remains the single Kusto source. | +| `src/templates/claude-plugin/output-styles/ftk-output-style.md` | Shared FinOps Toolkit report style uploaded as SRE Agent knowledge and referenced by every scheduled task. | + +## Custom agent capability matrix + +This matrix is the reference for which custom agent owns each FinOps capability surface, which tools it can call directly, and which scheduled tasks it owns. It is derived from `src/templates/claude-plugin/agents/*.md`, `src/templates/copilot-plugin/agents/*.agent.md`, `src/templates/agent-skills/`, `src/templates/sre-agent/recipes/finops-hub/config/subagents/*.yaml`, `src/templates/sre-agent/submodules/azcapman/agents/azure-capacity-manager.md`, `src/templates/sre-agent/submodules/azcapman/skills/azure-capacity-management/SKILL.md`, and `src/queries/`. + +| Custom agent | Persona / function | FinOps capabilities owned or directly implemented | Direct custom tools | Scheduled tasks owned | Required handoffs and consults | +|----------|--------------------|----------------------------------------------------|---------------------|---------------------|-------------------------------| +| `finops-practitioner` | FinOps Practitioner and operating-rhythm orchestrator. Leads practice cadence, report assembly, output style, and remediation approval flow. | Allocation, Reporting & Analytics orchestration, Anomaly Management orchestration, Budgeting, KPIs & Benchmarking, Unit Economics, Usage Optimization orchestration, Rate Optimization orchestration, FinOps Practice Operations, Governance, Policy & Risk, Automation, Tools, & Services, and Invoicing & Chargeback orchestration. | None. | All 19 scheduled tasks. | Must delegate all Kusto/FOCUS evidence to `ftk-database-query`; capacity, quota, SKU, zone, region, and CRG evidence to `azure-capacity-manager`; executive finance framing to `chief-financial-officer`; FinOps Hub platform readiness, Resource Graph, visualization, delivery, and infrastructure/remediation tooling to `ftk-hubs-agent`. | +| `ftk-database-query` | FinOps Hub evidence specialist. Owns Kusto, FOCUS, `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()` evidence packages. | Data Ingestion evidence, Allocation evidence, Reporting & Analytics evidence, Anomaly Management evidence, Forecasting evidence, KPIs & Benchmarking evidence, Unit Economics evidence, Rate Optimization evidence, Usage Optimization evidence, Invoicing & Chargeback evidence. | All 37 generated FinOps Hub `KustoTool` definitions listed in the Tool inventory from `src/queries/catalog/*.kql`. | None. This specialist is invoked by other scheduled tasks for evidence collection. | Returns evidence packages to `finops-practitioner`; does not own business recommendations, infrastructure checks, capacity evidence, or remediation decisions. | +| `azure-capacity-manager` | Engineering and platform capacity specialist sourced from the toolkit and azcapman. Owns Azure capacity, quota, SKU, region, zone, CRG, AKS, and non-compute limit evidence. | Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Governance, Policy & Risk, Automation, Tools, & Services. | `benefit-recommendations`, `sku-availability`, `vm-quota-usage`, `non-compute-quotas`, `db-service-quotas`, `capacity-reservation-groups`. | None. Invoked by `finops-practitioner` scheduled tasks for capacity evidence. | Returns capacity evidence to `finops-practitioner`. It does not query Kusto, run Resource Graph, check Hub freshness, or hand off to other agents. | +| `chief-financial-officer` | Finance and Leadership consultative persona. Frames budget, forecast, capital allocation, commitment risk, and executive tradeoffs. | Budgeting, Forecasting, KPIs & Benchmarking, Unit Economics, Rate Optimization decision framing, Invoicing & Chargeback framing, and leadership strategy alignment. | None. | None. Finance is consulted; it does not run autonomous scheduled tasks. | Consumes packaged evidence from `finops-practitioner`, `ftk-database-query`, `azure-capacity-manager`, and `ftk-hubs-agent`. Must not query Kusto, collect raw telemetry, investigate capacity directly, or deliver reports. | +| `ftk-hubs-agent` | FinOps Hub platform specialist. Owns hub deployment, upgrade, health, connector, export, monitoring scope, analytics-backend readiness, Resource Graph inventory, and explicit remediation deployment tooling. | Data Ingestion platform readiness, Reporting & Analytics platform readiness, Automation, Tools, & Services, Governance, Policy & Risk. | `data-freshness-check`, `resource-graph-query`, `sku-availability`, `deploy-anomaly-alert`, `deploy-budget`, `deploy-bulk-anomaly-alerts`, `deploy-bulk-budgets`, `suppress-advisor-recommendations`. | None. Invoked by `finops-practitioner` scheduled tasks for Hub platform and infrastructure evidence. | Returns infrastructure evidence to `finops-practitioner`. It does not own business cost analysis, capacity evidence, or executive framing. | + +## Capability coverage matrix + +The phase column is a primary operating lens, not a workflow gate. Scheduled tasks can produce Inform evidence, Optimize recommendations, and Operate actions in a single run when that matches the task intent. + +| FinOps capability | Domain | Primary phase lens | Recipe owner | Scheduled tasks | Primary tool families | +|-------------------|--------|--------------------|--------------|-----------------|-----------------------| +| Data Ingestion | Understand Usage & Cost | Inform | `ftk-hubs-agent`, `ftk-database-query` | `HubsHealthCheck`, `MonitoringScopeValidation`; evidence support for `Monthly` and `Semiannual` | `data-freshness-check`, `cost-visibility-delay`, `data-update-frequency`, FinOps Hub Kusto tools, Hub platform checks | +| Allocation | Understand Usage & Cost | Inform | `finops-practitioner`, `ftk-database-query` | `Monthly`, `Semiannual`, `AIWorkloadCostAnalysis` | `cost-by-financial-hierarchy`, `ai-cost-by-application`, `allocation-accuracy-index`, `percentage-unallocated-costs`, `percentage-untagged-costs`, `tagging-policy-compliance`, resource inventory evidence | +| Reporting & Analytics | Understand Usage & Cost | Inform | `finops-practitioner`, `ftk-database-query` | `Monthly`, `Semiannual`, `CostOptimization`, `AIWorkloadCostAnalysis` | Cost trend, top-N, savings, pricing, AI, FinOps Hub Kusto evidence, visualization, and notification tools | +| Anomaly Management | Understand Usage & Cost | Inform / Operate | `finops-practitioner`, `ftk-database-query` | `AlertCoverageAudit`, `CostOptimization`, `Monthly`, `Semiannual` | `cost-anomaly-detection`, `anomaly-detection-rate`, `anomaly-variance-total`, `deploy-anomaly-alert`, `deploy-bulk-anomaly-alerts`, `resource-graph-query` | +| Planning & Estimating | Quantify Business Value | Inform | `azure-capacity-manager`, `finops-practitioner` | `CapacityMonthlyPlanning`, `CapacityQuarterlyStrategy`, `StoragePaasGrowthForecast`, `Semiannual` | `vm-quota-usage`, `non-compute-quotas`, `capacity-reservation-groups`, `cost-forecasting-model` | +| Forecasting | Quantify Business Value | Inform | `azure-capacity-manager`, `ftk-database-query`, `finops-practitioner` | `CapacityMonthlyPlanning`, `StoragePaasGrowthForecast`, `Monthly`, `Semiannual` | `cost-forecasting-model`, `monthly-cost-trend`, quota and capacity trend tools | +| Budgeting | Quantify Business Value | Inform / Operate | `finops-practitioner`, `chief-financial-officer` | `BudgetCoverageAudit`, `Monthly`, `Semiannual` | `deploy-budget`, `deploy-bulk-budgets`, `monthly-cost-trend`, `cost-forecasting-model` | +| KPIs & Benchmarking | Quantify Business Value | Inform | `finops-practitioner`, `ftk-database-query`, `chief-financial-officer` | `Monthly`, `Semiannual`, `AIWorkloadCostAnalysis` | `service-price-benchmarking`, `savings-summary-report`, FinOps KPI Kusto tools, AI model comparison, visualization tools | +| Unit Economics | Quantify Business Value | Inform | `finops-practitioner`, `ftk-database-query`, `chief-financial-officer` | `AIWorkloadCostAnalysis`, `Monthly`, `Semiannual` | AI token and model cost tools, `compute-cost-per-core`, `cost-per-gb-stored`, `cost-by-financial-hierarchy`, `service-price-benchmarking` | +| Architecting & Workload Placement | Optimize Usage & Cost | Optimize | `azure-capacity-manager`, `finops-practitioner` | `CapacityWeeklySupplyReview`, `SkuAvailabilityAudit`, `ComputeUtilizationTrend`, `CapacityQuarterlyStrategy` | `sku-availability`, `resource-graph-query`, `vm-quota-usage`, `capacity-reservation-groups` | +| Rate Optimization | Optimize Usage & Cost | Optimize | `finops-practitioner`, `ftk-database-query`, `azure-capacity-manager`, `chief-financial-officer` | `BenefitRecommendationReview`, `CapacityMonthlyPlanning`, `CapacityQuarterlyStrategy`, `Monthly`, `Semiannual` | `benefit-recommendations`, `commitment-discount-utilization`, `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, `cost-optimization-index`, `macc-consumption-vs-commitment`, `reservation-recommendation-breakdown`, `savings-summary-report`, `service-price-benchmarking` | +| Usage Optimization | Optimize Usage & Cost | Optimize | `finops-practitioner`, `azure-capacity-manager`, `ftk-database-query` | `CostOptimization`, `ComputeUtilizationTrend`, `CapacityDailyMonitor`, `CapacityWeeklySupplyReview` | `top-services-by-cost`, `top-resource-types-by-cost`, `compute-cost-per-core`, `cost-per-gb-stored`, `storage-tier-distribution`, `resource-graph-query`, quota and CRG tools | +| Sustainability | Optimize Usage & Cost | Optimize | Guidance only through `finops-practitioner` | None | No direct recipe tool. Consider only when optimization decisions materially affect sustainability goals. | +| Licensing & SaaS | Optimize Usage & Cost | Optimize | Guidance only through `finops-practitioner` and `chief-financial-officer` | None | No direct recipe tool. Azure Hybrid Benefit evidence can appear in FinOps Hub cost data, but this recipe does not ship a Licensing & SaaS workflow. | +| FinOps Practice Operations | Manage the FinOps Practice | Operate | `finops-practitioner` | `Monthly`, `Semiannual`, all governance review tasks | Scheduled task cadence, output style, memory, Teams/Outlook delivery pattern | +| Governance, Policy & Risk | Manage the FinOps Practice | Operate | `finops-practitioner`, `azure-capacity-manager`, `ftk-hubs-agent` | `AdvisorSuppressionReview`, `AlertCoverageAudit`, `BudgetCoverageAudit`, `CapacityDailyMonitor`, `MonitoringScopeValidation` | `resource-graph-query`, budget/anomaly deployment tools, suppression tools, quota tools | +| FinOps Assessment | Manage the FinOps Practice | Operate | Guidance only through `finops-practitioner` | None | No direct recipe tool. Assessment is advisory unless a future task is added. | +| Automation, Tools, & Services | Manage the FinOps Practice | Operate | `finops-practitioner`, `azure-capacity-manager`, `ftk-hubs-agent` | All scheduled tasks | Scheduled tasks, custom tools, built-in visualization tools, Teams and Outlook connector tools | +| FinOps Education & Enablement | Manage the FinOps Practice | Operate | Guidance only through `finops-practitioner` | None | No direct recipe tool. Knowledge files support agent context but are not a training workflow. | +| Invoicing & Chargeback | Manage the FinOps Practice | Operate | `finops-practitioner`, `ftk-database-query`, `chief-financial-officer` | `Monthly`, `Semiannual` | `cost-by-financial-hierarchy`, transaction tools, monthly trend and allocation evidence | +| Intersecting Disciplines | Manage the FinOps Practice | Operate | Guidance only through `finops-practitioner` | None | No direct recipe tool. Security, ITSM, ITFM, ITAM, and sustainability intersections are consultative context. | + +## Skills + +| Skill | Path | +|-------|------| +| `azure-capacity-management` | `config/skills/azure-capacity-management/` | +| `azure-cost-management` | `config/skills/azure-cost-management/` | +| `finops-toolkit` | `config/skills/finops-toolkit/` | + +## Scheduled task ownership map + +| Task | Owning agent | Schedule | Framework alignment | Required delegates and consults | +|------|------------|----------|---------------------|----------------------------------| +| `HubsHealthCheck` | `finops-practitioner` | `0 6 * * *` | Understand Usage & Cost: Data Ingestion; Manage the FinOps Practice: Automation, Tools, & Services | Delegates Hub platform evidence to `ftk-hubs-agent`. | +| `CapacityDailyMonitor` | `finops-practitioner` | `30 6 * * *` | Automation, Tools, & Services; Usage Optimization; Governance, Policy & Risk | Delegates capacity evidence to `azure-capacity-manager`; no CFO consult. | +| `ComputeUtilizationTrend` | `finops-practitioner` | `0 7 * * 1` | Usage Optimization; Planning & Estimating; Forecasting | Delegates capacity and inventory evidence to `azure-capacity-manager`. | +| `CostOptimization` | `finops-practitioner` | `0 8 * * 1` | Optimize Usage & Cost: Usage Optimization and Rate Optimization; Manage the FinOps Practice: Governance, Policy & Risk | Delegates Kusto evidence to `ftk-database-query`; delegates quota/capacity feasibility to `azure-capacity-manager`; consults `chief-financial-officer` for commitment and priority framing when decisions are material. | +| `CapacityWeeklySupplyReview` | `finops-practitioner` | `0 8 * * 1` | Planning & Estimating; Forecasting; Architecting & Workload Placement; Usage Optimization; Rate Optimization support | Delegates capacity evidence to `azure-capacity-manager`; asks `ftk-database-query` for Kusto-backed commitment, savings, and forecast evidence. | +| `NonComputeQuotaAudit` | `finops-practitioner` | `0 7 * * 2` | Automation, Tools, & Services; Governance, Policy & Risk | Delegates non-compute quota evidence to `azure-capacity-manager`. | +| `DbQuotaAudit` | `finops-practitioner` | `0 7 * * 3` | Automation, Tools, & Services; Governance, Policy & Risk | Delegates database quota evidence to `azure-capacity-manager`. | +| `SkuAvailabilityAudit` | `finops-practitioner` | `30 7 * * 3` | Planning & Estimating; Architecting & Workload Placement; region and SKU readiness | Delegates SKU availability evidence to `azure-capacity-manager`; consults `ftk-hubs-agent` only for FinOps Hub ADX backend deployment readiness. | +| `MonitoringScopeValidation` | `finops-practitioner` | `0 9 * * 4` | Understand Usage & Cost: Data Ingestion and Reporting & Analytics foundation | Delegates Hub platform and inventory evidence to `ftk-hubs-agent`. | +| `BenefitRecommendationReview` | `finops-practitioner` | `0 8 * * 5` | Optimize Usage & Cost: Rate Optimization; Quantify Business Value | Delegates Kusto recommendation/utilization evidence to `ftk-database-query`; consults `chief-financial-officer` for approval framing and commitment risk. | +| `AdvisorSuppressionReview` | `finops-practitioner` | `0 9 1 * *` | Optimize Usage & Cost; Governance, Policy & Risk | Uses inventory/governance evidence; remediation requires explicit approval. | +| `AIWorkloadCostAnalysis` | `finops-practitioner` | `0 10 1 * *` | Quantify Business Value: Unit Economics; Understand Usage & Cost: Reporting & Analytics; leadership strategy alignment for AI | Delegates AI cost Kusto evidence to `ftk-database-query`; delegates GPU/capacity evidence to `azure-capacity-manager`; consults `chief-financial-officer` for investment and unit-economics framing. | +| `CapacityMonthlyPlanning` | `finops-practitioner` | `0 9 1 * *` | Planning & Estimating; Forecasting; Budgeting support; Architecting & Workload Placement | Delegates capacity evidence to `azure-capacity-manager`; asks `ftk-database-query` for Kusto-backed forecast/rate context; may consult `chief-financial-officer` for budget guardrails. | +| `StoragePaasGrowthForecast` | `finops-practitioner` | `0 8 1 * *` | Planning & Estimating; Forecasting; Automation, Tools, & Services | Delegates non-compute and inventory evidence to `azure-capacity-manager`. | +| `Monthly` | `finops-practitioner` | `15 17 5 * *` | Understand Usage & Cost: Reporting & Analytics and Anomaly Management; Optimize Usage & Cost: Usage Optimization and Rate Optimization | Delegates all Kusto evidence to `ftk-database-query`; delegates capacity risk evidence to `azure-capacity-manager`; consults `chief-financial-officer` for material commitment or forecast decisions. | +| `Semiannual` | `finops-practitioner` | `0 9 5 1,7 *` | Quantify Business Value: Forecasting, Budgeting, KPIs & Benchmarking; Manage the FinOps Practice leadership reporting | Delegates fiscal Kusto evidence to `ftk-database-query`; delegates capacity risk evidence to `azure-capacity-manager` where needed; consults `chief-financial-officer` for executive report framing. | +| `BudgetCoverageAudit` | `finops-practitioner` | `0 8 15 * *` | Quantify Business Value: Budgeting; Manage the FinOps Practice: Governance, Policy & Risk | Uses governance inventory; budget deployment requires explicit approval. | +| `AlertCoverageAudit` | `finops-practitioner` | `0 8 16 * *` | Understand Usage & Cost: Anomaly Management; Manage the FinOps Practice: Governance, Policy & Risk and Automation, Tools, & Services | Uses governance inventory; anomaly alert deployment requires explicit approval. | +| `CapacityQuarterlyStrategy` | `finops-practitioner` | `0 9 1 1,4,7,10 *` | Leadership strategy alignment; Planning & Estimating; Forecasting; Architecting & Workload Placement; Rate Optimization support | Delegates strategic capacity evidence to `azure-capacity-manager`; asks `ftk-database-query` for Kusto-backed cost/rate evidence; consults `chief-financial-officer` for portfolio tradeoff framing. | + +## Tool inventory + +### Kusto tools + +All Kusto tools are owned by `ftk-database-query`. Other agents request Kusto evidence from that specialist instead of calling these tools directly. + +| Tool | Purpose | +|------|---------| +| `ai-cost-by-application` | Breaks down Azure OpenAI costs by application, team, and environment tags. | +| `ai-daily-trend` | Reports daily Azure OpenAI cost and token consumption trends. | +| `ai-model-cost-comparison` | Compares cost per 1K tokens across Azure OpenAI model versions. | +| `ai-token-usage-breakdown` | Breaks Azure OpenAI token consumption down by model version and input/output direction. | +| `allocation-accuracy-index` | Measures directly attributed cost as a share of total effective cost. | +| `anomaly-detection-rate` | Measures the share of effective spend on anomaly-flagged daily buckets. | +| `anomaly-variance-total` | Quantifies signed and absolute unpredicted spend variance for anomaly events. | +| `commitment-discount-waste` | Measures unused commitment value as a share of total commitment cost. | +| `commitment-discount-utilization` | Analyzes consumed core hours by commitment discount type. | +| `commitment-utilization-score` | Computes commitment utilization amount, potential, and score by commitment and currency. | +| `compute-cost-per-core` | Computes hourly and effective average compute cost per consumed vCPU core hour. | +| `compute-spend-commitment-coverage` | Measures compute spend covered by commitment discounts. | +| `cost-anomaly-detection` | Detects cost spikes and drops over a configurable history window. | +| `cost-by-financial-hierarchy` | Summarizes costs across billing profile, invoice section, team, product, application, and environment. | +| `cost-by-region-trend` | Summarizes effective cost by Azure region. | +| `cost-forecasting-model` | Forecasts future effective cost from historical cost data. | +| `cost-optimization-index` | Computes the hub-wide Cost Optimization Index from current recommendations and windowed cost. | +| `cost-per-gb-stored` | Calculates storage cost per normalized GB-month. | +| `cost-visibility-delay` | Measures cost data visibility delay from charge period end to Hub ingestion. | +| `costs-enriched-base` | Returns enriched row-level cost and usage samples for drill-down analysis. | +| `data-update-frequency` | Measures Hub ingestion update cadence from distinct ingestion timestamps. | +| `macc-consumption-vs-commitment` | Measures MACC consumption versus commitment drawdown by billing profile and month. | +| `monthly-cost-change-percentage` | Calculates month-over-month billed and effective cost change. | +| `monthly-cost-trend` | Returns billed and effective cost totals by month. | +| `percentage-unallocated-costs` | Measures the share of effective cost without allocation evidence. | +| `percentage-untagged-costs` | Measures the share of effective cost associated with resources that have no tags. | +| `quarterly-cost-by-resource-group` | Returns top resource-group cost rows by subscription and month. | +| `reservation-recommendation-breakdown` | Analyzes Microsoft reservation recommendations from `Recommendations()`. | +| `savings-summary-report` | Summarizes list cost, effective cost, negotiated discount savings, commitment savings, and effective savings rate. | +| `service-price-benchmarking` | Benchmarks services by list, contracted, and effective cost. | +| `storage-tier-distribution` | Summarizes storage cost and GB-month distribution by access-tier bucket. | +| `tagging-policy-compliance` | Measures cost-weighted compliance with required tag keys. | +| `top-commitment-transactions` | Returns top non-usage commitment discount purchase transactions. | +| `top-other-transactions` | Returns top non-usage, non-commitment purchase transactions. | +| `top-resource-groups-by-cost` | Returns top resource groups by effective cost. | +| `top-resource-types-by-cost` | Returns top resource types by count and effective cost. | +| `top-services-by-cost` | Returns top Azure services by effective cost. | + +### Built-in tools + +The recipe enables SRE Agent platform tools through `config/built-in-tools.json` during the apply-extras step. These are platform tools, not custom recipe tools. FinOps Hub database access remains owned by the custom Kusto tools assigned to `ftk-database-query`. + +| Category | Enabled tools | +|----------|---------------| +| Log Query | `QueryLogAnalyticsByWorkspaceId`, `QueryAppInsightsByAppId`, `QueryAppInsightsByResourceId`, `QueryLogAnalyticsByResourceId` | +| Visualization | `PlotScatter`, `PlotHeatmap`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation` | + +### Custom Azure and Hub tools + +| Tool | Assigned agents | Purpose | +|------|-----------------|---------| +| `benefit-recommendations` | `azure-capacity-manager` | Gets Cost Management benefit recommendations for savings plans and reserved instances. | +| `capacity-reservation-groups` | `azure-capacity-manager` | Lists capacity reservation groups and reports reserved versus allocated capacity. | +| `data-freshness-check` | `ftk-hubs-agent` | Checks FinOps Hub function data freshness through Azure Data Explorer REST queries. | +| `db-service-quotas` | `azure-capacity-manager` | Reports SQL DB, SQL MI, Cosmos DB, PostgreSQL Flex, and MySQL Flex quota and region access signals. | +| `deploy-anomaly-alert` | `ftk-hubs-agent` | Creates or updates a Cost Management scheduled action for anomaly detection after explicit remediation approval. | +| `deploy-budget` | `ftk-hubs-agent` | Creates or updates a subscription-level Cost Management budget after explicit remediation approval. | +| `deploy-bulk-anomaly-alerts` | `ftk-hubs-agent` | Creates or updates anomaly alert scheduled actions across subscriptions discovered from a management group after explicit remediation approval. | +| `deploy-bulk-budgets` | `ftk-hubs-agent` | Creates or updates Cost Management budgets across subscriptions discovered from a management group after explicit remediation approval. | +| `non-compute-quotas` | `azure-capacity-manager` | Checks non-compute Azure service quota utilization. | +| `resource-graph-query` | `ftk-hubs-agent` | Runs Azure Resource Graph KQL across one or more subscriptions. | +| `sku-availability` | `azure-capacity-manager`, `ftk-hubs-agent` | Lists regional SKU availability for Azure Compute or Azure Data Explorer. | +| `suppress-advisor-recommendations` | `ftk-hubs-agent` | Suppresses selected Azure Advisor recommendations across subscriptions under a management group after explicit remediation approval. | +| `vm-quota-usage` | `azure-capacity-manager` | Reports Azure VM family quota usage and quota risk by subscription and region. | + +## Operating notes + +- The Kusto connector is applied by `bin/apply-extras.sh` as an SRE Agent connector child resource when a Kusto URI is provided. The Bicep deployment grants the agent managed identity `AllDatabasesViewer` on the Azure Data Explorer cluster before the Kusto connector is created. This is required because the Hub functions can resolve cross-database references such as `Ingestion`. `finops-hub-kusto` supports the recipe's custom query tools. Scheduled tasks are applied by the same helper through the SRE Agent data plane. +- The portal Team onboarding wizard is part of the expected customer flow and must not be bypassed. The deployment supports it by assigning deployment-subscription Reader by default; adding the agent resource group, explicit target resource groups, and same-subscription FinOps Hub resource group to the agent managed-resource scope; and assigning the agent identity target-scope RBAC for Azure Resource Graph and Azure CLI discovery. +- When the target Azure Data Explorer cluster denies public query access, `bin/deploy.sh` still deploys all resources, grants cluster `AllDatabasesViewer`, and creates the connector, then warns that private endpoint ADX blocks direct KQL queries from the hosted SRE Agent and links to the SRE Agent known limitations. +- The SRE Agent resource is deployed with `Microsoft.App/agents@2026-01-01`, `upgradeChannel: Preview`, `experimentalSettings.EnableSandboxGroup`, and `experimentalSettings.EnableWorkspaceTools`. +- Skills are applied with their `SKILL.md` content and tool references. Supporting reference material that must be available to the agent should be promoted to KnowledgeFile sources because the current SRE Agent data plane rejects skill payloads with non-empty `additionalFiles`. +- `bin/apply-extras.sh` uploads `ftk-output-style.md` from the Claude plugin output styles as a portal-visible `KnowledgeFile` source and verifies the expected KnowledgeFile sources are indexed. Every scheduled task explicitly applies that style for report, Teams-message, and Outlook-email output. +- `README.md` carries the deployment workflow; this file carries the detailed implemented recipe inventory. +- Add or remove scheduled task YAML, tool YAML, subagent YAML, or skill directories first, then update this catalog and `README.md` in the same change. diff --git a/src/templates/sre-agent/README.md b/src/templates/sre-agent/README.md new file mode 100644 index 000000000..82b0dffb8 --- /dev/null +++ b/src/templates/sre-agent/README.md @@ -0,0 +1,243 @@ +# FinOps toolkit SRE Agent + +Deploy and configure an Azure SRE Agent with the FinOps toolkit recipe under `recipes/finops-hub/`. + +The deployment flow is copied from the Microsoft SRE Agent starter lab and updated for the FinOps toolkit: + +- Azure CLI + Bicep deploy the SRE Agent infrastructure. +- `bin/apply-extras.sh` applies recipe assets that are not deployed by Bicep: connectors, KnowledgeFile sources, built-in tool configuration, tools, skills, subagents, and scheduled tasks. +- `azd` is not used. + +## What you get + +| Component | Count | Description | +|-----------|-------|-------------| +| SRE Agent | 1 | `Microsoft.App/agents` resource | +| Model provider | 1 | Azure OpenAI provider-level routing (`MicrosoftFoundry` ARM value, `Automatic` model routing) | +| Managed identity | 1 | Agent system-assigned managed identity | +| Log Analytics | 1 | Workspace for agent telemetry | +| Application Insights | 1 | Linked to Log Analytics | +| Custom agents | 5 | FinOps practitioner orchestrator plus CFO, capacity, database-query, and hubs specialists | +| Skills | 3 | Azure capacity management, Azure cost management, and FinOps Toolkit | +| Tools | 50 | Kusto, capacity, and Hub infrastructure tools | +| Tool overrides | 9 | Enables SRE Agent Log Query and Visualization tools | +| Scheduled tasks | 19 | Recurring FinOps, capacity, governance, and reporting tasks, all owned by `finops-practitioner` | +| Connectors | 1 | Optional FinOps Hub Kusto connector when `--cluster-uri` is provided | +| Knowledge docs | 6 | Five recipe knowledge docs plus the FinOps Toolkit output style | + +## Current recipe inventory + +The current implementation is the `recipes/finops-hub/` recipe. [CATALOG.md](CATALOG.md) is the authoritative inventory and FinOps Framework alignment reference, including the subagent-to-capability, tool, and scheduled-task matrix; this section summarizes what ships. + +| Agent | Scheduled tasks owned | Focus | +|-------|----------------------:|-------| +| `finops-practitioner` | 19 | Sole scheduled-task owner. Runs the operating rhythm, delegates specialist evidence collection, applies the output style, assembles reports, and delivers results. | +| `azure-capacity-manager` | 0 | Tool-bearing delegated subagent for quota, capacity reservation groups, region and zone access, AKS capacity, and capacity evidence. Owns the capacity Python tools; does not own Kusto, Resource Graph, Hub freshness, CLI, or remediation deployment tools. | +| `chief-financial-officer` | 0 | Consultative subagent with no tools. Provides finance and leadership framing for budgeting, forecasting, AI unit economics, commitment risk, and executive decisions from evidence supplied by the practitioner. | +| `ftk-database-query` | 0 | Tool-bearing delegated subagent for schema-aware FinOps Hub KQL and database evidence. Owns the Kusto tools; does not own Python, Azure CLI, Resource Graph, Hub freshness, or remediation deployment tools. | +| `ftk-hubs-agent` | 0 | Tool-bearing delegated subagent for Hub health, data freshness, monitoring scope validation, deployment, upgrade, connector readiness, Resource Graph inventory, and explicit remediation deployment tooling. | + +| Tool type | Count | Examples | +|-----------|------:|----------| +| KustoTool | 37 | `cost-anomaly-detection`, `allocation-accuracy-index`, `cost-optimization-index`, `reservation-recommendation-breakdown` | +| PythonTool | 13 | `vm-quota-usage`, `data-freshness-check`, `db-service-quotas`, `sku-availability` | + +The infrastructure deploys `Microsoft.App/agents@2026-01-01` on the `Preview` upgrade channel with `EnableSandboxGroup` and `EnableWorkspaceTools` enabled. This matches the upstream SRE Agent template default and enables the extended-agent skill, tool, subagent, and schedule APIs used by the recipe. The recipe defaults the parent SRE Agent to Azure OpenAI provider-level routing (`defaultModel.provider = MicrosoftFoundry`, `defaultModel.name = Automatic`). Azure SRE Agent selects the model within the configured provider; this template does not pin different models per custom agent or scheduled task. `bin/apply-extras.sh` enables the SRE Agent built-in Log Query and Visualization tools. It uploads the recipe knowledge files and the shared FinOps Toolkit output style from `../claude-plugin/output-styles/ftk-output-style.md` as portal-visible `KnowledgeFile` sources, then verifies the expected sources are indexed before tools, subagents, and scheduled tasks are applied. Scheduled tasks reference `ftk-output-style.md` so recurring reports use the same evidence, formatting, FinOps capability, confidence, and disclaimer conventions. + +Skills are applied with their `SKILL.md` content and tool references. The FinOps Toolkit query references resolve through the canonical `src/queries` catalog so the SRE Agent recipe does not carry a stale copy. Supporting reference material that must be available to the agent should be uploaded as KnowledgeFile sources; the current SRE Agent data plane rejects skill payloads with non-empty `additionalFiles`. + +Scheduled reports must distinguish product or deployment defects from expected evaluation-data limits and customer-owned delegation. Limited Hub history, empty transaction diagnostics, and missing multi-period trigger evidence reduce confidence; they are not by themselves deployment failures. Broader management group, billing, quota, or subscription visibility should be reported as a required customer delegation step unless this template explicitly owns the role assignment. + +The recipe is aligned to the FinOps Framework references listed in [CATALOG.md](CATALOG.md). `finops-practitioner` owns all scheduled tasks, has no direct tools, and orchestrates four delegated subagents. Three delegated subagents have tools: `ftk-database-query` owns Kusto and FOCUS evidence collection, `azure-capacity-manager` owns capacity Python evidence, and `ftk-hubs-agent` owns Hub platform and infrastructure health tooling. `chief-financial-officer` is consulted for finance and leadership framing and has no tools or scheduled tasks. Capacity and quota management is mapped into the canonical domains, capabilities, personas, principles, and phases, not a separate azcapman operating model. + +The phase model is iterative: + +| Phase | How the recipe uses it | +|-------|------------------------| +| Inform | Build trusted cost, usage, allocation, forecast, unit-economics, data freshness, and capacity-headroom evidence. | +| Optimize | Identify rate, usage, workload placement, SKU, quota, CRG, and architecture opportunities with business-value tradeoffs. | +| Operate | Run scheduled governance, budget, alert, reporting, connector, and continuous-improvement workflows. | + +| Scheduled task | Owning agent | Schedule | +|----------------|-------|----------| +| `CapacityDailyMonitor` | `finops-practitioner` | `30 6 * * *` | +| `HubsHealthCheck` | `finops-practitioner` | `0 6 * * *` | +| `Monthly` | `finops-practitioner` | `15 17 5 * *` | +| `CapacityWeeklySupplyReview` | `finops-practitioner` | `0 8 * * 1` | +| `ComputeUtilizationTrend` | `finops-practitioner` | `0 7 * * 1` | +| `CostOptimization` | `finops-practitioner` | `0 8 * * 1` | +| `NonComputeQuotaAudit` | `finops-practitioner` | `0 7 * * 2` | +| `DbQuotaAudit` | `finops-practitioner` | `0 7 * * 3` | +| `SkuAvailabilityAudit` | `finops-practitioner` | `30 7 * * 3` | +| `MonitoringScopeValidation` | `finops-practitioner` | `0 9 * * 4` | +| `BenefitRecommendationReview` | `finops-practitioner` | `0 8 * * 5` | +| `AdvisorSuppressionReview` | `finops-practitioner` | `0 9 1 * *` | +| `AIWorkloadCostAnalysis` | `finops-practitioner` | `0 10 1 * *` | +| `CapacityMonthlyPlanning` | `finops-practitioner` | `0 9 1 * *` | +| `StoragePaasGrowthForecast` | `finops-practitioner` | `0 8 1 * *` | +| `Semiannual` | `finops-practitioner` | `0 9 5 1,7 *` | +| `BudgetCoverageAudit` | `finops-practitioner` | `0 8 15 * *` | +| `AlertCoverageAudit` | `finops-practitioner` | `0 8 16 * *` | +| `CapacityQuarterlyStrategy` | `finops-practitioner` | `0 9 1 1,4,7,10 *` | + +## Prerequisites + +- Azure CLI (`az`) +- `curl` +- `jq` +- `python3` with PyYAML +- Bash 3.2 or newer +- `Microsoft.App` registered in the target subscription + +Run: + +```bash +bash bin/check-prerequisites.sh --subscription +``` + +## Deploy + +Run one script with explicit parameters: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] \ + [--target-resource-group ...] \ + [--dry-run] \ + [--force] \ + [--no-telemetry] +``` + +`bin/deploy.sh --help` is the CLI contract: + +```text +Usage: bash bin/deploy.sh --recipe [options] + +Required: + --recipe Recipe directory + --subscription Azure subscription + -g, --resource-group Resource group for the agent + -n, --name Agent name + -l, --location Azure region + +Optional: + --target-resource-group Repeatable target resource group. The agent resource group is always included. + --cluster-uri Kusto connector URI, including database name. + Example: https://..kusto.windows.net/Hub + --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. + --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deploy-name Deployment name override. Defaults to a deterministic name. + --dry-run Validate inputs and write parameters without Azure calls. + --force Accepted for compatibility. + --no-telemetry Accepted for compatibility. + -h, --help Show this help. +``` + +### Modes + +Dry-run is hermetic and does not call Azure: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + -g \ + -n \ + -l \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/] \ + --dry-run +``` + +You can also validate the local extras assembly without Azure calls: + +```bash +bash bin/apply-extras.sh \ + --endpoint https://example.sre.azure.com \ + --subscription \ + --resource-group \ + --name \ + --recipe recipes/finops-hub \ + --build-dir /tmp/ftk-sre-agent-extras \ + --kusto-connector-uri https://..kusto.windows.net/Hub \ + --dry-run +``` + +When deploying, `deploy.sh` runs a subscription-scoped ARM deployment and then runs `bin/apply-extras.sh` to apply the recipe extras. The helper follows the upstream SRE Agent template pattern: connectors and KnowledgeFile sources use ARM child resources, while built-in tool configuration, custom tools, skills, subagents, and scheduled tasks use the SRE Agent data plane. + +Supporting resource names are deterministic for the subscription ID, agent resource group ID, and agent name. Rerunning the script with the same values updates the same Log Analytics workspace, Application Insights component, system-managed identity RBAC assignments, and SRE Agent. The apply-extras step deletes existing scheduled tasks with the recipe's task names before applying manifests so redeployments don't create duplicate automations. `--deploy-name` only changes the ARM deployment record and local build directory. + +The deployment intentionally keeps the SRE Agent onboarding wizard in the portal. The wizard uses the agent managed identity first to discover managed Azure resources and may show a **Grant permissions** OBO prompt if the identity cannot read a scope yet. Do not bypass that flow. Instead, confirm the agent has the expected managed-resource scopes and RBAC: + +- The deployment assigns `Reader` at subscription scope by default so subscription inventory, Resource Graph, capacity, quota, and coverage tools can inspect the deployment subscription. Pass `--no-subscription-reader` only when you grant equivalent read access another way. +- The agent resource group is always added to `knowledgeGraphConfiguration.managedResources` and receives the recipe's target-scope RBAC. +- Each `--target-resource-group` value is added to managed resources and receives the same target-scope RBAC. +- When `--cluster-uri` resolves to a same-subscription FinOps Hub Kusto cluster, the cluster's resource group is also added to managed resources and receives target-scope RBAC. +- With the default `High` recipe, target-scope RBAC is `Reader`, `Monitoring Reader`, `Log Analytics Reader`, and `Contributor`. `Low` omits `Contributor`. + +If `--cluster-uri` points to an Azure Data Explorer cluster with `publicNetworkAccess` set to `Disabled`, the script still deploys all resources, assigns the agent identity `AllDatabasesViewer` on the cluster, and creates the `finops-hub-kusto` connector. It also prints a warning with the SRE Agent known-limitations URL because private endpoint ADX blocks direct KQL queries from the hosted agent. The customer can decide whether to enable public query access for the connector after reviewing . + +## Recipe identity policy + +- Shipped recipes in this repo omit the `identity` block. +- Customer-authored recipes may include `identity` defaults for reproducible deployments. +- CLI flags always win over recipe defaults. + +If you omit `--target-resource-group`, the deploy flow still scopes the agent to its own resource group. If a same-subscription `--cluster-uri` is provided, the FinOps Hub resource group is also included automatically. + +## Verify + +```bash +bash bin/verify-agent.sh \ + $(az account show --query id -o tsv) \ + \ + \ + --expected recipes/finops-hub +``` + +If you passed `--cluster-uri`, confirm the `finops-hub-kusto` connector in `https://sre.azure.com`. If the deployment warned that the cluster denies public query access, the connector is expected to remain unhealthy until the customer enables public query access or Microsoft adds private endpoint ADX query support for SRE Agent. + +## CI/CD example + +The GitHub Actions example passes the cluster URI as a script flag while keeping secrets such as `GITHUB_PAT` or `ADO_PAT` in the environment. + +## Migrating from env-var-driven deploys + +The old deploy path accepted config through environment variables such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, `SRE_AGENT_NO_TELEMETRY`, and `connectors.secrets.env`. Those inputs are no longer supported for config or identity. + +Before: + +```bash +export FINOPS_HUB_CLUSTER_URI="https://..kusto.windows.net/hub" +export FINOPS_HUB_CLUSTER_RESOURCE_ID="/subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/" +export SRE_AGENT_NO_TELEMETRY=1 +bash bin/deploy.sh recipes/finops-hub +``` + +After: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + --cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/ \ + --no-telemetry +``` + +The only supported environment-variable inputs are secrets: + +- `GITHUB_PAT` +- `ADO_PAT` +- `ADO_USE_AAD` +- `ADO_USE_MI` +- `ADO_ORG` diff --git a/src/templates/sre-agent/bin/build-extras.py b/src/templates/sre-agent/bin/build-extras.py new file mode 100755 index 000000000..769dcb831 --- /dev/null +++ b/src/templates/sre-agent/bin/build-extras.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python3 +"""Build SRE Agent extras from a FinOps Toolkit recipe. + +The output follows the microsoft/sre-agent apply-extras contract: infrastructure +stays in Bicep/ARM, while data-plane and connector extras are assembled into one +JSON document for the local apply step. +""" + +from __future__ import annotations + +import argparse +import json +import os +import pathlib +import re +import sys +from typing import Any + +try: + import yaml +except ImportError as exc: # pragma: no cover - exercised by shell prereq checks + raise SystemExit("PyYAML is required. Install with: pip install pyyaml") from exc + + +JsonObject = dict[str, Any] + + +def load_json(path: pathlib.Path, default: Any) -> Any: + if not path.is_file(): + return default + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def load_yaml(path: pathlib.Path) -> JsonObject: + with path.open("r", encoding="utf-8") as handle: + data = yaml.safe_load(handle) or {} + if not isinstance(data, dict): + raise SystemExit(f"YAML manifest must be an object: {path}") + return data + + +def yaml_files(root: pathlib.Path) -> list[pathlib.Path]: + if not root.is_dir(): + return [] + paths: list[pathlib.Path] = [] + for dirpath, _, filenames in os.walk(root, followlinks=True): + for filename in filenames: + path = pathlib.Path(dirpath) / filename + if path.suffix.lower() in {".yaml", ".yml"}: + paths.append(path) + return sorted(paths) + + +def collect_yaml(root: pathlib.Path) -> list[JsonObject]: + return [load_yaml(path) for path in yaml_files(root)] + + +def read_kql_body(path: pathlib.Path) -> str: + text = read_text(path) + lines = text.splitlines() + start = 0 + for index, line in enumerate(lines): + stripped = line.strip() + if stripped == "" or stripped.startswith("//"): + continue + start = index + break + return "\n".join(lines[start:]).rstrip() + + +def collect_kql_comment_block(path: pathlib.Path) -> list[str]: + comments: list[str] = [] + for line in read_text(path).splitlines(): + stripped = line.strip() + if stripped == "": + continue + if not stripped.startswith("//"): + break + comments.append(stripped[2:].strip()) + return comments + + +def kql_description(path: pathlib.Path) -> str: + comments = collect_kql_comment_block(path) + query_name = path.stem.replace("-", " ") + description_lines: list[str] = [] + in_description = False + for comment in comments: + if comment == "Description:": + in_description = True + continue + if comment == "Parameters:" or comment.startswith("Query:"): + if in_description: + break + if comment.startswith("Query:"): + query_name = comment.split(":", 1)[1].strip() or query_name + continue + if in_description: + description_lines.append(comment) + description = " ".join(part for part in description_lines if part) + if not description: + description = f"Runs the {query_name} FinOps Hub catalog query." + return description + + +def kql_parameters(path: pathlib.Path) -> list[JsonObject]: + comments = collect_kql_comment_block(path) + query = read_kql_body(path) + parameters: list[JsonObject] = [] + in_parameters = False + for comment in comments: + if comment == "Parameters:": + in_parameters = True + continue + if not in_parameters: + continue + if comment.startswith("Each row") or comment.startswith("Use this query"): + break + if comment.lower().startswith("none"): + break + if ":" not in comment: + continue + name, raw_description = comment.split(":", 1) + name = name.strip() + if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", name): + continue + if not re.search(rf"^let\s+{re.escape(name)}\s*=", query, flags=re.MULTILINE): + continue + if any(parameter["name"] == name for parameter in parameters): + continue + parameters.append( + { + "name": name, + "type": "string", + "description": raw_description.strip(), + "required": True, + } + ) + return parameters + + +def replace_kql_parameter_defaults(query: str, parameters: list[JsonObject]) -> str: + for parameter in parameters: + name = re.escape(str(parameter["name"])) + query = re.sub( + rf"^let\s+{name}\s*=\s*[^;\n]+;", + f"let {parameter['name']} = ##{parameter['name']}##;", + query, + count=1, + flags=re.MULTILINE, + ) + return query + + +def collect_catalog_kusto_tools(recipe_dir: pathlib.Path) -> list[JsonObject]: + catalog_dir = (recipe_dir / "../../../../queries/catalog").resolve() + if not catalog_dir.is_dir(): + raise SystemExit(f"FinOps Hub query catalog not found: {catalog_dir}") + + generated: list[JsonObject] = [] + for path in sorted(catalog_dir.glob("*.kql")): + name = path.stem + parameters = kql_parameters(path) + query = replace_kql_parameter_defaults(read_kql_body(path), parameters) + spec: JsonObject = { + "type": "KustoTool", + "connector": "finops-hub-kusto", + "toolMode": "Auto", + "description": kql_description(path), + "database": "Hub", + "query": query, + } + if parameters: + spec["parameters"] = parameters + generated.append( + { + "api_version": "azuresre.ai/v2", + "kind": "ExtendedAgentTool", + "metadata": {"name": name}, + "spec": spec, + } + ) + return generated + + +def validate_explicit_tools(tools: list[JsonObject]) -> None: + explicit_kusto_names: list[str] = [] + for tool in tools: + name = metadata_name(tool) + spec = tool.get("spec") or {} + if spec.get("type") == "KustoTool": + explicit_kusto_names.append(name) + if explicit_kusto_names: + raise SystemExit( + "Kusto tools must be generated from src/queries/catalog/*.kql; " + "remove explicit Kusto YAML file(s): " + + ", ".join(sorted(explicit_kusto_names)) + ) + + +def catalog_kpi_tool_names(recipe_dir: pathlib.Path) -> set[str]: + kpi_path = (recipe_dir / "../../../../queries/KPI.md").resolve() + if not kpi_path.is_file(): + raise SystemExit(f"FinOps KPI catalog not found: {kpi_path}") + text = read_text(kpi_path) + return set(re.findall(r"\[([a-z0-9-]+)\]\(catalog/\1\.kql\)", text)) + + +def validate_tool_and_task_coverage(recipe_dir: pathlib.Path, extras: JsonObject) -> None: + catalog_dir = (recipe_dir / "../../../../queries/catalog").resolve() + catalog_names = {path.stem for path in catalog_dir.glob("*.kql")} + tools = extras.get("tools") or [] + tool_names = [metadata_name(tool) for tool in tools] + duplicate_names = sorted({name for name in tool_names if tool_names.count(name) > 1}) + if duplicate_names: + raise SystemExit("Duplicate tool definitions found: " + ", ".join(duplicate_names)) + + kusto_names = { + metadata_name(tool) + for tool in tools + if (tool.get("spec") or {}).get("type") == "KustoTool" + } + missing_kusto = sorted(catalog_names - kusto_names) + if missing_kusto: + raise SystemExit( + "Catalog query file(s) missing generated Kusto tools: " + + ", ".join(missing_kusto) + ) + + kpi_names = catalog_kpi_tool_names(recipe_dir) + missing_kpi_tools = sorted(kpi_names - kusto_names) + if missing_kpi_tools: + raise SystemExit( + "KPI catalog query file(s) missing generated Kusto tools: " + + ", ".join(missing_kpi_tools) + ) + + scheduled_text = "\n".join(json.dumps(task, sort_keys=True) for task in extras.get("scheduledTasks") or []) + missing_scheduled_kpis = [ + name + for name in sorted(kpi_names) + if not re.search(rf"(? str: + metadata = item.get("metadata") or {} + spec = item.get("spec") or {} + name = metadata.get("name") or spec.get("name") or item.get("name") + if not name: + raise SystemExit(f"Manifest missing metadata.name: {item}") + return str(name) + + +def ordered_subagents(root: pathlib.Path) -> list[JsonObject]: + items = collect_yaml(root) + by_name = {metadata_name(item): item for item in items} + dependencies: dict[str, list[str]] = {} + for name, item in by_name.items(): + spec = item.get("spec") or {} + handoffs = spec.get("handoffs") or [] + dependencies[name] = [str(handoff) for handoff in handoffs if str(handoff) in by_name] + + ordered: list[JsonObject] = [] + visiting: set[str] = set() + visited: set[str] = set() + + def visit(name: str) -> None: + if name in visited: + return + if name in visiting: + cycle = " -> ".join([*visiting, name]) + raise SystemExit(f"Subagent handoff cycle detected: {cycle}") + visiting.add(name) + for dependency in dependencies[name]: + visit(dependency) + visiting.remove(name) + visited.add(name) + ordered.append(by_name[name]) + + for name in sorted(by_name): + visit(name) + return ordered + + +def parse_frontmatter(text: str) -> JsonObject: + lines = text.splitlines() + if not lines or lines[0].strip() != "---": + return {} + for index, line in enumerate(lines[1:], start=1): + if line.strip() == "---": + raw = "\n".join(lines[1:index]) + data = yaml.safe_load(raw) or {} + if not isinstance(data, dict): + return {} + return data + return {} + + +def as_list(value: Any) -> list[str]: + if value is None: + return [] + if isinstance(value, list): + return [str(item) for item in value] + if isinstance(value, str): + return [part for part in re.split(r"[\s,]+", value.strip()) if part] + return [str(value)] + + +def read_text(path: pathlib.Path) -> str: + return path.read_text(encoding="utf-8", errors="replace") + + +def collect_skill_directories(root: pathlib.Path) -> list[JsonObject]: + if not root.is_dir(): + return [] + + skills: list[JsonObject] = [] + for skill_dir in sorted(path for path in root.iterdir() if path.is_dir()): + skill_file = skill_dir / "SKILL.md" + if not skill_file.is_file(): + continue + + skill_content = read_text(skill_file) + frontmatter = parse_frontmatter(skill_content) + name = str(frontmatter.get("name") or skill_dir.name) + description = str(frontmatter.get("description") or "") + tools = as_list(frontmatter.get("tools")) + + additional_files: list[JsonObject] = [] + for dirpath, _, filenames in os.walk(skill_dir, followlinks=True): + for filename in filenames: + path = pathlib.Path(dirpath) / filename + relative_path = path.relative_to(skill_dir).as_posix() + if relative_path == "SKILL.md": + continue + additional_files.append( + { + "name": relative_path, + "path": relative_path, + "content": read_text(path), + } + ) + + skills.append( + { + "metadata": { + "name": name, + "description": description, + "spec": {"tools": tools}, + }, + "skillContent": skill_content, + "additionalFiles": sorted(additional_files, key=lambda item: item["name"]), + } + ) + + return skills + + +def replace_env_refs(value: Any, replacements: dict[str, str]) -> Any: + if isinstance(value, str): + pattern = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}") + + def repl(match: re.Match[str]) -> str: + key = match.group(1) + return replacements.get(key) or os.environ.get(key) or match.group(0) + + return pattern.sub(repl, value) + if isinstance(value, list): + return [replace_env_refs(item, replacements) for item in value] + if isinstance(value, dict): + return {key: replace_env_refs(item, replacements) for key, item in value.items()} + return value + + +def collect_connectors(recipe_dir: pathlib.Path, kusto_connector_uri: str) -> list[JsonObject]: + config = load_json(recipe_dir / "connectors.json", {"connectors": []}) + raw_connectors = config if isinstance(config, list) else config.get("connectors", []) + replacements = {} + if kusto_connector_uri: + replacements["FINOPS_HUB_CLUSTER_URI"] = kusto_connector_uri + + connectors: list[JsonObject] = [] + for raw in raw_connectors: + connector = replace_env_refs(raw, replacements) + properties = connector.get("properties") or {} + connector_type = str(properties.get("dataConnectorType") or properties.get("type") or "") + if connector_type.lower() == "kusto" and not kusto_connector_uri: + continue + if connector_type.lower() == "kusto": + properties["dataSource"] = kusto_connector_uri + connector["properties"] = properties + connectors.append(connector) + return connectors + + +def knowledge_content_type(path: pathlib.Path) -> str: + suffix = path.suffix.lower() + return { + ".md": "text/markdown", + ".txt": "text/plain", + ".json": "application/json", + ".csv": "text/csv", + ".yaml": "application/yaml", + ".yml": "application/yaml", + }.get(suffix, "application/octet-stream") + + +def collect_knowledge_items(recipe_dir: pathlib.Path) -> list[JsonObject]: + knowledge_paths: list[pathlib.Path] = [] + knowledge_dir = recipe_dir / "knowledge" + if knowledge_dir.is_dir(): + knowledge_paths.extend(sorted(path for path in knowledge_dir.iterdir() if path.is_file())) + + output_style = (recipe_dir / "../../../claude-plugin/output-styles/ftk-output-style.md").resolve() + if not output_style.is_file(): + raise SystemExit(f"Output style knowledge document not found: {output_style}") + knowledge_paths.append(output_style) + + items: list[JsonObject] = [] + for path in knowledge_paths: + items.append( + { + "name": path.name, + "content": read_text(path), + "contentType": knowledge_content_type(path), + "sourcePath": str(path), + } + ) + return items + + +def main() -> int: + parser = argparse.ArgumentParser(description="Build FinOps Toolkit SRE Agent extras JSON.") + parser.add_argument("--recipe", required=True, type=pathlib.Path) + parser.add_argument("--output", required=True, type=pathlib.Path) + parser.add_argument("--kusto-connector-uri", default="") + args = parser.parse_args() + + recipe_dir = args.recipe.resolve() + if not recipe_dir.is_dir(): + raise SystemExit(f"Recipe directory not found: {recipe_dir}") + + explicit_tools = collect_yaml(recipe_dir / "config/tools") + validate_explicit_tools(explicit_tools) + generated_tools = collect_catalog_kusto_tools(recipe_dir) + + extras = { + "connectors": collect_connectors(recipe_dir, args.kusto_connector_uri), + "builtInTools": load_json(recipe_dir / "config/built-in-tools.json", {"overrides": []}), + "knowledgeItems": collect_knowledge_items(recipe_dir), + "skills": collect_skill_directories(recipe_dir / "config/skills"), + "subagents": ordered_subagents(recipe_dir / "config/subagents"), + "tools": [*explicit_tools, *generated_tools], + "scheduledTasks": collect_yaml(recipe_dir / "automations/scheduled-tasks"), + } + validate_tool_and_task_coverage(recipe_dir, extras) + + args.output.parent.mkdir(parents=True, exist_ok=True) + with args.output.open("w", encoding="utf-8") as handle: + json.dump(extras, handle, indent=2, ensure_ascii=False) + handle.write("\n") + + summary = {key: len(value) for key, value in extras.items() if isinstance(value, list)} + summary["builtInToolOverrides"] = len((extras["builtInTools"] or {}).get("overrides", [])) + print(json.dumps(summary, sort_keys=True)) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/templates/sre-agent/bin/verify-agent.sh b/src/templates/sre-agent/bin/verify-agent.sh new file mode 100755 index 000000000..b6cab003a --- /dev/null +++ b/src/templates/sre-agent/bin/verify-agent.sh @@ -0,0 +1,548 @@ +#!/usr/bin/env bash +# verify-agent.sh — Verify an SRE Agent deployment is complete. +# +# Usage: +# ./verify-agent.sh [--expected ] +# +# Queries ARM + data-plane APIs and prints a pass/fail table. +# If --expected is given, compares counts against the config directory. + +set -uo pipefail + +usage() { + cat < [--expected ] + +Arguments: + Subscription + Resource group + Agent name + +Options: + --expected Expected config directory + -h, --help Show this help +EOF + exit "${1:-0}" +} + +[[ "${1:-}" == "-h" || "${1:-}" == "--help" ]] && usage 0 +[[ $# -ge 3 ]] || usage 2 + +SUB="$1" +RG="$2" +AGENT="$3" +EXPECTED_DIR="" +EXPECTED_CONFIG="" +EXPECTED_CONNECTORS="" +EXPECTED_CONFIG_HAS_CONNECTORS="false" +shift 3 +while [[ $# -gt 0 ]]; do + case "$1" in + --expected) + if [[ -z "${2:-}" || "${2:-}" == -* ]]; then + echo "Error: flag --expected requires a value" >&2 + usage 2 + fi + EXPECTED_DIR="$2" + shift 2 + ;; + -h|--help) usage 0 ;; + *) + echo "Error: unknown argument '$1'" >&2 + usage 2 + ;; + esac +done + +az() { command az "$@" --subscription "$SUB"; } + +# Load expected-config.json if present +if [[ -n "$EXPECTED_DIR" && -f "${EXPECTED_DIR}/expected-config.json" ]]; then + EXPECTED_CONFIG=$(cat "${EXPECTED_DIR}/expected-config.json") + if echo "$EXPECTED_CONFIG" | jq -e 'has("connectors")' >/dev/null 2>&1; then + EXPECTED_CONFIG_HAS_CONNECTORS="true" + fi +fi +if [[ -n "$EXPECTED_DIR" && -f "${EXPECTED_DIR}/connectors.json" ]]; then + EXPECTED_CONNECTORS=$(jq -c '.connectors // []' "${EXPECTED_DIR}/connectors.json" 2>/dev/null || echo "[]") +fi + +# Helper: get expected value from expected-config.json +exp() { + local path="$1" fallback="${2:--}" + if [[ -n "$EXPECTED_CONFIG" ]]; then + local val + val=$(echo "$EXPECTED_CONFIG" | jq -r "$path // empty" 2>/dev/null) + [[ -n "$val" && "$val" != "null" ]] && echo "$val" && return + fi + echo "$fallback" +} +exp_list() { + local path="$1" + if [[ -n "$EXPECTED_CONFIG" ]]; then + echo "$EXPECTED_CONFIG" | jq -r "$path // [] | sort | join(\",\")" 2>/dev/null + fi +} +count_present_names() { + local values="$1" + local expected_csv="$2" + echo "$values" | jq -r --arg expected_csv "$expected_csv" ' + ($expected_csv | split(",") | map(select(. != ""))) as $expected + | [.[].name] as $actual + | [$expected[] | . as $name | select($actual | index($name))] | length + ' 2>/dev/null || echo 0 +} +count_enabled_names() { + local values="$1" + local expected_csv="$2" + echo "$values" | jq -r --arg expected_csv "$expected_csv" ' + ($expected_csv | split(",") | map(select(. != ""))) as $expected + | [.[] | select(.enabled == true) | .name] as $actual + | [$expected[] | . as $name | select($actual | index($name))] | length + ' 2>/dev/null || echo 0 +} +knowledge_source_name() { + basename "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' +} + +API_VERSION="2026-01-01" +ARM_BASE="https://management.azure.com/subscriptions/${SUB}/resourceGroups/${RG}/providers/Microsoft.App/agents/${AGENT}" + +# Resolve agent endpoint +AGENT_JSON=$(az rest -m GET --url "${ARM_BASE}?api-version=${API_VERSION}" -o json 2>/dev/null || echo "{}") +ENDPOINT=$(echo "$AGENT_JSON" | jq -r '.properties.agentEndpoint // empty') +if [[ -z "$ENDPOINT" || "$ENDPOINT" == "null" ]]; then + echo "FAIL: Could not resolve agent endpoint for ${AGENT} in ${RG}" + exit 1 +fi + +TOKEN=$(az account get-access-token --resource https://azuresre.dev --query accessToken -o tsv 2>/dev/null) +if [[ -z "$TOKEN" ]]; then + echo "FAIL: Could not get data-plane token" + exit 1 +fi + +dp_get() { curl -sS "$ENDPOINT$1" -H "Authorization: Bearer $TOKEN" 2>/dev/null; } + +PASS=0 +FAIL=0 +RESULTS="" + +check() { + local name="$1" actual="$2" expected="$3" + if [[ "$expected" == "-" ]]; then + RESULTS="${RESULTS}\n ${name}|${actual}|—|✅" + PASS=$((PASS + 1)) + elif [[ "$actual" == "$expected" ]]; then + RESULTS="${RESULTS}\n ${name}|${actual}|${expected}|✅ PASS" + PASS=$((PASS + 1)) + else + RESULTS="${RESULTS}\n ${name}|${actual}|${expected}|❌ FAIL" + FAIL=$((FAIL + 1)) + fi +} + +echo "" +echo "═══════════════════════════════════════════════════" +echo " SRE Agent Verification: ${AGENT}" +echo " Endpoint: ${ENDPOINT}" +echo "═══════════════════════════════════════════════════" +echo "" + +# ── Agent properties ── +PROPS=$(echo "$AGENT_JSON" | jq -c '{ + accessLevel: .properties.actionConfiguration.accessLevel, + mode: .properties.actionConfiguration.mode, + upgradeChannel: .properties.upgradeChannel, + modelProvider: .properties.defaultModel.provider, + incidentPlatform: (.properties.incidentManagementConfiguration.type // "None"), + experimentalSettings: (.properties.experimentalSettings | keys | sort | join(",")) +}') +check "Agent exists" "yes" "yes" +check "Access level" "$(echo "$PROPS" | jq -r '.accessLevel')" "$(exp '.agent.accessLevel')" +check "Action mode" "$(echo "$PROPS" | jq -r '.mode')" "$(exp '.agent.actionMode')" +check "Upgrade channel" "$(echo "$PROPS" | jq -r '.upgradeChannel')" "$(exp '.agent.upgradeChannel')" +EXP_EXPERIMENTAL_SETTINGS="$(exp_list '.agent.experimentalSettings')" +if [[ -n "$EXP_EXPERIMENTAL_SETTINGS" ]]; then + EXP_EXPERIMENTAL_CT=$(exp '.agent.experimentalSettings | length' "-") + ACTUAL_EXPERIMENTAL_SETTINGS="$(echo "$PROPS" | jq -r '.experimentalSettings')" + ACTUAL_EXPERIMENTAL_VALUES="$(printf '%s\n' "$ACTUAL_EXPERIMENTAL_SETTINGS" | jq -R 'split(",") | map({name: .})')" + EXPERIMENTAL_PRESENT=$(count_present_names "$ACTUAL_EXPERIMENTAL_VALUES" "$EXP_EXPERIMENTAL_SETTINGS") + check "Experimental settings expected" "$EXPERIMENTAL_PRESENT" "$EXP_EXPERIMENTAL_CT" + RESULTS="${RESULTS}\n Experimental settings|${ACTUAL_EXPERIMENTAL_SETTINGS}|—|" +else + check "Experimental settings" "$(echo "$PROPS" | jq -r '.experimentalSettings')" "-" +fi +check "Model provider" "$(echo "$PROPS" | jq -r '.modelProvider')" "$(exp '.agent.defaultModelProvider')" +check "Incident platform" "$(echo "$PROPS" | jq -r '.incidentPlatform')" "$(exp '.agent.incidentPlatform')" + +# ── Onboarding discovery prerequisites ── +MANAGED_RESOURCE_GROUPS=$(echo "$AGENT_JSON" | jq -r '.properties.knowledgeGraphConfiguration.managedResources // [] | join(",")' 2>/dev/null) +EXPECTED_RG_ID="/subscriptions/${SUB}/resourceGroups/${RG}" +MANAGED_RESOURCE_GROUP_PRESENT=$(echo "$AGENT_JSON" | jq -r --arg expected "$EXPECTED_RG_ID" ' + [.properties.knowledgeGraphConfiguration.managedResources[]? | ascii_downcase] | index($expected | ascii_downcase) != null +' 2>/dev/null || echo false) +[[ "$MANAGED_RESOURCE_GROUP_PRESENT" == "true" ]] && check "Onboarding managed resource group" "present" "present" || check "Onboarding managed resource group" "missing" "present" +RESULTS="${RESULTS}\n Managed resource groups|${MANAGED_RESOURCE_GROUPS}|—|" + +ACTION_IDENTITY=$(echo "$AGENT_JSON" | jq -r '.properties.actionConfiguration.identity // empty' 2>/dev/null) +ACTION_PRINCIPAL_ID="" +if [[ "$(printf '%s' "$ACTION_IDENTITY" | tr '[:upper:]' '[:lower:]')" == "system" ]]; then + ACTION_PRINCIPAL_ID=$(echo "$AGENT_JSON" | jq -r '.identity.principalId // empty' 2>/dev/null) +elif [[ -n "$ACTION_IDENTITY" ]]; then + ACTION_PRINCIPAL_ID=$(echo "$AGENT_JSON" | jq -r --arg identity "$ACTION_IDENTITY" ' + .identity.userAssignedIdentities as $identities + | ($identities[$identity].principalId // ( + $identities + | to_entries[] + | select(.key | ascii_downcase == ($identity | ascii_downcase)) + | .value.principalId + ) // empty) + ' 2>/dev/null) +fi + +if [[ -n "$ACTION_PRINCIPAL_ID" ]]; then + EXPECTED_SUBSCRIPTION_ROLES="$(exp_list '.subscriptionRoleAssignments')" + if [[ -n "$EXPECTED_SUBSCRIPTION_ROLES" ]]; then + SUBSCRIPTION_SCOPE="/subscriptions/${SUB}" + SUBSCRIPTION_ROLE_ASSIGNMENTS=$(az role assignment list --assignee "$ACTION_PRINCIPAL_ID" --scope "$SUBSCRIPTION_SCOPE" -o json 2>/dev/null || echo "[]") + SUBSCRIPTION_ROLE_NAMES=$(echo "$SUBSCRIPTION_ROLE_ASSIGNMENTS" | jq -r '[.[].roleDefinitionName] | sort | join(",")' 2>/dev/null) + SUBSCRIPTION_ROLES_PRESENT=$(echo "$SUBSCRIPTION_ROLE_ASSIGNMENTS" | jq -r --arg expected_csv "$EXPECTED_SUBSCRIPTION_ROLES" ' + ($expected_csv | split(",") | map(select(. != ""))) as $expected + | [.[].roleDefinitionName] as $actual + | all($expected[]; $actual | index(.)) + ' 2>/dev/null || echo false) + check "Subscription identity RBAC" "$SUBSCRIPTION_ROLES_PRESENT" "true" + RESULTS="${RESULTS}\n Subscription identity roles (${SUBSCRIPTION_SCOPE})|${SUBSCRIPTION_ROLE_NAMES}|—|" + fi + + EXPECTED_TARGET_ROLES="Log Analytics Reader,Monitoring Reader,Reader" + if [[ "$(echo "$PROPS" | jq -r '.accessLevel')" == "High" ]]; then + EXPECTED_TARGET_ROLES="Contributor,Log Analytics Reader,Monitoring Reader,Reader" + fi + + MANAGED_SCOPE_CT=$(echo "$AGENT_JSON" | jq '.properties.knowledgeGraphConfiguration.managedResources // [] | length' 2>/dev/null || echo 0) + MANAGED_SCOPES_WITH_RBAC=0 + while IFS= read -r managed_scope; do + [[ -n "$managed_scope" ]] || continue + TARGET_ROLE_ASSIGNMENTS=$(az role assignment list --assignee "$ACTION_PRINCIPAL_ID" --scope "$managed_scope" -o json 2>/dev/null || echo "[]") + TARGET_ROLE_NAMES=$(echo "$TARGET_ROLE_ASSIGNMENTS" | jq -r '[.[].roleDefinitionName] | sort | join(",")' 2>/dev/null) + TARGET_ROLES_PRESENT=$(echo "$TARGET_ROLE_ASSIGNMENTS" | jq -r --arg expected_csv "$EXPECTED_TARGET_ROLES" ' + ($expected_csv | split(",") | map(select(. != ""))) as $expected + | [.[].roleDefinitionName] as $actual + | all($expected[]; $actual | index(.)) + ' 2>/dev/null || echo false) + if [[ "$TARGET_ROLES_PRESENT" == "true" ]]; then + MANAGED_SCOPES_WITH_RBAC=$((MANAGED_SCOPES_WITH_RBAC + 1)) + fi + RESULTS="${RESULTS}\n Onboarding identity roles (${managed_scope})|${TARGET_ROLE_NAMES}|—|" + done < <(echo "$AGENT_JSON" | jq -r '.properties.knowledgeGraphConfiguration.managedResources[]?' 2>/dev/null) + check "Onboarding identity RBAC" "$MANAGED_SCOPES_WITH_RBAC" "$MANAGED_SCOPE_CT" +else + check "Onboarding identity RBAC" "missing action identity" "present" +fi + +# ── Connectors ── +CONNECTORS=$(dp_get "/api/v2/extendedAgent/connectors") +CONNECTOR_VALUES=$(echo "$CONNECTORS" | jq -c '(.value // []) | if type == "array" then [.[] | select(.properties.dataConnectorType != "KnowledgeFile" and .properties.dataConnectorType != "KnowledgeText" and .properties.dataConnectorType != "KnowledgeWebPage")] else [] end' 2>/dev/null || echo "[]") +CONN_CT=$(echo "$CONNECTOR_VALUES" | jq 'length') +CONN_HEALTHY=$(echo "$CONNECTOR_VALUES" | jq '[.[] | select((.properties.provisioningState // "Succeeded") == "Succeeded" or (.properties.provisioningState // "Succeeded") == "Running")] | length') +CONN_ERRORED=$(echo "$CONNECTOR_VALUES" | jq '[.[] | select((.properties.provisioningState // "Succeeded") != "Succeeded" and (.properties.provisioningState // "Succeeded") != "Running")] | length') +EXP_CONN_CT=$(exp '.connectors | length' "-") +if [[ "$EXPECTED_CONFIG_HAS_CONNECTORS" != "true" && -n "$EXPECTED_CONNECTORS" ]]; then + EXP_CONN_CT=$(echo "$EXPECTED_CONNECTORS" | jq 'length') +fi +check "Connectors (total)" "$CONN_CT" "$EXP_CONN_CT" +check "Connectors (healthy)" "$CONN_HEALTHY" "$CONN_CT" +# Show errored connectors explicitly +if [[ "$CONN_ERRORED" -gt 0 ]]; then + ERRORED_LIST=$(echo "$CONNECTOR_VALUES" | jq -r '.[] | select((.properties.provisioningState // "Succeeded") != "Succeeded" and (.properties.provisioningState // "Succeeded") != "Running") | "\(.name) (\(.properties.dataConnectorType)): \(.properties.provisioningState)"') + RESULTS="${RESULTS}\n ⚠ Errored connectors|${ERRORED_LIST}||❌ FAIL" + FAIL=$((FAIL + 1)) +fi +CONN_NAMES=$(echo "$CONNECTOR_VALUES" | jq -r '.[].name' 2>/dev/null | sort | tr '\n' ', ' | sed 's/,$//') +EXP_CONN_NAMES=$(exp_list '.connectors[].name') +if [[ "$EXPECTED_CONFIG_HAS_CONNECTORS" != "true" && -n "$EXPECTED_CONNECTORS" ]]; then + EXP_CONN_NAMES=$(echo "$EXPECTED_CONNECTORS" | jq -r '[.[].name] | sort | join(",")') +fi +[[ -n "$EXP_CONN_NAMES" ]] && check "Connector names" "$CONN_NAMES" "$EXP_CONN_NAMES" || RESULTS="${RESULTS}\n Connector names|${CONN_NAMES}|—|" + +# ── Skills ── +SKILLS=$(dp_get "/api/v1/extendedAgent/skills") +SKILL_CT=$(echo "$SKILLS" | jq 'if type == "array" then length elif .value then (.value | length) else 0 end' 2>/dev/null || echo 0) +SKILL_NAMES=$(echo "$SKILLS" | jq -r '(if type == "array" then . elif .value then .value else [] end)[].name' 2>/dev/null | sort | tr '\n' ', ' | sed 's/,$//') +EXP_SKILL_CT=$(exp '.skills | length' "-") +EXP_SKILL_NAMES=$(exp_list '.skills') +check "Skills" "$SKILL_CT" "$EXP_SKILL_CT" +[[ -n "$EXP_SKILL_NAMES" ]] && check "Skill names" "$SKILL_NAMES" "$EXP_SKILL_NAMES" || RESULTS="${RESULTS}\n Skill names|${SKILL_NAMES}|—|" + +# ── Subagents ── +SUBAGENTS=$(dp_get "/api/v2/extendedAgent/agents") +SA_CT=$(echo "$SUBAGENTS" | jq '.value | length' 2>/dev/null || echo 0) +SA_NAMES=$(echo "$SUBAGENTS" | jq -r '.value[].name' 2>/dev/null | sort | tr '\n' ', ' | sed 's/,$//') +EXP_SA_CT=$(exp '.subagents | length' "-") +EXP_SA_NAMES=$(exp_list '.subagents') +check "Subagents" "$SA_CT" "$EXP_SA_CT" +[[ -n "$EXP_SA_NAMES" ]] && check "Subagent names" "$SA_NAMES" "$EXP_SA_NAMES" || RESULTS="${RESULTS}\n Subagent names|${SA_NAMES}|—|" + +EXP_TOOL_OWNER_NAMES=$(exp_list '.subagentRequirements.toolOwners') +if [[ -n "$EXP_TOOL_OWNER_NAMES" ]]; then + KNOWLEDGE_ONLY_TOOLS=$(exp_list '.subagentRequirements.knowledgeOnlyTools') + ACTUAL_TOOL_OWNER_NAMES=$(echo "$SUBAGENTS" | jq -r --arg knowledgeOnlyTools "$KNOWLEDGE_ONLY_TOOLS" ' + [.value[]? + | select(((((.properties.tools // []) + (.properties.systemTools // []) + (.properties.mcpTools // [])) - (($knowledgeOnlyTools | split(",") | map(select(length > 0))) // [])) | length) > 0) + | .name] | sort | join(",") + ' 2>/dev/null) + check "Operational tool-bearing agents" "$ACTUAL_TOOL_OWNER_NAMES" "$EXP_TOOL_OWNER_NAMES" +fi + +EXP_NO_TOOL_NAMES=$(exp_list '.subagentRequirements.noTools') +if [[ -n "$EXP_NO_TOOL_NAMES" ]]; then + KNOWLEDGE_ONLY_TOOLS=$(exp_list '.subagentRequirements.knowledgeOnlyTools') + ACTUAL_NO_TOOL_NAMES=$(echo "$SUBAGENTS" | jq -r --arg knowledgeOnlyTools "$KNOWLEDGE_ONLY_TOOLS" ' + [.value[]? + | select(((((.properties.tools // []) + (.properties.systemTools // []) + (.properties.mcpTools // [])) - (($knowledgeOnlyTools | split(",") | map(select(length > 0))) // [])) | length) == 0) + | .name] | sort | join(",") + ' 2>/dev/null) + check "Agents without operational tools" "$ACTUAL_NO_TOOL_NAMES" "$EXP_NO_TOOL_NAMES" +fi + +if [[ -n "$EXPECTED_CONFIG" ]]; then + EXP_TOOLS_BY_AGENT_NAMES=$(echo "$EXPECTED_CONFIG" | jq -r '.subagentRequirements.toolsByAgent // {} | keys | sort | join(",")' 2>/dev/null) + if [[ -n "$EXP_TOOLS_BY_AGENT_NAMES" ]]; then + IFS=',' read -r -a TOOLS_BY_AGENT_NAMES <<< "$EXP_TOOLS_BY_AGENT_NAMES" + for tools_agent in "${TOOLS_BY_AGENT_NAMES[@]}"; do + [[ -n "$tools_agent" ]] || continue + EXP_AGENT_TOOLS=$(echo "$EXPECTED_CONFIG" | jq -r --arg agent "$tools_agent" '.subagentRequirements.toolsByAgent[$agent] // [] | sort | join(",")' 2>/dev/null) + ACTUAL_AGENT_TOOLS=$(echo "$SUBAGENTS" | jq -r --arg agent "$tools_agent" ' + ([.value[]? | select(.name == $agent)][0].properties // {}) + | (((.tools // []) + (.systemTools // []) + (.mcpTools // [])) | sort | join(",")) + ' 2>/dev/null) + check "Tools: ${tools_agent}" "$ACTUAL_AGENT_TOOLS" "$EXP_AGENT_TOOLS" + done + fi +fi + +if [[ -n "$EXPECTED_CONFIG" ]]; then + EXP_HANDOFF_AGENT_NAMES=$(echo "$EXPECTED_CONFIG" | jq -r '.subagentRequirements.handoffs // {} | keys | sort | join(",")' 2>/dev/null) + if [[ -n "$EXP_HANDOFF_AGENT_NAMES" ]]; then + IFS=',' read -r -a HANDOFF_AGENTS <<< "$EXP_HANDOFF_AGENT_NAMES" + for handoff_agent in "${HANDOFF_AGENTS[@]}"; do + [[ -n "$handoff_agent" ]] || continue + EXP_HANDOFFS=$(echo "$EXPECTED_CONFIG" | jq -r --arg agent "$handoff_agent" '.subagentRequirements.handoffs[$agent] // [] | sort | join(",")' 2>/dev/null) + ACTUAL_HANDOFFS=$(echo "$SUBAGENTS" | jq -r --arg agent "$handoff_agent" '[.value[]? | select(.name == $agent)][0].properties.handoffs // [] | sort | join(",")' 2>/dev/null) + check "Handoffs: ${handoff_agent}" "$ACTUAL_HANDOFFS" "$EXP_HANDOFFS" + done + fi + + EXP_NO_HANDOFF_NAMES=$(exp_list '.subagentRequirements.noHandoffs') + if [[ -n "$EXP_NO_HANDOFF_NAMES" ]]; then + ACTUAL_NO_HANDOFF_NAMES=$(echo "$SUBAGENTS" | jq -r ' + [.value[]? | select(((.properties.handoffs // []) | length) == 0) | .name] | sort | join(",") + ' 2>/dev/null) + check "Agents without handoffs" "$ACTUAL_NO_HANDOFF_NAMES" "$EXP_NO_HANDOFF_NAMES" + fi +fi + +# ── Built-in tool configuration ── +EXP_BUILT_IN_TOOL_NAMES=$(exp_list '.builtInTools.enabled') +if [[ -n "$EXP_BUILT_IN_TOOL_NAMES" ]]; then + AGENT_TOOLS=$(dp_get "/api/v2/agent/tools") + AGENT_TOOL_VALUES=$(echo "$AGENT_TOOLS" | jq -c '.data // []' 2>/dev/null || echo "[]") + EXP_BUILT_IN_TOOL_CT=$(exp '.builtInTools.enabled | length' "-") + BUILT_IN_ENABLED_PRESENT=$(count_enabled_names "$AGENT_TOOL_VALUES" "$EXP_BUILT_IN_TOOL_NAMES") + check "Built-in tools enabled" "$BUILT_IN_ENABLED_PRESENT" "$EXP_BUILT_IN_TOOL_CT" + + EXPECTED_LOG_QUERY_CT=$(exp '.builtInTools.categories["Log Query"]' "-") + if [[ "$EXPECTED_LOG_QUERY_CT" != "-" ]]; then + ACTUAL_LOG_QUERY_CT=$(echo "$AGENT_TOOL_VALUES" | jq '[.[] | select(.category == "Log Query" and .enabled == true)] | length' 2>/dev/null || echo 0) + check "Log Query tools enabled" "$ACTUAL_LOG_QUERY_CT" "$EXPECTED_LOG_QUERY_CT" + fi + + EXPECTED_VISUALIZATION_CT=$(exp '.builtInTools.categories.Visualization' "-") + if [[ "$EXPECTED_VISUALIZATION_CT" != "-" ]]; then + ACTUAL_VISUALIZATION_CT=$(echo "$AGENT_TOOL_VALUES" | jq '[.[] | select(.category == "Visualization" and .enabled == true)] | length' 2>/dev/null || echo 0) + check "Visualization tools enabled" "$ACTUAL_VISUALIZATION_CT" "$EXPECTED_VISUALIZATION_CT" + fi +fi + +# ── Hooks ── +HOOKS=$(dp_get "/api/v2/extendedAgent/hooks") +HOOK_CT=$(echo "$HOOKS" | jq '.value // . | if type == "array" then length else 0 end' 2>/dev/null || echo 0) +HOOK_NAMES=$(echo "$HOOKS" | jq -r '(.value // .)[].name' 2>/dev/null | sort | tr '\n' ', ' | sed 's/,$//') +EXP_HOOK_CT=$(exp '.hooks | length' "-") +EXP_HOOK_NAMES=$(exp_list '.hooks') +check "Hooks" "$HOOK_CT" "$EXP_HOOK_CT" +[[ -n "$EXP_HOOK_NAMES" ]] && check "Hook names" "$HOOK_NAMES" "$EXP_HOOK_NAMES" || RESULTS="${RESULTS}\n Hook names|${HOOK_NAMES}|—|" + +# ── Common Prompts ── +PROMPTS=$(dp_get "/api/v2/extendedAgent/commonprompts") +PROMPT_CT=$(echo "$PROMPTS" | jq '.value // . | if type == "array" then length else 0 end' 2>/dev/null || echo 0) +PROMPT_NAMES=$(echo "$PROMPTS" | jq -r '(.value // .)[].name' 2>/dev/null | sort | tr '\n' ', ' | sed 's/,$//') +EXP_PROMPT_CT=$(exp '.commonPrompts | length' "-") +EXP_PROMPT_NAMES=$(exp_list '.commonPrompts') +check "Common Prompts" "$PROMPT_CT" "$EXP_PROMPT_CT" +[[ -n "$EXP_PROMPT_NAMES" ]] && check "Prompt names" "$PROMPT_NAMES" "$EXP_PROMPT_NAMES" || RESULTS="${RESULTS}\n Prompt names|${PROMPT_NAMES}|—|" + +# ── Scheduled Tasks ── +TASKS=$(dp_get "/api/v1/scheduledtasks") +TASK_CT=$(echo "$TASKS" | jq 'if type == "array" then length else 0 end' 2>/dev/null || echo 0) +TASK_UNIQUE=$(echo "$TASKS" | jq '[.[].name] | unique | length' 2>/dev/null || echo 0) +TASK_NAMES=$(echo "$TASKS" | jq -r '[.[].name] | unique | sort | join(",")' 2>/dev/null) +EXP_TASK_CT=$(exp '.scheduledTasks | length' "-") +EXP_TASK_NAMES=$(exp_list '.scheduledTasks') +check "Scheduled Tasks (unique)" "$TASK_UNIQUE" "$EXP_TASK_CT" +[[ -n "$EXP_TASK_NAMES" ]] && check "Task names" "$TASK_NAMES" "$EXP_TASK_NAMES" || true +if [[ "$TASK_CT" != "$TASK_UNIQUE" ]]; then + RESULTS="${RESULTS}\n Scheduled task duplicates|${TASK_CT} total, ${TASK_UNIQUE} unique|0 duplicates|❌ FAIL" + FAIL=$((FAIL + 1)) +fi +EXP_TASK_OWNER=$(exp '.scheduledTaskRequirements.ownerAgent' "") +if [[ -n "$EXP_TASK_OWNER" ]]; then + TASKS_WITH_EXPECTED_OWNER=$(echo "$TASKS" | jq -r --arg owner "$EXP_TASK_OWNER" ' + [.[]? | select((.agent // .properties.agent // .spec.agent // .agentName // .properties.agentName // .properties.targetAgent // "") == $owner)] | length + ' 2>/dev/null || echo 0) + check "Scheduled task owner" "$TASKS_WITH_EXPECTED_OWNER" "$TASK_CT" + TASK_OWNER_MISMATCHES=$(echo "$TASKS" | jq -r --arg owner "$EXP_TASK_OWNER" ' + [.[]? + | (.agent // .properties.agent // .spec.agent // .agentName // .properties.agentName // .properties.targetAgent // "missing") as $actual + | select($actual != $owner) + | "\(.name // .metadata.name // .id // "unnamed") -> \($actual)" + ] | join("; ") + ' 2>/dev/null) + if [[ -n "$TASK_OWNER_MISMATCHES" ]]; then + RESULTS="${RESULTS}\n Scheduled task owner mismatches|${TASK_OWNER_MISMATCHES}|${EXP_TASK_OWNER}|❌ FAIL" + FAIL=$((FAIL + 1)) + fi +fi +if [[ -n "$EXPECTED_CONFIG" ]]; then + EXP_TASK_PROMPT_REQUIRED=$(echo "$EXPECTED_CONFIG" | jq -c '.scheduledTaskRequirements.promptRequiredText // []' 2>/dev/null || echo "[]") + EXP_TASK_PROMPT_REQUIRED_CT=$(echo "$EXP_TASK_PROMPT_REQUIRED" | jq 'length' 2>/dev/null || echo 0) + if [[ "$EXP_TASK_PROMPT_REQUIRED_CT" -gt 0 ]]; then + TASKS_WITH_REQUIRED_PROMPT=$(echo "$TASKS" | jq -r --argjson required "$EXP_TASK_PROMPT_REQUIRED" ' + [.[]? + | (.agentPrompt // .agent_prompt // .prompt // .properties.agentPrompt // .properties.agent_prompt // .properties.prompt // .spec.agentPrompt // .spec.agent_prompt // .spec.prompt // "") as $prompt + | select(([$required[] as $needle | select(($prompt | contains($needle)) | not)] | length) == 0) + ] | length + ' 2>/dev/null || echo 0) + check "Scheduled task prompt required text" "$TASKS_WITH_REQUIRED_PROMPT" "$TASK_CT" + TASK_REQUIRED_PROMPT_MISMATCHES=$(echo "$TASKS" | jq -r --argjson required "$EXP_TASK_PROMPT_REQUIRED" ' + [.[]? + | (.name // .metadata.name // .id // "unnamed") as $name + | (.agentPrompt // .agent_prompt // .prompt // .properties.agentPrompt // .properties.agent_prompt // .properties.prompt // .spec.agentPrompt // .spec.agent_prompt // .spec.prompt // "") as $prompt + | select(([$required[] as $needle | select(($prompt | contains($needle)) | not)] | length) > 0) + | $name + ] | join(",") + ' 2>/dev/null) + if [[ -n "$TASK_REQUIRED_PROMPT_MISMATCHES" ]]; then + RESULTS="${RESULTS}\n Scheduled task prompt missing routing guard|${TASK_REQUIRED_PROMPT_MISMATCHES}|all tasks|❌ FAIL" + FAIL=$((FAIL + 1)) + fi + fi + + EXP_TASK_PROMPT_FORBIDDEN=$(echo "$EXPECTED_CONFIG" | jq -c '.scheduledTaskRequirements.promptForbiddenText // []' 2>/dev/null || echo "[]") + EXP_TASK_PROMPT_FORBIDDEN_CT=$(echo "$EXP_TASK_PROMPT_FORBIDDEN" | jq 'length' 2>/dev/null || echo 0) + if [[ "$EXP_TASK_PROMPT_FORBIDDEN_CT" -gt 0 ]]; then + TASKS_WITH_FORBIDDEN_PROMPT=$(echo "$TASKS" | jq -r --argjson forbidden "$EXP_TASK_PROMPT_FORBIDDEN" ' + [.[]? + | (.agentPrompt // .agent_prompt // .prompt // .properties.agentPrompt // .properties.agent_prompt // .properties.prompt // .spec.agentPrompt // .spec.agent_prompt // .spec.prompt // "") as $prompt + | select(([$forbidden[] as $needle | select($prompt | contains($needle))] | length) > 0) + ] | length + ' 2>/dev/null || echo 0) + check "Scheduled task prompt forbidden text" "$TASKS_WITH_FORBIDDEN_PROMPT" "0" + TASK_FORBIDDEN_PROMPT_MISMATCHES=$(echo "$TASKS" | jq -r --argjson forbidden "$EXP_TASK_PROMPT_FORBIDDEN" ' + [.[]? + | (.name // .metadata.name // .id // "unnamed") as $name + | (.agentPrompt // .agent_prompt // .prompt // .properties.agentPrompt // .properties.agent_prompt // .properties.prompt // .spec.agentPrompt // .spec.agent_prompt // .spec.prompt // "") as $prompt + | [ $forbidden[] as $needle | select($prompt | contains($needle)) | $needle ] as $matches + | select(($matches | length) > 0) + | "\($name): \($matches | join("; "))" + ] | join(" | ") + ' 2>/dev/null) + if [[ -n "$TASK_FORBIDDEN_PROMPT_MISMATCHES" ]]; then + RESULTS="${RESULTS}\n Scheduled task prompt forbidden matches|${TASK_FORBIDDEN_PROMPT_MISMATCHES}|none|❌ FAIL" + FAIL=$((FAIL + 1)) + fi + fi +fi + +# ── Knowledge sources ── +DATA_CONNECTORS=$(dp_get "/api/v2/extendedAgent/connectors") +KNOWLEDGE_SOURCE_VALUES=$(echo "$DATA_CONNECTORS" | jq -c '[.value[]? | select(.properties.dataConnectorType == "KnowledgeFile" or .properties.dataConnectorType == "KnowledgeText" or .properties.dataConnectorType == "KnowledgeWebPage")]' 2>/dev/null || echo "[]") +KS_CT=$(echo "$KNOWLEDGE_SOURCE_VALUES" | jq 'length') +KS_NAMES=$(echo "$KNOWLEDGE_SOURCE_VALUES" | jq -r '[.[].name] | sort | join(",")' 2>/dev/null) +EXP_KS_CT=$(exp '.knowledgeSources | length' "-") +EXP_KS_NAMES=$(exp_list '.knowledgeSources') +check "Knowledge sources total" "$KS_CT" "-" +if [[ -n "$EXP_KS_NAMES" && "$EXP_KS_CT" != "-" ]]; then + KS_EXPECTED_PRESENT=0 + KS_EXPECTED_INDEXED=0 + KS_EXPECTED_UNINDEXED="" + IFS=',' read -r -a EXPECTED_KNOWLEDGE_DOCS <<< "$EXP_KS_NAMES" + for doc in "${EXPECTED_KNOWLEDGE_DOCS[@]}"; do + [[ -n "$doc" ]] || continue + source_name="$(knowledge_source_name "$doc")" + present=$(echo "$KNOWLEDGE_SOURCE_VALUES" | jq -r --arg name "$source_name" --arg display "$doc" ' + [ .[] | select(.name == $name or .properties.extendedProperties.displayName == $display) ] | length + ' 2>/dev/null || echo 0) + if [[ "$present" -gt 0 ]]; then + KS_EXPECTED_PRESENT=$((KS_EXPECTED_PRESENT + 1)) + detail=$(dp_get "/api/v2/extendedAgent/connectors/${source_name}") + indexed=$(echo "$detail" | jq -r '.properties.extendedProperties.createdAt // empty' 2>/dev/null || true) + if [[ -n "$indexed" ]]; then + KS_EXPECTED_INDEXED=$((KS_EXPECTED_INDEXED + 1)) + else + KS_EXPECTED_UNINDEXED="${KS_EXPECTED_UNINDEXED}${KS_EXPECTED_UNINDEXED:+; }${source_name}" + fi + fi + done + check "Knowledge sources expected" "$KS_EXPECTED_PRESENT" "$EXP_KS_CT" + check "Knowledge sources indexed" "$KS_EXPECTED_INDEXED" "$EXP_KS_CT" + if [[ -n "$KS_EXPECTED_UNINDEXED" ]]; then + RESULTS="${RESULTS}\n ⚠️ Unindexed knowledge sources|${KS_EXPECTED_UNINDEXED}|—|❌ FAIL" + FAIL=$((FAIL + 1)) + fi +fi +RESULTS="${RESULTS}\n Knowledge source names|${KS_NAMES}|—|" + +# ── Response Plans (Incident Filters) ── +FILTERS=$(dp_get "/api/v1/incidentPlayground/filters") +FILTER_CT=$(echo "$FILTERS" | jq 'if type == "array" then length else 0 end' 2>/dev/null || echo 0) +FILTER_NAMES=$(echo "$FILTERS" | jq -r '.[].id' 2>/dev/null | sort | tr '\n' ', ' | sed 's/,$//') +EXP_FILTER_CT=$(exp '.responsePlans | length' "-") +EXP_FILTER_NAMES=$(exp_list '.responsePlans[].name') +check "Response Plans" "$FILTER_CT" "$EXP_FILTER_CT" +[[ -n "$EXP_FILTER_NAMES" ]] && check "Filter names" "$FILTER_NAMES" "$EXP_FILTER_NAMES" || RESULTS="${RESULTS}\n Filter names|${FILTER_NAMES}|—|" + +# ── GitHub ── +GH_STATUS=$(dp_get "/api/v1/Github/auth/status") +GH_CONFIGURED=$(echo "$GH_STATUS" | jq -r '.isConfigured // .hosts[0].isConfigured // false' 2>/dev/null) +check "GitHub OAuth" "$GH_CONFIGURED" "-" + +# ── Repos ── +REPOS=$(dp_get "/api/v2/repos") +REPO_CT=$(echo "$REPOS" | jq '.value // . | if type == "array" then length else 0 end' 2>/dev/null || echo 0) +REPO_NAMES=$(echo "$REPOS" | jq -r '(.value // .)[].name' 2>/dev/null | sort | tr '\n' ', ' | sed 's/,$//') +EXP_REPO_CT=$(exp '.repos | length' "-") +EXP_REPO_NAMES=$(exp_list '.repos') +check "Repos" "$REPO_CT" "$EXP_REPO_CT" +[[ -n "$EXP_REPO_NAMES" ]] && check "Repo names" "$REPO_NAMES" "$EXP_REPO_NAMES" || RESULTS="${RESULTS}\n Repo names|${REPO_NAMES}|—|" + +# ── Print results ── +echo "" +printf " %-25s %-10s %-10s %s\n" "Check" "Actual" "Expected" "Result" +printf " %-25s %-10s %-10s %s\n" "─────────────────────────" "──────────" "──────────" "──────" +echo -e "$RESULTS" | while IFS='|' read -r name actual expected result; do + [[ -z "$name" ]] && continue + printf " %-25s %-10s %-10s %s\n" "$name" "$actual" "$expected" "$result" +done + +echo "" +echo "═══════════════════════════════════════════════════" +echo " Results: ${PASS} passed, ${FAIL} failed" +echo " Portal: https://sre.azure.com/#/agent/${SUB}/${RG}/${AGENT}" +echo "═══════════════════════════════════════════════════" +echo "" + +[[ "$FAIL" -gt 0 ]] && exit 1 +exit 0 diff --git a/src/templates/sre-agent/recipes/finops-hub/README.md b/src/templates/sre-agent/recipes/finops-hub/README.md new file mode 100644 index 000000000..4af60119b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/README.md @@ -0,0 +1,33 @@ +# FinOps Hub SRE Agent recipe + +Deploys the FinOps Toolkit SRE Agent using the canonical Microsoft SRE Agent recipe layout. + +## Contents + +- 5 custom agents in `config/subagents/`: `finops-practitioner` plus four delegated subagents +- 3 tool-bearing delegated subagents: `azure-capacity-manager`, `ftk-database-query`, and `ftk-hubs-agent`; `chief-financial-officer` has no tools +- 3 skills in `config/skills/` +- 50 tools: 37 generated Kusto tools from `src/queries/catalog/` plus 13 Python tools in `config/tools/` +- 9 platform tool overrides in `config/built-in-tools.json` +- 19 scheduled tasks in `automations/scheduled-tasks/`, all owned by `finops-practitioner` +- 1 connector in `connectors.json`: FinOps Hub Kusto +- 6 uploaded KnowledgeFile sources: files in `knowledge/` plus `../../../claude-plugin/output-styles/ftk-output-style.md` + +## Framework mapping + +The authoritative FinOps Framework mapping for this recipe is [../../CATALOG.md](../../CATALOG.md). It maps the toolkit and SRE Agent to FinOps domains, capabilities, personas, principles, phases, agent ownership, tool ownership, scheduled-task ownership, and required handoffs. Keep this recipe aligned to that catalog when changing subagents, tools, skills, knowledge sources, or scheduled tasks. + +## Deploy + +```bash +bash ../../bin/deploy.sh \ + --recipe . \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] +``` + +The deployment uses the explicit subscription passed with `--subscription`. Real deployments resolve the Kusto cluster resource ID from `--cluster-uri` when possible. Pass `--cluster-resource-id` when the cluster cannot be resolved automatically or when running `--dry-run`. diff --git a/src/templates/sre-agent/recipes/finops-hub/agent.json b/src/templates/sre-agent/recipes/finops-hub/agent.json new file mode 100644 index 000000000..a2a90bbe8 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/agent.json @@ -0,0 +1,21 @@ +{ + "access": { + "accessLevel": "High", + "actionMode": "Autonomous" + }, + "upgradeChannel": "Preview", + "defaultModelProvider": "MicrosoftFoundry", + "defaultModelName": "Automatic", + "monthlyAgentUnitLimit": 10000, + "tags": { + "finops-toolkit": "sre-agent", + "source": "microsoft-finops-toolkit" + }, + "toggles": { + "enableWebhookBridge": false + }, + "experimentalSettings": { + "EnableSandboxGroup": true, + "EnableWorkspaceTools": true + } +} diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml new file mode 100644 index 000000000..2f29f7102 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml @@ -0,0 +1,80 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: AdvisorSuppressionReview +spec: + name: AdvisorSuppressionReview + description: Monthly review of active Advisor recommendation suppressions for stale or expired decisions + cron_expression: 0 9 1 * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Advisor Suppression Review + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to Advisor suppression governance, prior suppression decisions, and exception review cadence. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Load your relevant FinOps practitioner skill. Do not call Python, Kusto, Resource Graph, Azure CLI, visualization, Teams, or Outlook tools directly; delegate tool work to the specialist subagent named in the routing guard. + + + ## Specialist tools to request + + + Specialist tools use their configured authentication and the agent system-managed identity where required. + + + - `ftk-hubs-agent`: Run `resource-graph-query` with `query`, optional `subscription_ids` to find active Advisor recommendation suppressions, suppression metadata, owners, expiration dates, and related resources. + + + ## 1. Establish suppression inventory + + + Ask `ftk-hubs-agent` to run `resource-graph-query` to find active Advisor recommendation suppressions across in-scope subscriptions. Capture suppression name, subscription, resource, recommendation category, owner metadata, creation date, expiration date, and justification where available. + + + ## 2. Classify suppression status + + + Classify suppressions as active and current, expired, stale without expiration, missing owner, missing justification, or no longer linked to an active recommendation or resource. + + + ## 3. Review stale or expired suppressions + + + Flag suppressions that should be reconsidered because they are expired, older than the governance review window, missing justification, suppressing high-value recommendations, or attached to resources that changed materially. + + + ## 4. Recommend actions + + + Recommend renew, remove, update justification, assign owner, or validate recommendation state for each flagged suppression. Prioritize suppressions that hide optimization, reliability, or security recommendations. + + + ## Report format + + + Produce a markdown report with an executive summary, an active suppression table, a stale or expired suppression table, missing metadata findings, and recommended owner actions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, recommendation savings amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a suppression status chart and a stale suppression age chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' + diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/ai-workload-cost-analysis.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/ai-workload-cost-analysis.yaml new file mode 100644 index 000000000..2d24fdb3d --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/ai-workload-cost-analysis.yaml @@ -0,0 +1,194 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: AIWorkloadCostAnalysis +spec: + name: AIWorkloadCostAnalysis + description: Monthly AI workload cost analysis — token economics, model efficiency, and cost allocation for Azure OpenAI + cron_expression: 0 10 1 * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# AI Workload Cost Analysis + + + ## Phase 0: Preparation + + + Before starting any analysis, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Load your finops-toolkit and azure-cost-management skills. Lead the analysis as the FinOps practitioner. Delegate all FinOps Hub Kusto evidence collection to `ftk-database-query`, delegate GPU and regional capacity checks to `azure-capacity-manager`, and consult `chief-financial-officer` for executive unit-economics and investment framing. + + + Azure OpenAI charges based on token usage — a fundamentally different cost model from traditional compute. This analysis tracks token economics, model efficiency, and AI cost allocation aligned with + the FinOps Foundation AI Working Group guidance and FOCUS specification. + + ## Specialist evidence requests for this task + + Do not run Kusto tools directly. Ask `ftk-database-query` to run AI cost and token tools, and ask `azure-capacity-manager` to run GPU and regional capacity checks. Ask `ftk-hubs-agent` to run `resource-graph-query` only for Azure resource inventory and governance context. + + - `ftk-hubs-agent`: Run `resource-graph-query` with query and subscriptions to execute Azure Resource Graph KQL for AI resource discovery + - `azure-capacity-manager`: Run `vm-quota-usage` with subscription_id and location to get VM family quota usage with at-risk thresholds for GPU capacity + - `ftk-database-query`: Run `ai-token-usage-breakdown`, `ai-daily-trend`, and `ai-model-cost-comparison` as the FinOps KPI-backed token consumption evidence set + + + ## FOCUS Alignment + + + AI cost data uses these FOCUS columns: + + - ConsumedQuantity = token count + + - ConsumedUnit = tokens + + - x_SkuMeterCategory = Azure OpenAI + + - x_SkuMeterSubcategory = model version + direction (e.g., "gpt 4o 0513 Input global Tokens") + + - Unit economics = EffectiveCost / ConsumedQuantity + + + ## Phase 1: Token Economics + + + This phase covers the `Token Consumption Metrics` KPI in `src/queries/KPI.md`. Keep `ai-token-usage-breakdown`, `ai-daily-trend`, and `ai-model-cost-comparison` results together as the AI unit-economics KPI evidence set. + + + ### 1.1 Token Usage Breakdown + + Ask `ftk-database-query` to run `ai-token-usage-breakdown` with startDate=startofmonth(ago(30d)), endDate=startofmonth(now()). Record per-model, per-direction (input/output): + + - Total tokens consumed + + - Effective cost + + - Unit cost per token + + - Cost per 1K tokens + + + ### 1.2 Model Cost Comparison + + Ask `ftk-database-query` to run `ai-model-cost-comparison` with the same date range. Compare cost per 1K tokens across model versions. Identify: + + - Which models are most expensive per token + + - Which models have the best discount (list vs effective) + + - Opportunities to switch to cheaper models for equivalent tasks + + + ### 1.3 Daily Trend + + Ask `ftk-database-query` to run `ai-daily-trend` with startDate=ago(30d). Look for: + + - Usage pattern (weekday vs weekend) + + - Cost spikes (any day > 2x the 7-day rolling average) + + - Growth trajectory (are AI costs accelerating?) + + - If spikes detected, use deep investigation to hypothesize causes + + + ### 1.4 Cost Allocation + + Ask `ftk-hubs-agent` to run `resource-graph-query` to discover Azure OpenAI, AI Foundry, Machine Learning, and GPU compute resources, then ask `ftk-database-query` to run `ai-cost-by-application` with the same date range. Break down by: + + - Application tag — which apps consume the most tokens? + + - Team/CostCenter — who should be charged? + + - Environment — production vs dev/test ratio + + - ResourceName — which Azure OpenAI deployments are driving cost? + + + **Checkpoint:** Token economics collected. Proceed to month-over-month comparison. + + + ## Phase 2: Month-over-Month AI Analysis + + + ### 2.1 Prior Month Comparison + + Ask `ftk-database-query` to run `ai-token-usage-breakdown` again with the PRIOR month (startDate=startofmonth(ago(60d)), endDate=startofmonth(ago(30d))). Compare: + + - Token volume change (% growth) + + - Cost change (% growth) + + - Unit cost change (are we getting cheaper or more expensive per token?) + + - Model mix shift (are we using more expensive models?) + + + ### 2.2 Input/Output Ratio + + Calculate the input-to-output token ratio for each model. Long prompts with short responses indicate potential prompt optimization. Flag any model where input tokens > 10x output tokens. + + + ## Phase 3: Optimization Recommendations + + + ### 3.1 Model Substitution + + For each high-cost model, check if a cheaper model could handle the same workload. Reference the model cost comparison data. Calculate potential savings from model downgrades. + + + ### 3.2 Prompt Engineering Impact + + If input tokens are disproportionately high, recommend prompt optimization. Shorter context windows = fewer tokens = lower cost. + + + ### 3.3 Environment Rightsizing + + If dev/test environments are using production-tier models, recommend cheaper models for non-production. + + + ### 3.4 Commitment Coverage + + Check if Azure OpenAI Provisioned Throughput Units (PTUs) would be cheaper than pay-as-you-go for high-volume workloads. + + Ask `azure-capacity-manager` to run `vm-quota-usage` in GPU-capable regions to identify GPU quota constraints for AI workloads that rely on VM-hosted inference or training. + + + ## Phase 4: Report + + + Format as a professional AI cost report: + + - Executive summary with total AI spend, token volume, and cost per 1K tokens + + - Model efficiency table (cost per 1K tokens by model, input vs output) + + - Application allocation table (cost by app/team/environment) + + - Month-over-month trend chart description + + - Top 3 optimization recommendations with dollar savings estimates + + - FOCUS compliance note (all metrics use standard FOCUS columns) + + + Use 🤖 for AI metrics, 💰 for savings, 📊 for trends, 🎯 for recommendations. + + + Do not stop until the report is complete. + + + ## Phase 5: Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (financial results only):** Post the final AI workload cost report to our Teams channel. Include the executive summary, token economics, model efficiency table, and top optimization recommendations. Do not post intermediate results — only the completed report. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — model availability changes, query patterns for AI billing data, FOCUS column mappings discovered, tool errors encountered. Never save financial figures, cost amounts, token costs, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml new file mode 100644 index 000000000..88899f971 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml @@ -0,0 +1,84 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: AlertCoverageAudit +spec: + name: AlertCoverageAudit + description: Monthly audit of cost anomaly alert coverage across active subscriptions + cron_expression: 0 8 16 * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Alert Coverage Audit + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to anomaly detection standards, monitoring ownership notes, and prior alert coverage gaps. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Load your relevant FinOps practitioner skill. Do not call Python, Kusto, Resource Graph, Azure CLI, visualization, Teams, or Outlook tools directly; delegate tool work to the specialist subagent named in the routing guard. + + + ## Specialist tools to request + + + Specialist tools use their configured authentication and the agent system-managed identity where required. + + + - `ftk-hubs-agent`: Run `resource-graph-query` with `query`, optional `subscription_ids` to find active subscriptions, cost anomaly alerts, action groups, alert rules, and monitoring metadata. + + - `ftk-database-query`: Run `anomaly-detection-rate` and `anomaly-variance-total` for Kusto-backed Anomaly Management KPI context. + + + ## 1. Establish subscription inventory + + + Ask `ftk-hubs-agent` to run `resource-graph-query` to identify active subscriptions and ownership metadata. Exclude subscriptions explicitly documented as out of scope. + + + ## 2. Find anomaly alert coverage + + + Ask `ftk-hubs-agent` to run `resource-graph-query` to detect cost anomaly alerts, scheduled query rules, metric alerts, action groups, and any documented alerting resources that implement cost anomaly detection. + + + ## 3. Identify missing anomaly detection + + + Compare active subscriptions with detected anomaly alert coverage. Flag subscriptions missing anomaly detection, subscriptions with disabled or incomplete alerts, and subscriptions missing notification routing. + + Ask `ftk-database-query` to run `anomaly-detection-rate` and `anomaly-variance-total` for the same monitoring period. Use those outputs to distinguish missing alert coverage from low observed anomaly volume, and cite the KPI tool result when anomaly evidence is unavailable. + + + ## 4. Recommend remediation + + + Recommend alert deployment, action group updates, ownership remediation, or follow-up validation. Prioritize production and business-critical subscriptions. + + + ## Report format + + + Produce a markdown report with an executive summary, an alert coverage table, a missing anomaly detection table, disabled or incomplete alert findings, and recommended remediation actions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, alert threshold amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum an anomaly alert coverage chart and a missing alert count by owner or environment chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' + diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml new file mode 100644 index 000000000..2835091fe --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml @@ -0,0 +1,84 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: BenefitRecommendationReview +spec: + name: BenefitRecommendationReview + description: Weekly executive review of reservation and savings plan recommendations + cron_expression: 0 8 * * 5 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Benefit Recommendation Review + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to commitment discount strategy, reservation governance, savings plan policy, and prior recommendation review notes. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Load the FinOps toolkit and Azure Cost Management skills. Lead this as the FinOps practitioner. Ask `azure-capacity-manager` to run `benefit-recommendations` for current Cost Management recommendations, delegate any Kusto-backed recommendation, utilization, transaction, or savings evidence to `ftk-database-query`, and consult `chief-financial-officer` for approval framing, commitment risk, and executive decision language. + + + ## Specialist tools to request + + + Specialist tools use their configured authentication and the agent system-managed identity where required. + + + - `azure-capacity-manager`: Run `benefit-recommendations` with `billing_scope`, optional `lookback_period`, optional `term` to retrieve reservation and savings plan recommendations. + + - `ftk-database-query`: Run `reservation-recommendation-breakdown`, `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, `macc-consumption-vs-commitment`, and `savings-summary-report` for Kusto-backed Rate Optimization and commitment KPI evidence. + + + ## 1. Establish billing scope + + + Identify the billing scope or subscription scope from knowledge base guidance. If multiple scopes are documented, run the review for each and keep results separated by scope. + + + ## 2. Retrieve latest recommendations + + + Ask `azure-capacity-manager` to run `benefit-recommendations` with `billing_scope`, `lookback_period`, `term`. Review both reservation and savings plan recommendation types where available. + + + ## 3. Summarize savings opportunity + + + Summarize estimated savings, recommended cost, term, break-even information, and recommendation count. Separate recommendations by type and highlight assumptions or missing fields in the source payload. + + Ask `ftk-database-query` to run `reservation-recommendation-breakdown`, `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, `macc-consumption-vs-commitment`, and `savings-summary-report`. Use these outputs to reconcile external benefit recommendations against realized commitment utilization, commitment waste, compute coverage, MACC drawdown, and effective savings rate. + + + ## 4. Consult finance and recommend executive actions + + + Consult `chief-financial-officer` for the financial decision frame, then recommend which opportunities need purchase approval, deeper workload validation, commitment adjustment, or no action. Highlight governance risks such as over-commitment, insufficient utilization history, or missing owner accountability. + + + ## Report format + + + Produce a markdown report with an executive summary, a reservation recommendation table, a savings plan recommendation table, total potential savings summary, key risks, and recommended executive decisions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, savings amounts, cost amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a savings by recommendation type chart and a cost versus savings chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' + diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml new file mode 100644 index 000000000..50a856902 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml @@ -0,0 +1,80 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: BudgetCoverageAudit +spec: + name: BudgetCoverageAudit + description: Monthly audit of subscription budget coverage and missing budget controls + cron_expression: 0 8 15 * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Budget Coverage Audit + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to budgeting standards, subscription ownership notes, and prior missing-budget findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Load your relevant FinOps practitioner skill. Do not call Python, Kusto, Resource Graph, Azure CLI, visualization, Teams, or Outlook tools directly; delegate tool work to the specialist subagent named in the routing guard. + + + ## Specialist tools to request + + + Specialist tools use their configured authentication and the agent system-managed identity where required. + + + - `ftk-hubs-agent`: Run `resource-graph-query` with `query`, optional `subscription_ids` to find subscriptions, budget resources, tags, ownership metadata, and budget coverage gaps. + + + ## 1. Establish subscription inventory + + + Ask `ftk-hubs-agent` to run `resource-graph-query` to identify active subscriptions and subscription metadata needed for ownership, environment, cost center, or portfolio grouping. Exclude subscriptions that are documented as out of scope. + + + ## 2. Find configured budgets + + + Ask `ftk-hubs-agent` to run `resource-graph-query` against budget resource types and related policy or governance metadata. Identify subscription-level budgets and any documented management-group or shared budget coverage that should count as coverage. + + + ## 3. Identify coverage gaps + + + Compare active subscriptions with detected budget coverage. Report subscriptions missing budgets, subscriptions with ambiguous budget scope, and subscriptions where owner metadata is missing or incomplete. + + + ## 4. Recommend remediation + + + Recommend budget creation, owner follow-up, tag correction, or policy remediation for each uncovered subscription. Prioritize production and high-risk environments first. + + + ## Report format + + + Produce a markdown report with an executive summary, a subscription budget coverage table, a missing-budget table, ownership gaps, and recommended remediation actions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, budget amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a budget coverage by portfolio chart and a missing-budget count by environment chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' + diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-daily-monitor.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-daily-monitor.yaml new file mode 100644 index 000000000..d4ed64f60 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-daily-monitor.yaml @@ -0,0 +1,134 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: CapacityDailyMonitor +spec: + name: CapacityDailyMonitor + description: Daily FinOps capacity management health check — quota usage, CRG utilization, zone capacity + cron_expression: 30 6 * * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Daily FinOps Capacity Management Monitor + + + ## Phase 0: Preparation + + + Before starting any checks, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate capacity evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its azure-capacity-management skill during the handoff. + + + This daily check maps Azure capacity health into FinOps Automation, Tools, & Services, Usage Optimization, and Governance, Policy & Risk signals so issues are visible before they block deployments. + + ## Specialist tools to request from `azure-capacity-manager` + + Ask `azure-capacity-manager` to use the following Python tools instead of `az` CLI commands when available. Specialist tools use their configured authentication and the agent system-managed identity where required. + + - `vm-quota-usage`: Run with subscription_id and location to get VM family quota usage with at-risk thresholds + - `capacity-reservation-groups`: Run with subscription_id and resource_group when scoped to list CRGs with instanceView utilization + - `data-freshness-check`: Run with cluster_uri and database to check Hub data staleness + - `non-compute-quotas`: Run with subscription_id and location to get Storage and Network quota usage + + + ## 1. Quota Health + + + Ask `azure-capacity-manager` to use `vm-quota-usage` against each active subscription and region to check: + + - VM family quota usage vs limits + + - Flag any family at >80% utilization — these are deployment risks + + - Flag any family at >95% — these are imminent blockers + + - Check quota groups if configured — report group-level headroom + + Ask `azure-capacity-manager` to use `non-compute-quotas` for Storage and Network quota usage so non-compute limits are included in the daily capacity status. + + + Reference: `references/docs/operations/quota/README.md` + + + ## 2. Capacity Reservation Utilization + + + Ask `azure-capacity-manager` to use `capacity-reservation-groups` for each active CRG: + + - Check reserved vs allocated VM count + + - Flag any CRG where utilization < 50% (paying for unused capacity) + + - Flag any CRG where overallocation exceeds 2x reservation + + - Check zone alignment for shared CRGs + + + Reference: `references/docs/operations/capacity-reservations/README.md` + + + ## 3. AKS Node Pool Capacity + + + For AKS clusters with CRG associations: + + - Verify node pool CRG association is still active + + - Check if autoscaler is hitting quota limits + + - Report node pool scale events in last 24 hours + + + Reference: `references/docs/operations/aks-capacity/README.md` + + + ## 4. Alert Status + + + Check for any fired alerts in last 24 hours: + + - Quota threshold alerts + + - Budget alerts + + - Cost anomaly alerts + + Ask `ftk-hubs-agent` to run `data-freshness-check` to verify Hub data health before trusting alert and cost context. + + + Reference: `references/docs/operations/monitoring-alerting/README.md` + + + ## Output + + + Use #remember to note key findings. Escalate: + + - 🔴 CRITICAL: Any quota at >95% or CRG billing waste >$1000/day + + - 🟡 WARNING: Any quota at >80% or CRG utilization <50% + + - 🟢 HEALTHY: All within thresholds + + + Do not stop until all checks are complete. + + + ## Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (status results only):** Post the final daily capacity health check to our Teams channel. Include the overall status (🔴🟡🟢), any critical or warning items, and recommended actions. Do not post intermediate results — only the completed summary. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — Python tool failures, quota API workarounds, CRG query patterns, zone alignment discoveries. Never save financial figures, cost amounts, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-monthly-planning.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-monthly-planning.yaml new file mode 100644 index 000000000..883424c5a --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-monthly-planning.yaml @@ -0,0 +1,166 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: CapacityMonthlyPlanning +spec: + name: CapacityMonthlyPlanning + description: Monthly capacity planning cycle — demand forecast, capacity request pipeline, governance review + cron_expression: 0 9 1 * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Monthly Capacity Planning Cycle + + + ## Phase 0: Preparation + + + Before starting any analysis, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate capacity evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its azure-capacity-management skill during the handoff. + + + Monthly planning maps Azure capacity signals into FinOps Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Budgeting support, and Governance, Policy & Risk. + + ## Specialist tools to request from `azure-capacity-manager` + + Ask `azure-capacity-manager` to use the following Python tools instead of `az` CLI commands when available. Specialist tools use their configured authentication and the agent system-managed identity where required. + + - `vm-quota-usage`: Run with subscription_id and location to get VM family quota usage with at-risk thresholds + - `capacity-reservation-groups`: Run with subscription_id and resource_group when scoped to list CRGs with instanceView utilization + - `azure-capacity-manager`: Run `benefit-recommendations` with billing_scope and lookback to get reservation and savings plan recommendations + - `ftk-hubs-agent`: Run `resource-graph-query` with query and subscriptions to execute Azure Resource Graph KQL + - `ftk-database-query`: Run `compute-spend-commitment-coverage`, `compute-cost-per-core`, `commitment-utilization-score`, `commitment-discount-waste`, and `macc-consumption-vs-commitment` for capacity-related Rate Optimization KPI evidence + + + ## 1. Demand Forecast + + + Ask `ftk-database-query` to run `cost-forecasting-model` Kusto tool with 180-day historical, 90-day forecast. + + Filter to compute services. Project: + + - VM core demand by family for next 3 months + + - Growth rate by region + + - Seasonal patterns (if detectable) + + + Cross-reference with business targets: + + - New customer deployments planned? + + - Stamp scale-out events expected? + + + Reference: `references/docs/operations/capacity-planning/README.md` + + + ## 2. Capacity Request Pipeline + + + Based on the demand forecast, use `vm-quota-usage` and build a capacity request pipeline: + + - Quota increases needed (by subscription, region, family) + + - Region access requests needed + + - Zonal enablement requests needed + + - Quota group limit increases needed + + - Estimated lead times for each request type + + + Reference: `references/docs/operations/quota/README.md` and capacity request guidance in the uploaded knowledge. + + + ## 3. Allocation Review + + + Ask `azure-capacity-manager` to use `capacity-reservation-groups` to review current CRG portfolio: + + - Utilization trends over the past month (from daily checks) + + - Rightsizing recommendations (reduce or increase reservations) + + - New CRGs needed based on demand forecast + + - CRG sharing opportunities across subscriptions + + - Overallocation policy review + + + Reference: `references/docs/operations/capacity-reservations/README.md` + + + ## 4. Cost Impact + + + Ask `azure-capacity-manager` to run `benefit-recommendations`, then ask `ftk-database-query` to run `commitment-discount-utilization`, `savings-summary-report`, `compute-spend-commitment-coverage`, `compute-cost-per-core`, `commitment-utilization-score`, `commitment-discount-waste`, and `macc-consumption-vs-commitment` for Kusto-backed rate-optimization and capacity unit-economics evidence. + + Calculate: + + - Monthly cost of unused CRG capacity + + - Savings from Azure Reservations paired with CRGs + + - Potential savings from new commitment purchases aligned with capacity needs + + - ESR impact of capacity decisions + + + ## 5. Governance Review + + + Check adherence to the governance program. Ask `ftk-hubs-agent` to use `resource-graph-query` for subscription, alert, budget, and governance inventory where ARM resource data is needed: + + - Are all subscriptions in quota groups? + + - Are anomaly alerts deployed across all subscriptions? + + - Are budget alerts configured? + + - Any post-incident reviews needed from scaling failures? + + + Reference: `references/docs/operations/capacity-governance/README.md` and `references/docs/operations/monitoring-alerting/README.md` + + + ## Output + + + Produce a monthly capacity planning report: + + - Demand forecast table (VM family × region × month) + + - Capacity request pipeline with status and lead times + + - CRG portfolio review with cost impact + + - Governance compliance scorecard + + - Recommended actions with owners and deadlines + + + Use deep investigation for any critical capacity gaps. Use #remember to note key capacity findings. + + + ## Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (capacity results only):** Post the final monthly capacity planning report to our Teams channel. Include the demand forecast, capacity request pipeline, CRG portfolio review, governance scorecard, and recommended actions. Do not post intermediate results — only the completed report. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — forecasting model accuracy, capacity request lead time observations, governance gaps discovered, CLI workarounds. Never save financial figures, cost amounts, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-quarterly-strategy.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-quarterly-strategy.yaml new file mode 100644 index 000000000..7a5d71dd8 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-quarterly-strategy.yaml @@ -0,0 +1,163 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: CapacityQuarterlyStrategy +spec: + name: CapacityQuarterlyStrategy + description: Quarterly capacity strategy review — FinOps maturity, commitment alignment, architecture evolution + cron_expression: 0 9 1 1,4,7,10 * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Quarterly Capacity Strategy Review + + + ## Phase 0: Preparation + + + Before starting any analysis, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate capacity evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its azure-capacity-management skill during the handoff. + + + Quarterly strategic review bridging capacity management with FinOps Rate Optimization, Architecting & Workload Placement, and leadership strategy alignment. + + ## Specialist tools to request from `azure-capacity-manager` + + Ask `azure-capacity-manager` to use the following Python tools instead of `az` CLI commands when available. Specialist tools use their configured authentication and the agent system-managed identity where required. + + - `azure-capacity-manager`: Run `benefit-recommendations` with billing_scope and lookback to get reservation and savings plan recommendations + - `ftk-hubs-agent`: Run `resource-graph-query` with query and subscriptions to execute Azure Resource Graph KQL + - `vm-quota-usage`: Run with subscription_id and location to get VM family quota usage with at-risk thresholds + - `ftk-database-query`: Run `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, `compute-cost-per-core`, and `macc-consumption-vs-commitment` for quarterly Rate Optimization KPI evidence + + + ## 1. FinOps Capability Maturity Assessment + + + Assess maturity across the FinOps capabilities this capacity review supports: + + + | Capability | Crawl | Walk | Run | + + |------|-------|------|-----| + + | Planning & Estimating | Ad-hoc estimates | Telemetry-based estimates | Estimate checks integrated into workload intake | + + | Forecasting | Reactive demand projection | Forecasts from cost and utilization trends | Forecasts integrated into budget and engineering planning | + + | Architecting & Workload Placement | Ad-hoc placement decisions | Regular architecture and placement review | Placement decisions integrated into engineering intake and governance | + + | Automation, Tools, & Services | Manual quota checks | Alert-based quota and capacity governance | Automated guardrails and exception review | + + + Score current maturity and recommend next-level actions. + + + ## 2. Commitment Alignment + + + Ask `azure-capacity-manager` to run `benefit-recommendations` for Azure Cost Management recommendations. Ask `ftk-database-query` to run `reservation-recommendation-breakdown`, `commitment-discount-utilization`, `savings-summary-report`, `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, `compute-cost-per-core`, and `macc-consumption-vs-commitment` with quarterly scope for Kusto-backed commitment, savings, coverage, and unit-economics evidence. + + + Align capacity reservations with commitment purchases: + + - Which CRGs have matching Azure Reservations? (ideal) + + - Which CRGs are paying full price? (needs reservation) + + - Which reservations don''t have CRG capacity? (supply risk) + + - RI/SP purchase recommendations for next quarter + + + Reference: Skill section on "Capacity reservation vs Azure Reservation vs savings plan" + + + ## 3. Architecture Review + + + Ask `ftk-hubs-agent` to run `resource-graph-query` for resource inventory, and ask `azure-capacity-manager` to use `vm-quota-usage` for multi-subscription quota distribution: + + - Stamp-based isolation health — any stamps at capacity? + + - Multi-subscription quota distribution — balanced? + + - Regional expansion needs for next quarter + + - AKS cluster capacity governance + + + Reference: `references/docs/operations/capacity-planning/README.md` and `references/docs/operations/aks-capacity/README.md` + + + ## 4. Non-Compute Quotas + + + Review non-compute service quotas from available Hub data and resource inventory: + + - Storage account limits + + - Cosmos DB throughput limits + + - Service Bus/Event Hub namespace limits + + - Any service-specific scaling constraints + + + Reference: `references/docs/operations/non-compute-quotas/README.md` + + + ## 5. Governance Program Health + + + Evaluate the capacity governance program: + + - Monthly review cadence maintained? + + - Post-incident reviews conducted for scaling failures? + + - Alert coverage complete? + + - Scripts and tooling up to date? + + + Reference: `references/docs/operations/capacity-governance/README.md` + + + ## Output + + + Quarterly capacity strategy brief for leadership: + + - FinOps capability maturity scorecard with progression plan + + - Commitment alignment matrix (capacity + pricing) + + - Quarterly capacity and workload-placement roadmap + + - Key risks and mitigations + + - Budget impact of capacity decisions + + + Use deep investigation for any strategic decisions. Use #remember to note key strategy findings. + + + ## Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (strategy results only):** Post the final quarterly capacity strategy brief to our Teams channel. Include the maturity scorecard, commitment alignment matrix, quarterly roadmap, and key risks. Do not post intermediate results — only the completed strategy brief. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — maturity assessment methodology refinements, commitment alignment patterns, architecture observations, CLI workarounds. Never save financial figures, cost amounts, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-weekly-supply-review.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-weekly-supply-review.yaml new file mode 100644 index 000000000..ba3458bbe --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/capacity-weekly-supply-review.yaml @@ -0,0 +1,149 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: CapacityWeeklySupplyReview +spec: + name: CapacityWeeklySupplyReview + description: Weekly FinOps capacity management review — quota headroom, CRG cost optimization, SKU availability, benefit recommendations + cron_expression: 0 8 * * 1 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Weekly FinOps Capacity Management Review + + + ## Phase 0: Preparation + + + Before starting any analysis, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate capacity evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its azure-capacity-management skill during the handoff. + + + Weekly review mapping Azure capacity signals into FinOps Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Governance, Policy & Risk, and Automation, Tools, & Services. + + ## Specialist tools to request from `azure-capacity-manager` + + Ask `azure-capacity-manager` to use the following Python tools instead of `az` CLI commands when available. Specialist tools use their configured authentication and the agent system-managed identity where required. + + - `vm-quota-usage`: Run with subscription_id and location to get VM family quota usage with at-risk thresholds + - `non-compute-quotas`: Run with subscription_id and location to get Storage and Network quota usage + - `capacity-reservation-groups`: Run with subscription_id and resource_group when scoped to list CRGs with instanceView utilization + - `sku-availability`: Ask `azure-capacity-manager` to run with subscription_id and location to get Compute SKU availability and restrictions by default. Use `resource_provider: kusto` with a planned Data Explorer SKU in `sku_filter` to preflight Azure Data Explorer / Kusto eligibility for FinOps Hub analytics deployments; never infer Kusto availability from Compute SKU results. + - `azure-capacity-manager`: Run `benefit-recommendations` with billing_scope and lookback to get reservation and savings plan recommendations + - `ftk-database-query`: Run `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, and `compute-cost-per-core` when Kusto cost evidence is available + + + ## 1. Quota Headroom Analysis + + + Ask `azure-capacity-manager` to run comprehensive quota analysis across all subscriptions using `vm-quota-usage` and `non-compute-quotas`: + + - Aggregate quota usage by VM family across subscriptions + + - Identify families with <20% headroom across the estate + + - Check quota group balances — any group near its limit? + + - Identify quota transfer opportunities between subscriptions + + - Flag subscriptions not yet added to quota groups + + + Reference: `references/docs/operations/quota/README.md` and `references/docs/operations/quota-groups/README.md` + + + ## 2. CRG Cost-Waste Audit + + + Ask `azure-capacity-manager` to use `capacity-reservation-groups` for all capacity reservations: + + - Calculate weekly cost of unused reserved capacity (reserved minus allocated × pay-as-you-go rate) + + - Compare CRG cost against equivalent Azure Reservation or savings plan cost + + - Identify CRGs that could be rightsized (reduce reservation quantity) + + - Check for CRGs without matching Azure Reservations (paying both capacity guarantee AND full price) + + + Key distinction from skill: Capacity reservations guarantee supply. Azure Reservations reduce cost. Best practice is to pair both. + + + Reference: `references/docs/operations/capacity-reservations/README.md` + + + ## 3. SKU and Zone Availability Validation + + + Ask `azure-capacity-manager` to use `sku-availability` to validate SKU and zone availability for shared CRGs and upcoming deployments: + + - Verify that planned SKUs are available in the required locations and zones + + - Flag any SKU restrictions that could block planned scaling + + - For FinOps Hub Data Explorer backend work, ask `azure-capacity-manager` to run `sku-availability` with `resource_provider: kusto` and the planned ADX SKU as `sku_filter`; treat `is_available: false` as a deploy or upgrade blocker. + + + Reference: Skill section on zone alignment and `references/docs/operations/capacity-planning/README.md` + + + ## 4. Benefit Recommendations + + + Ask `azure-capacity-manager` to run `benefit-recommendations` when current RI/SP recommendations are needed. Where Hub cost context is available, ask `ftk-database-query` to run `reservation-recommendation-breakdown`, `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, and `compute-cost-per-core` for Kusto-backed recommendation, commitment, coverage, and unit-economics evidence. + + Cross-reference with capacity reservation strategy: + + - Do recommended reservations overlap with existing CRGs? (Good — pair pricing with capacity) + + - Are there high-savings recommendations in regions without CRGs? (May need capacity too) + + + ## 5. Region and SKU Availability + + + Ask `azure-capacity-manager` to use `sku-availability` to check for any new region access or zonal enablement needs: + + - Upcoming deployments that need new regions? + + - SKU restrictions blocking planned scaling? + + + Reference: `references/docs/operations/capacity-planning/README.md` + + + ## Output + + + Produce a weekly FinOps capacity management briefing with: + + - Quota headroom scorecard (🔴🟡🟢 by VM family) + + - CRG utilization and waste summary with dollar amounts + + - Benefit recommendation highlights + + - Action items for platform, engineering, and finance stakeholders + + + Use #remember to note key FinOps capacity findings. Use deep investigation if any quota is critically low. + + + ## Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (capacity results only):** Post the final weekly capacity briefing to our Teams channel. Include the quota headroom scorecard, CRG waste summary, benefit recommendations, and capacity action items. Do not post intermediate results — only the completed briefing. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — quota API failures, SKU availability discoveries, CRG query patterns, Python tool workarounds. Never save financial figures, cost amounts, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml new file mode 100644 index 000000000..9e77d3005 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml @@ -0,0 +1,84 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: ComputeUtilizationTrend +spec: + name: ComputeUtilizationTrend + description: Weekly VM quota utilization trend review across subscriptions and regions + cron_expression: 0 7 * * 1 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Compute Utilization Trend + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to prior capacity run notes, known quota API workarounds, and active subscription or region scope notes. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate capacity evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its capacity-management guidance and use the agent system-managed identity for Python tool authentication. + + + ## Specialist tools to request from `azure-capacity-manager` + + + Ask `azure-capacity-manager` to use Python tools with DefaultAzureCredential and the agent system-managed identity. + + + - `ftk-hubs-agent`: Run `resource-graph-query` with `query` and optional `subscription_ids` to discover active subscriptions, active VM resources, regions, and prior tagging or ownership context. + + - `vm-quota-usage`: Run with `subscription_id` and optional `location` to retrieve VM family current usage, limits, and utilization percentages. + + + ## 1. Establish scope + + + Ask `ftk-hubs-agent` to use `resource-graph-query` to identify active subscriptions with compute resources and the regions where virtual machines, virtual machine scale sets, or AKS node pools are deployed. Exclude disabled, test-only, or explicitly out-of-scope subscriptions if documented in the knowledge base. + + + ## 2. Collect quota utilization + + + For each active subscription and region, ask `azure-capacity-manager` to run `vm-quota-usage` with `subscription_id`, `location`. Capture VM family current usage, limit, utilization percentage, warning status, and critical status. + + + ## 3. Compare to prior week + + + Compare current results against prior #remember findings or prior run notes. Identify VM families where utilization increased materially, where headroom decreased, or where the trend suggests quota risk before the next weekly run. + + + ## 4. Flag growing utilization + + + Flag any family above 80% utilization, any family above 95% utilization, and any family with week-over-week growth that could exceed 80% within the next two reporting periods. Include subscription, region, VM family, current utilization, previous utilization when known, and recommended action. + + + ## Report format + + + Produce a markdown report with an executive summary, a risk scorecard table by subscription and region, a VM family trend table, and a recommended action list. Use 🔴 for critical quota pressure, 🟡 for growing or warning utilization, and 🟢 for healthy headroom. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a utilization trend chart and a current headroom comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' + diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/cost-optimization.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/cost-optimization.yaml new file mode 100644 index 000000000..19fe9233a --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/cost-optimization.yaml @@ -0,0 +1,333 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: CostOptimization +spec: + name: CostOptimization + description: Comprehensive cost optimization report with orphaned resources, rightsizing, and commitment analysis + cron_expression: 0 8 * * 1 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Cost optimization report + + + ## Phase 0: Preparation + + + Before starting any analysis, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Generate a comprehensive cost optimization report for the current Azure environment. Works with or without FinOps hubs. + + ## Specialist tools to request for this task + + The following Python tools provide real Azure data via ARM REST API. Always use these instead of `az` CLI commands when available. Specialist tools use their configured authentication and the agent system-managed identity where required. + + - `ftk-hubs-agent`: Run `resource-graph-query` with query and subscriptions to execute Azure Resource Graph KQL for orphaned resource detection + - `azure-capacity-manager`: Run `benefit-recommendations` with billing_scope and lookback to get reservation and savings plan recommendations + - `ftk-database-query`: Run Kusto KPI tools when a FinOps hub is connected, especially `cost-optimization-index`, `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, `compute-cost-per-core`, `cost-per-gb-stored`, and `storage-tier-distribution` + + + ## Phase 1: Discovery + + + 1. Determine scope from the configured scheduled-task scope, documented knowledge-base scope, or current authenticated context. Do not wait for user input during this autonomous scheduled run. If scope cannot be determined, report the missing scope as a blocking configuration issue. + + 2. Verify authentication: confirm Python tools are using DefaultAzureCredential with the agent system-managed identity. + + 3. Check permissions: Reader role is sufficient for all detection queries. Note if elevated permissions are available. + + 4. Check for FinOps hubs: Read `.ftk/environments.local.md` to see if a FinOps hub is connected. If available, note it for Phase 2. + + + ## Phase 2: Data collection + + + Run these data collection steps in parallel where possible. Use #remember to note key intermediate findings as you go. + + + ### 2a: Orphaned resources + + + Detect unused resources generating waste with zero workload value. + + + Ask `ftk-hubs-agent` to run `resource-graph-query` with the queries from `references/azure-orphaned-resources.md` to scan for: + + - Unattached managed disks + + - Unused network interfaces + + - Orphaned public IP addresses + + - Idle NAT gateways + + - Orphaned snapshots (source disk deleted, age > 30 days) + + - Idle load balancers (empty backend pools) + + - Empty availability sets + + - Orphaned NSGs + + + For each category, capture: count, estimated monthly cost, resource list. + + + ### 2b: Advisor cost recommendations + + + Query Azure Advisor for all cost recommendations. Ask `ftk-hubs-agent` to run `resource-graph-query` for any Advisor recommendation Resource Graph queries in the references. + + + Use `references/azure-advisor.md` for query patterns: + + + Categorize recommendations by type: right-size VMs, shutdown idle VMs, reserved instances, delete unused disks, and other. + + + Calculate total potential monthly savings from Advisor. + + + ### 2c: Commitment discount status + + + Analyze current commitment discount coverage and opportunities. Ask `azure-capacity-manager` to run `benefit-recommendations` for new reservation and savings plan purchase recommendations. + + + Use `references/azure-savings-plans.md` and `references/azure-reservations.md` for: + + - Current savings plan coverage and utilization + + - Current reservation coverage and utilization + + - New purchase recommendations from the Benefit Recommendations API + + - Gap analysis: what percentage of eligible compute spend is covered + + + Use `references/azure-commitment-discount-decision.md` for the decision framework when recommending new purchases. + + + ### 2d: FinOps hubs data (if available) + + + If a FinOps hub is connected from Phase 1, do not run Kusto directly. Ask `ftk-database-query` to collect these evidence packages with the connected cluster URI, database, and analysis window: + + + - `monthly-cost-trend` for the last three complete months. + + - `top-services-by-cost` for the current and prior complete month. + + - `cost-by-region-trend` when placement or capacity decisions affect optimization. + + - `cost-anomaly-detection` for unusual service-level spikes or drops. + + - `cost-optimization-index`, `commitment-utilization-score`, `commitment-discount-waste`, `compute-spend-commitment-coverage`, `compute-cost-per-core`, `cost-per-gb-stored`, and `storage-tier-distribution` for the generated FinOps KPI optimization scorecard. + + + Use the returned evidence to identify cost anomalies and trends that inform optimization priorities. + + + ## Phase 3: Analysis + + + ### 3a: Validate top rightsizing recommendations + + + For the top 5 Advisor right-size VM recommendations (by savings amount), validate with the Retail Prices API. + + + Use `references/azure-retail-prices.md` to look up current and target SKU prices. Compare Advisor''s estimated savings against actual retail price deltas. + + + ### 3b: VM utilization deep dive (if VM Insights available) + + + For the top rightsizing candidates, check actual utilization metrics if VM Insights is enabled. + + + Use `references/azure-vm-rightsizing.md` for: + + - 14-day CPU P95 analysis + + - Memory utilization (if VM Insights agent deployed) + + - Burst pattern detection (P99 check) + + + Skip this step if VM Insights is not available — note it as a recommendation for future optimization maturity. + + + ### 3c: Categorize by effort and risk + + Before categorizing, ask `azure-capacity-manager` to use `non-compute-quotas` to identify Storage and Network quota pressure that may affect optimization feasibility. + + + Organize all findings into four categories: + + + | Category | Effort | Risk | Examples | + + |----------|--------|------|----------| + + | **Quick wins** | Low | Zero | Delete orphaned resources, remove unused IPs | + + | **Rightsizing** | Medium | Low | Resize underutilized VMs (requires restart) | + + | **Commitment optimization** | Medium | Medium | Purchase savings plans or reservations | + + | **Architecture changes** | High | Variable | Redesign for cost efficiency, migrate to PaaS | + + + ## Phase 4: Report + + + Generate a markdown report with the following structure: + + + ### Report template + + + ```markdown + + # Cost Optimization Report — {subscription/environment name} + + **Generated:** {date} + + **Scope:** {subscription(s) or management group} + + **FinOps Hubs:** {connected / not connected} + + + ## Executive summary + + + - **Total identified monthly savings:** ${amount} + + - **Quick wins (zero risk):** ${amount} across {count} resources + + - **Rightsizing opportunities:** ${amount} across {count} VMs + + - **Commitment discount opportunities:** ${amount} estimated + + - **Current commitment coverage:** {percentage}% + + + ## Quick wins — orphaned resources + + + | Resource Type | Count | Est. Monthly Cost | Action | + + |--------------|-------|-------------------|--------| + + | Unattached disks | {n} | ${cost} | Delete | + + | Orphaned public IPs | {n} | ${cost} | Delete | + + | ... | ... | ... | ... | + + | **Total** | **{n}** | **${cost}** | | + + + ## Rightsizing recommendations + + + ### Top VM recommendations (validated) + + + | VM | Current SKU | Target SKU | CPU P95 | Savings/mo | Risk | + + |----|-------------|------------|---------|------------|------| + + | {name} | {current} | {target} | {%} | ${savings} | Low | + + | ... | ... | ... | ... | ... | ... | + + + {Include notes on burst patterns, memory utilization where available} + + + ## Commitment discount opportunities + + + ### Current coverage + + - Savings plan utilization: {%} + + - Reservation utilization: {%} + + - Total eligible compute covered: {%} + + + ### Recommendations + + {Summarize Benefit Recommendations API findings} + + {Reference azure-commitment-discount-decision.md framework for purchase guidance} + + + ## Cost trends (FinOps hubs) + + {Include if FinOps hubs connected, otherwise note: "Connect FinOps hubs for trend analysis — run /ftk-hubs-connect"} + + + ## Next steps + + + 1. **Immediate (this week):** Delete orphaned resources — ${amount}/mo savings + + 2. **Short-term (this month):** Resize top {n} VMs — ${amount}/mo savings + + 3. **Medium-term (this quarter):** Evaluate commitment discount purchases + + 4. **Ongoing:** Deploy VM Insights for memory-aware rightsizing, connect FinOps hubs for trend analysis + + + ## Audit trail + + + | Data Source | Query Time | Records | + + |-------------|-----------|---------| + + | Resource Graph (orphaned) | {timestamp} | {count} | + + | Advisor recommendations | {timestamp} | {count} | + + | Benefit Recommendations API | {timestamp} | {count} | + + | FinOps hubs (if connected) | {timestamp} | {count} | + + ``` + + + ### Report guidance + + + - Format all currency values with the appropriate billing currency + + - Include resource IDs or names for actionable items + + - Flag any data gaps (e.g., "Memory metrics unavailable — VM Insights not deployed") + + - If FinOps hubs are not connected, recommend `/ftk-hubs-connect` for deeper analysis + + - Do not save task reports or financial data to the git repository — use #remember for key operational findings instead + + + ## Phase 5: Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (financial results only):** Post the final cost optimization report to our Teams channel. Include the executive summary, total identified savings, quick wins, and prioritized next steps. Do not post intermediate results — only the completed report. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — query failures, Resource Graph workarounds, Advisor API patterns, tool errors encountered. Never save financial figures, cost amounts, savings numbers, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/db-quota-audit.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/db-quota-audit.yaml new file mode 100644 index 000000000..354ff8453 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/db-quota-audit.yaml @@ -0,0 +1,60 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: DbQuotaAudit +spec: + name: DbQuotaAudit + description: Weekly audit of database (SQL DB, SQL MI, Cosmos DB, PostgreSQL Flex, MySQL Flex) quota and region/AZ access risks + cron_expression: 0 7 * * 3 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: |- + # Database Service Quota Audit + + ## Phase 0: Preparation + + Before starting, read all documents in the knowledge base. Pay special attention to prior database quota findings, service limit assumptions, regional access restrictions, and availability-zone access caveats. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate database quota evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its capacity-management guidance and use the agent system-managed identity for Python tool authentication. + + ## Specialist tools to request from `azure-capacity-manager` + + Ask `azure-capacity-manager` to use Python tools with DefaultAzureCredential and the agent system-managed identity. + + - `db-service-quotas`: Run with `subscription_id`, optional `location`, optional `services`, optional `include_capabilities` to retrieve SQL DB, SQL MI, Cosmos DB, PostgreSQL Flex, and MySQL Flex quotas plus region/AZ access status. + + ## 1. Establish subscription scope + + Use documented active subscription scope from the knowledge base and prior reports. If scope is missing, clearly state the subscriptions that were available to the tool at runtime and any access gaps. + + ## 2. Collect database quota and access usage + + For each active subscription, ask `azure-capacity-manager` to run `db-service-quotas` with `subscription_id`, optional `location`. Use the tool's normalized `quotas` and `region_access` arrays for tables and charts. Capture service name, scope, metric, current value, limit, available capacity, utilization percentage, unit, location, at-risk flags, source endpoint, access status, and any suppressed or unsuppressed errors. + + ## 3. Separate API-reported and default soft limits + + Separate API-reported quota limits from default soft limits. Treat Cosmos DB's default soft subscription account limit of 50 separately from provider-reported limits and label it clearly as a default soft limit. + + ## 4. Flag quota and access risk + + Flag database quotas at or above 80% utilization, highlight critical items above 95%, surface region access blocks where `access_allowed_for_region == false`, and surface AZ blocks separately from regular region access blocks. Group findings by service in the report so SQL DB, SQL MI, Cosmos DB, PostgreSQL Flex, and MySQL Flex risks are easy to triage. + + ## Report format + + Produce a markdown report with an executive summary, a database quota risk table grouped by service, an API-reported versus default soft limits table, a region access blocks table, an AZ access blocks table, errors and access gaps, and recommended mitigation actions. + + ## Persistence + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + ## Visualizations + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Build chart data from normalized quota rows and use `.get()`/safe-access patterns instead of indexing fields like `location` directly, because subscription-scoped database quota rows may not be regional. Include at minimum a quota utilization by service chart and an at-risk quota count by subscription chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/hubs-health-check.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/hubs-health-check.yaml new file mode 100644 index 000000000..6877b4ab4 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/hubs-health-check.yaml @@ -0,0 +1,106 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: HubsHealthCheck +spec: + name: HubsHealthCheck + description: FinOps hub version and data freshness validation + cron_expression: 0 6 * * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Health check for FinOps hubs + + + ## Phase 0: Preparation + + + Before starting any checks, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate FinOps Hub platform evidence collection and specialist analysis to `ftk-hubs-agent`; do not try to run Hub platform tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + ## Specialist tools to request from `ftk-hubs-agent` + + Ask `ftk-hubs-agent` to use its assigned Hub health tools instead of ad hoc `az` CLI commands when available. Specialist tools use their configured authentication and the agent system-managed identity where required. + + - `data-freshness-check`: Run with cluster_uri and database to check Hub data staleness + + - `ftk-database-query`: Run `cost-visibility-delay` and `data-update-frequency` to collect the FinOps KPI data-ingestion scorecard after `data-freshness-check` establishes authoritative freshness. + + + ## Step 1: Check the latest released FinOps hub version + + + Get the content from this file to determine the latest stable version of FinOps hubs: `https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/heads/main/src/templates/finops-hub/modules/fx/ftkver.txt`. + + + Get the content from this file to determine the latest development version of FinOps hubs: `https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/heads/dev/src/templates/finops-hub/modules/fx/ftkver.txt`. + + + If either URL fails or returns empty content, do not infer the latest version. Report the version lookup as unavailable and continue with the remaining health checks. + + + FinOps hubs use semantic versioning (SemVer) format for version numbers, which is `major.minor`, `major.minor.patch`, or `major.minor-prerelease`. If the version number has `-dev` at the end of it, + that means it''s a development version. + + + Compare the version of the current FinOps hub instance with the latest stable version of FinOps hubs. If it''s the same version as stable, tell the user they are using the latest released version and + skip to the next step. + + + If the FinOps hub version is the same as the development version, tell the user they are using the development version and they should monitor the repository to ensure it''s updated with the latest + changes, then skip to the next step. + + + If the FinOps hub version is older than the development version and matches or is older than the latest stable version, tell the user they are using an older development version and should update to + the latest stable release or development version. Mention their version number and the latest stable and development version numbers. Give them this link to deploy the latest stable version depending + on their Azure cloud environment: + + + - For the Azure public, commercial cloud, use https://aka.ms/finops/hubs/deploy + + - For the Azure Government cloud, use https://aka.ms/finops/hubs/deploy/gov + + - For the Azure China cloud, use https://aka.ms/finops/hubs/deploy/china + + + ## Step 2: Check the latest data refresh/update date + + + Ask `ftk-hubs-agent` to run `data-freshness-check` as the authoritative data staleness tool. This tool checks actual data dates in the Hub database through direct Azure Data Explorer REST queries, not Kusto ingestion timestamps or stale memory. Treat `Costs()` as the primary freshness signal. If the latest cost data is 3 days old or newer, skip stale-data remediation because Azure cost data normally lags 24-48 hours. If stale-memory, raw-KQL, or ingestion timestamp conclusions conflict with `data-freshness-check`, mark those older conclusions as superseded and unsafe. + + + If the latest `Costs()` data is more than 3 days old, or if `Costs()` has no rows, inform the user that the data may be stale and they should check the Microsoft Cost Management exports and Azure Data Factory data ingestion pipelines to ensure they are running without errors. + + + If `Transactions()` returns zero rows, do not report a generic empty table or a healthy success. Report the `TRANSACTIONS_ZERO_ROWS` diagnostic from `data-freshness-check` and state that reservation transaction analysis is unavailable until the Cost Management `reservationtransactions` export, Azure Data Factory Transactions ingestion, and Hub `Transactions()` / `Transactions_v1_2()` stored-function behavior are verified. Empty `Transactions()` is not enough by itself to mark core `Costs()` freshness stale, but it is an action item. + + + Report empty `Prices()` or `Recommendations()` results as follow-up items to confirm whether those exports should be configured. Do not report the hub as stale solely because an optional function is empty. + + Ask `ftk-database-query` to run `cost-visibility-delay` and `data-update-frequency` after the Hub platform freshness check. Use those KPI outputs as supporting Data Ingestion evidence, but do not let them override the `data-freshness-check` direct REST verdict for current `Costs()` staleness. + + + Give them a link to Microsoft Cost Management to check the exports: https://portal.azure.com/#view/Microsoft_Azure_CostManagement/Menu/~/exports + + + Give them a link to the Azure Data Factory portal to check data ingestion pipelines: https://adf.azure.com/monitoring/pipelineruns + + + Tell the user you can help them troubleshoot any issues with [common errors](https://learn.microsoft.com/cloud-computing/finops/toolkit/help/errors) and the [troubleshooting guide](https://learn.microsoft.com/cloud-computing/finops/toolkit/help/troubleshooting). + + + ## Deliver + + + + **Visualizations:** Include a trend chart of data freshness (hours since last update) if degradation is detected. Version status should be reported as a table. Skip charts if all checks pass. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. + + **Teams and Outlook (status results only):** Post the final health check results to our Teams channel. Include version status, data freshness status, and any action items. Do not post intermediate results — only the completed health check summary. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — version drift patterns, data freshness trends, pipeline failure modes, troubleshooting steps that worked. Never save financial figures or customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml new file mode 100644 index 000000000..2ce1741f0 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml @@ -0,0 +1,88 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: MonitoringScopeValidation +spec: + name: MonitoringScopeValidation + description: Weekly validation that FinOps Hub monitoring covers all active subscriptions + cron_expression: 0 9 * * 4 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Monitoring Scope Validation + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to FinOps Hub deployment notes, ADX cluster details, monitored scope decisions, and data freshness workarounds. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate monitoring-scope and FinOps Hub platform evidence collection to `ftk-hubs-agent`; do not try to run Hub platform tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `ftk-hubs-agent` to load its FinOps Hubs guidance and use assigned Hub health tools with the agent system-managed identity where required. + + + ## Specialist tools to request from `ftk-hubs-agent` + + + Ask `ftk-hubs-agent` to use assigned Hub health tools with their configured authentication and the agent system-managed identity where required. + + + - `ftk-hubs-agent`: Run `resource-graph-query` with `query`, optional `subscription_ids` to list active subscriptions and subscription metadata. + + - `data-freshness-check`: Run with `cluster_uri`, optional `database` to validate FinOps Hub function freshness and coverage signals. + + - `ftk-database-query`: Run `percentage-unallocated-costs`, `percentage-untagged-costs`, `tagging-policy-compliance`, and `allocation-accuracy-index` when Kusto is available to validate allocation coverage quality inside the monitored scope. + + + ## 1. Establish active subscription inventory + + + Ask `ftk-hubs-agent` to run `resource-graph-query` to list active subscriptions and key ownership or environment metadata. Exclude subscriptions documented as intentionally outside the Hub monitoring scope. + + + ## 2. Validate Hub data freshness + + + Ask `ftk-hubs-agent` to run `data-freshness-check` with `cluster_uri`, optional `database`. Capture latest data dates, staleness days, stale functions, missing functions, and query errors. + + + ## 3. Cross-reference monitoring coverage + + + Cross-reference Resource Graph subscription inventory with subscriptions represented in Hub data coverage notes or Hub query results. Identify active subscriptions with missing, stale, or ambiguous Hub coverage. + + Ask `ftk-database-query` to run `percentage-unallocated-costs`, `percentage-untagged-costs`, `tagging-policy-compliance`, and `allocation-accuracy-index` for the monitored scope. Use those Allocation KPI results to distinguish "subscription missing from monitoring" from "subscription present but allocation/tagging coverage is weak." + + + ## 4. Flag scope gaps + + + Flag any active subscription not covered by Hub monitoring, any stale Hub function, and any access or query failure that prevents confidence in coverage. Recommend export, scope, identity, or ingestion remediation. + + + ## Report format + + + Produce a markdown report with an executive summary, a subscription coverage table, a data freshness table, coverage gaps, errors, and recommended remediation actions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a monitored versus unmonitored subscription chart and a data staleness chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' + diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monthly-report.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monthly-report.yaml new file mode 100644 index 000000000..c32f303a9 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monthly-report.yaml @@ -0,0 +1,193 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: Monthly +spec: + name: Monthly + description: Autonomous monthly cost analysis with core cost-analysis Kusto tools + cron_expression: 15 17 5 * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Monthly Cost Analysis + + + ## Phase 0: Preparation + + + Before starting any analysis, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Load your finops-toolkit and azure-cost-management skills. + + + Perform a comprehensive autonomous analysis for the most recently completed calendar month and a forecast for the next calendar month. If the knowledge base documents a fiscal calendar, include the fiscal mapping and state the reporting boundary explicitly. Each run builds on previous runs — prior research, notes, and results carry forward. + + ## Specialist evidence requests for this task + + Lead the workflow as the FinOps practitioner. Do not run Kusto tools directly. Ask `ftk-database-query` to collect FinOps Hub Kusto evidence and ask `azure-capacity-manager` to collect quota and capacity evidence. + + - `ftk-hubs-agent`: Run `data-freshness-check` with cluster_uri and database to check Hub data staleness + - `azure-capacity-manager`: Run `vm-quota-usage` with subscription_id and location to get VM family quota usage with at-risk thresholds + + + ## Phase 1: Data Collection + + + Request these Kusto evidence packages from `ftk-database-query` in sequence. Use #remember to note operational observations (tool errors, data quality issues, query patterns) as you go — never financial figures. + + + ### 1.1 Verify Connectivity + + Ask `ftk-hubs-agent` to run `data-freshness-check` with the FinOps Hub cluster URI and Hub database. Treat its direct REST `Costs()` latest data date as the authoritative freshness source and mark any conflicting stale-memory, raw-KQL, or ingestion timestamp conclusion as superseded and unsafe. Proceed if latest `Costs()` data is 3 days old or newer. Do not ask `ftk-database-query` to run `costs-enriched-base` for freshness checks or month-level reports; use aggregated Kusto tools for complete-month reporting windows and reserve row-level detail for one-day drill-downs only. + + + ### 1.2 Fiscal Trends + + Ask `ftk-database-query` to run `monthly-cost-trend` with startDate=startofmonth(ago(365d)) to get 12-month billed and effective cost trends. + + + ### 1.3 Service Breakdown + + Ask `ftk-database-query` to run `top-services-by-cost` with N=20, startDate=startofmonth(ago(30d)) to identify top cost-driving services. Flag commitment discount opportunities and right-sizing potential. + + + ### 1.4 Resource Group Analysis + + Ask `ftk-database-query` to run `top-resource-groups-by-cost` with default parameters. Identify consolidation opportunities. + + + ### 1.5 Anomaly Detection + + Ask `ftk-database-query` to run `cost-anomaly-detection` with numberOfMonths=12, interval=1d. Use deep investigation on any detected anomalies to form hypotheses about root causes. + + + ### 1.6 Savings and ESR + + Ask `ftk-database-query` to run `savings-summary-report` with startDate=startofmonth(ago(30d)). Record negotiated discount savings, commitment discount savings, total savings, and Effective Savings Rate (ESR). + + + ### 1.7 Commitment Utilization + + Ask `ftk-database-query` to run `commitment-discount-utilization` with startDate=startofmonth(ago(30d)). Compare utilization against the 60-70% industry benchmark. + + + **Checkpoint:** Confirm fiscal trends, service breakdown, resource groups, anomalies, savings, and commitments are all collected before proceeding. + + + ### 1.8 Forecast + + Ask `ftk-database-query` to run `cost-forecasting-model` with startDate=startofmonth(ago(180d)), forecastPeriods=90, interval=1d. Assess forecast confidence. + + + ### 1.9 Reservation Recommendations + + Ask `ftk-database-query` to run `reservation-recommendation-breakdown` to identify top savings opportunities by break-even date and projected savings. + + + ### 1.10 Regional Distribution + + Ask `ftk-database-query` to run `cost-by-region-trend` with default parameters. Identify regional optimization opportunities. + + + ### 1.11 Resource Types + + Ask `ftk-database-query` to run `top-resource-types-by-cost` with N=20. Identify legacy or inefficient resource types. + + Ask `azure-capacity-manager` to run `vm-quota-usage` for subscriptions and locations with significant compute cost to identify VM family quota risks that could affect optimization or forecast assumptions. + + + ### 1.12 Tag Coverage + + Ask `ftk-database-query` to run `cost-by-financial-hierarchy` with N=20, startDate=startofmonth(ago(30d)), and endDate=startofmonth(now()) to review allocation dimensions and identify missing team, product, application, or environment values. Do not run raw `costs-enriched-base` for tag-coverage rollups. + + + ### 1.13 Price Benchmarking + + Ask `ftk-database-query` to run `service-price-benchmarking` with startDate=startofmonth(ago(30d)). Compare list, contracted, and effective costs. Identify negative savings anomalies. Compare variance to the 3-5% industry average + benchmark. + + + ### 1.14 Cost Volatility + + Ask `ftk-database-query` to run `cost-anomaly-detection` adapted for 90-day daily spikes. Identify peak cost dates and root causes. + + + ### 1.15 Marketplace/Other Purchases + + Ask `ftk-database-query` to run `top-other-transactions` with N=20. If it returns zero rows or `ZERO_ROWS_RETURNED`, ask `ftk-hubs-agent` to run `data-freshness-check` and report whether `Transactions()` has the `TRANSACTIONS_ZERO_ROWS` diagnostic. Do not conclude there were no large one-time non-usage purchases until the export, ingestion, and stored-function diagnostic is clear. + + + ### 1.16 Month-over-Month Change + + Ask `ftk-database-query` to run `monthly-cost-change-percentage` with startDate=startofmonth(ago(390d)). Track cost volatility and trend direction. + + + ### 1.17 FinOps KPI Scorecard + + Ask `ftk-database-query` to run the FinOps KPI tools that map directly to `src/queries/KPI.md` for the completed month. Use the same reporting window and keep every KPI result tied to its source tool: `percentage-unallocated-costs`, `percentage-untagged-costs`, `tagging-policy-compliance`, `allocation-accuracy-index`, `anomaly-detection-rate`, `anomaly-variance-total`, `monthly-cost-trend`, `cost-visibility-delay`, `data-update-frequency`, `macc-consumption-vs-commitment`, `ai-token-usage-breakdown`, `ai-daily-trend`, `ai-model-cost-comparison`, `commitment-utilization-score`, `compute-cost-per-core`, `savings-summary-report`, `compute-spend-commitment-coverage`, `commitment-discount-waste`, `cost-optimization-index`, `storage-tier-distribution`, and `cost-per-gb-stored`. + + Summarize the KPI scorecard by FinOps capability: Allocation, Data Ingestion, Anomaly Management, Rate Optimization, Unit Economics, Usage Optimization, AI unit economics, and KPIs & Benchmarking. If a KPI tool returns no rows or cannot run because the underlying Hub function is empty, classify it as a data sufficiency limitation and cite the tool result instead of omitting the KPI. + + + **Checkpoint:** Confirm ALL data collection is complete before strategic analysis. + + + ## Phase 2: Strategic Analysis + + + ### 2.1 ROI and Business Impact + + Calculate ROI = Annual Savings / Implementation Cost for each optimization opportunity. Determine payback period. Compare against industry benchmarks (cost variance 3-5%, RI coverage 60-70%). Create + opportunity matrix. + + + ### 2.2 Quick Wins + + Filter opportunities meeting ALL criteria: implementation < 30 days AND risk = low AND savings > $1000/month. Prioritize: commitment purchases, right-sizing, auto-shutdown. + + + ### 2.3 Detailed Findings + + Document 7 sections: (1) Cost Analysis, (2) Savings Analysis, (3) Optimization Opportunities, (4) Governance & Risk, (5) Strategic Market Positioning, (6) Temporal Themes, (7) Implementation Roadmap. + No raw JSON references — executive-level language only. + + + ### 2.4 Recommendations with Performance Grading + + Assign a letter grade (A+ to F) with percentile ranking. Build prioritized actions: Immediate (<30 days), Short-term (30-90 days), Long-term (90+ days). Include dollar savings amount, confidence %, + and clear owner for each. + + + ### 2.5 Implementation Roadmap + + Phase 1 (30 days): quick wins. Phase 2 (60 days): commitments. Phase 3 (90 days): architecture. Include dependencies, risks, success metrics for each phase. + + + **Checkpoint:** Validate all deliverables before formatting. + + + ## Phase 3: Report Formatting + + + Format as a professional, scannable report. Use tables, emoji indicators (📊 💰 🚨 🎯 🏆), bold dollar amounts. Include multi-scenario forecasts (Conservative/Expected/Optimistic), YoY/MoM comparisons, and + percentile positioning. + + + Do not stop or yield until the report is complete and ready for the FinOps team. + + + ## Phase 4: Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (financial results only):** Post the final report to our Teams channel. Include the executive summary, key findings, grade card, and top recommendations. Do not post intermediate results — only the completed report. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — tool errors encountered, workarounds discovered, data quality observations, query patterns that worked or failed. Never save financial figures, cost amounts, savings numbers, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/non-compute-quota-audit.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/non-compute-quota-audit.yaml new file mode 100644 index 000000000..0cb3b8621 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/non-compute-quota-audit.yaml @@ -0,0 +1,81 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: NonComputeQuotaAudit +spec: + name: NonComputeQuotaAudit + description: Weekly audit of storage, network, and non-compute quota usage at risk + cron_expression: 0 7 * * 2 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Non-Compute Quota Audit + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to prior non-compute quota findings, service limit assumptions, and known Resource Graph fallback caveats. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate non-compute quota evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its capacity-management guidance and use the agent system-managed identity for Python tool authentication. + + + ## Specialist tools to request from `azure-capacity-manager` + + + Ask `azure-capacity-manager` to use Python tools with DefaultAzureCredential and the agent system-managed identity. + + + - `non-compute-quotas`: Run with `subscription_id`, optional `location` to retrieve storage, network, and estimated non-compute service quota utilization. + + + ## 1. Establish subscription scope + + + Use documented active subscription scope from the knowledge base and prior reports. If scope is missing, clearly state the subscriptions that were available to the tool at runtime and any access gaps. + + + ## 2. Collect quota usage + + + For each active subscription, ask `azure-capacity-manager` to run `non-compute-quotas` with `subscription_id`, optional `location`. Use the tool''s normalized `quotas` array for tables and charts. If only legacy `services` records are available, normalize them with safe accessors before reporting: accept `service_name` or `service`, `quota_name` or `name`, `current_count` or `currentValue` or `current`, and default missing `location` to `subscription`. Capture service name, quota name, current count, limit, utilization percentage, count source, limit source, limit type, and any errors. + + + ## 3. Separate reported and estimated limits + + + Separate API-reported quota limits from estimated default service limits. Treat estimated limits as directional and highlight where a service owner should verify the exact service quota before taking action. + + + ## 4. Flag quotas at risk + + + Flag quotas at or above 80% utilization, quotas with unknown current count due to Resource Graph or provider failures, and services where estimated limits could hide a real quota risk. + + + ## Report format + + + Produce a markdown report with an executive summary, a non-compute quota risk table, an API-reported versus estimated limits table, errors and access gaps, and recommended mitigation actions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Build chart data from normalized quota rows and use `.get()`/safe-access patterns instead of indexing fields like `location` directly, because subscription-scoped non-compute quota rows may not be regional. Include at minimum a quota utilization by service chart and an at-risk quota count by subscription chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/sku-availability-audit.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/sku-availability-audit.yaml new file mode 100644 index 000000000..7ac7e97e2 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/sku-availability-audit.yaml @@ -0,0 +1,86 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: SkuAvailabilityAudit +spec: + name: SkuAvailabilityAudit + description: Weekly audit of regional SKU availability and restrictions that could block deployments + cron_expression: 30 7 * * 3 + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# SKU Availability Audit + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to deployment region notes, restricted SKU findings, and planned capacity requests. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate SKU availability evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its capacity-management guidance and use the agent system-managed identity for Python tool authentication. + + + ## Specialist tools to request from `azure-capacity-manager` + + + Ask `azure-capacity-manager` to use Python tools with DefaultAzureCredential and the agent system-managed identity. + + + - `sku-availability`: Ask `azure-capacity-manager` to run with `subscription_id`, `location`, optional `sku_filter`, optional `resource_provider`. Use the default `resource_provider: compute` to list Compute SKU availability, zones, and restrictions. Use `resource_provider: kusto` for Azure Data Explorer / Kusto SKU eligibility checks before FinOps Hub analytics backend deployments or upgrades. + + + ## 1. Establish region and SKU scope + + + Identify deployment regions, priority VM SKU families, and any planned FinOps Hub Data Explorer SKUs from knowledge base notes and prior reports. If no priority SKU list exists, audit commonly deployed VM families and explicitly state the assumed scope. If no Data Explorer SKU list exists, include the currently planned or default Hub analytics backend SKU where documented; otherwise state that ADX scope is unknown. + + + ## 2. Collect SKU availability + + + Ask `azure-capacity-manager` to run `sku-availability` for each scoped subscription and region using `subscription_id`, `location`, optional `sku_filter`, `resource_provider`. + + + - For Compute, use `resource_provider: compute` or omit it to preserve the default behavior. Capture total SKUs, restricted SKUs, restriction reason codes, zone availability, and restriction values. + + - For Azure Data Explorer / Kusto, use `resource_provider: kusto`. Capture `source_endpoint`, returned SKUs, `requested_sku`, `is_available`, and any guidance. ADX Kusto SKU eligibility must use the Microsoft.Kusto regional SKU API and must not be inferred from Microsoft.Compute SKU results. + + + ## 3. Analyze deployment blockers + + + Identify restricted Compute SKUs that could block future deployments, scaling, zone alignment, or capacity reservation planning. Identify Kusto SKUs that are absent from the Microsoft.Kusto regional SKU response and could block FinOps Hub analytics deployments. Group findings by provider, reason code when available, region, zone, subscription, and family or SKU name. + + + ## 4. Recommend actions + + + Recommend whether to request quota, change SKU family, change region, adjust deployment zone, select a returned ADX SKU, or escalate to Azure capacity planning. Include uncertainty where planned demand is not documented. + + + ## Report format + + + Produce a markdown report with an executive summary, a restricted SKU table, a reason-code summary table, deployment blocker notes, and recommended mitigation actions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a restricted SKU count by region chart and a restriction reason-code chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/storage-paas-growth-forecast.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/storage-paas-growth-forecast.yaml new file mode 100644 index 000000000..3452bcdef --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/storage-paas-growth-forecast.yaml @@ -0,0 +1,87 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: StoragePaasGrowthForecast +spec: + name: StoragePaasGrowthForecast + description: Monthly storage and PaaS quota growth forecast across active subscriptions + cron_expression: 0 8 1 * * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Storage and PaaS Growth Forecast + + + ## Phase 0: Preparation + + + Before starting, read all documents in the knowledge base. Pay special attention to prior non-compute quota notes, known service limit assumptions, and subscription scope guidance. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Orchestration rule: This scheduled task is owned by `finops-practitioner`. Delegate storage and PaaS quota evidence collection and specialist analysis to `azure-capacity-manager`; do not try to run capacity tools directly from the practitioner. When the specialist returns evidence, assemble the final FinOps report, apply `ftk-output-style.md`, generate supported visualizations, and deliver the completed output through configured connectors. + + Ask `azure-capacity-manager` to load its capacity-management guidance and use the agent system-managed identity for Python tool authentication. + + + ## Specialist tools to request from `azure-capacity-manager` + + + Ask `azure-capacity-manager` to use Python tools with DefaultAzureCredential and the agent system-managed identity. + + + - `ftk-hubs-agent`: Run `resource-graph-query` with `query` and optional `subscription_ids` to inventory storage accounts, network resources, App Service plans, SQL servers, Service Bus namespaces, Key Vaults, and other PaaS resources. + + - `non-compute-quotas`: Run with `subscription_id` and optional `location` to retrieve storage, network, and estimated PaaS quota utilization. + + - `ftk-database-query`: Run `storage-tier-distribution` and `cost-per-gb-stored` when FinOps Hub Kusto is connected to add storage unit-economics KPI evidence to the quota forecast. + + + ## 1. Establish scope + + + Ask `ftk-hubs-agent` to use `resource-graph-query` to list active subscriptions and count current storage and PaaS resources by type, region, and subscription. Identify resource types with meaningful month-over-month growth or high operational importance. + + + ## 2. Collect current non-compute quotas + + + For each active subscription, ask `azure-capacity-manager` to run `non-compute-quotas` with `subscription_id`, optional `location`. Use the tool''s normalized `quotas` array for tables and charts. If only legacy `services` records are available, normalize them with safe accessors before reporting: accept `service_name` or `service`, `quota_name` or `name`, `current_count` or `currentValue` or `current`, and default missing `location` to `subscription`. Capture API-reported limits separately from estimated limits and preserve limit source notes. + + + ## 3. Forecast growth + + + Compare current resource counts and quota utilization against prior #remember findings or prior monthly reports. Forecast expected utilization for the next 30, 60, and 90 days using observed growth where prior data exists. + + Ask `ftk-database-query` to run `storage-tier-distribution` and `cost-per-gb-stored` for the same reporting window. Use storage tier mix and cost-per-GB trends to explain whether growth is also creating avoidable storage unit-cost risk. + + + ## 4. Flag subscriptions approaching limits + + + Flag subscriptions where storage, network, or PaaS quota utilization is at or above 80%, where estimated limits are uncertain, or where growth trends indicate a likely limit breach before the next monthly cycle. + + + ## Report format + + + Produce a markdown report with an executive summary, a quota risk table by subscription and service, a growth forecast table, explicit API-reported versus estimated limit notes, and recommended owner actions. + + + ## Persistence + + + **Teams and Outlook (results only):** Post the final report to our Teams channel. Do not post intermediate results. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge (#remember):** Save operational findings using #remember for future reference. Do not commit task reports, financial figures, cost amounts, or customer financial data to git or the knowledge base. Financial detail goes to configured Teams and Outlook delivery only. + + + ## Visualizations + + + Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Build chart data from normalized quota rows and use `.get()`/safe-access patterns instead of indexing fields like `location` directly, because subscription-scoped non-compute quota rows may not be regional. Include at minimum a 90-day forecast chart and a quota utilization comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml new file mode 100644 index 000000000..d8a5870e7 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml @@ -0,0 +1,186 @@ +api_version: azuresre.ai/v1 +kind: ScheduledTask +metadata: + name: Semiannual +spec: + name: Semiannual + description: Semiannual year-over-year financial analysis for January and July close checkpoints + cron_expression: 0 9 5 1,7 * + agent_mode: autonomous + agent: finops-practitioner + agent_prompt: '# Semiannual Financial Analysis + + + ## Phase 0: Preparation + + + Before starting any analysis, read all documents in the knowledge base. Pay special attention to known-issues-and-workarounds.md and any prior run notes. Use what you learn to avoid repeating known errors and to build on previous findings. + + Output style: Apply `ftk-output-style.md` from the knowledge base to every report, Teams message, and Outlook email message. Use its evidence labels, source/derivation rules, exact scope and time-period statements, FinOps capability sections, risk thresholds, confidence/caveat language, and disclaimer requirements. + + Tool routing and delivery guard: This scheduled task is owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools. Use subagent handoffs for all tool work and pass the full task scope, evidence already collected, open questions, and desired output shape with each handoff. Use `ftk-database-query` for FinOps Hub Kusto, cost, pricing, recommendation, and transaction query tools. Use `azure-capacity-manager` for capacity, quota, capacity reservation group, SKU availability, database service quota, and benefit recommendation Python tools. Use `ftk-hubs-agent` for FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment, remediation, alert and budget deployment, and Advisor suppression operations. Use `chief-financial-officer` only for executive finance framing. Use a tool-bearing specialist (`ftk-database-query`, `azure-capacity-manager`, or `ftk-hubs-agent`) for visualization and Teams/Outlook delivery after the final evidence package is assembled. Ask that delivery specialist to check available visualization and delivery tools exactly once per run and remember whether `PostTeamsMessage`, `SendOutlookEmail`, `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, and `ExecutePythonCode` are present. Do not call notification, email, connector, Microsoft Graph, `dynamicInvoke`, raw webhook, or connector APIs just to test availability. Use visualization tools first for charts when available, with `ExecutePythonCode` or code-interpreter chart generation only as a fallback. Complete the report before delivery. When a Teams connector/channel is configured, ask the delivery specialist to make one final `PostTeamsMessage` attempt to the configured Teams channel. When an Outlook connector/recipient is configured, ask the delivery specialist to make one final `SendOutlookEmail` attempt with the same final report and any generated chart artifacts. If a configured delivery path fails, mark the task/run failed instead of degrading to local output or probing alternate paths. If neither Teams nor Outlook delivery is configured or available, render the completed report in the run output and explicitly state which delivery paths were skipped. + + + + Load your finops-toolkit and azure-cost-management skills. Lead this as the FinOps practitioner. Delegate all FinOps Hub Kusto evidence collection to `ftk-database-query`, delegate capacity-risk evidence to `azure-capacity-manager`, and consult `chief-financial-officer` for fiscal planning, executive framing, and commitment-risk recommendations. + + + Our fiscal year runs July through June. This task runs on January 5 and July 5. On January 5, compare the completed July-December first-half period against the same period in the prior fiscal year and forecast through June 30. On July 5, compare the just-completed July-June fiscal year against the previous fiscal year and prepare the next fiscal year planning view. + + ## Specialist evidence requests for this task + + Do not run Kusto tools directly. Ask `ftk-database-query` to run fiscal cost, pricing, savings, recommendation, and transaction tools. Ask `azure-capacity-manager` to run `benefit-recommendations` and ask `ftk-hubs-agent` to run `resource-graph-query` where non-Kusto Azure Cost Management or resource-inventory evidence is needed. + + - `azure-capacity-manager`: Run `benefit-recommendations` with billing_scope and lookback to get reservation and savings plan recommendations + - `ftk-hubs-agent`: Run `data-freshness-check` with cluster_uri and database to check Hub data freshness + - `ftk-hubs-agent`: Run `resource-graph-query` with query and subscriptions to execute Azure Resource Graph KQL + + + ## Phase 1: Data Collection + + + ### 1.1 Verify Connectivity + + Ask `ftk-hubs-agent` to run `data-freshness-check` with the FinOps Hub cluster URI and Hub database. Treat its direct REST `Costs()` latest data date as the authoritative freshness source and mark any conflicting stale-memory, raw-KQL, or ingestion timestamp conclusion as superseded and unsafe. Proceed if latest `Costs()` data is 3 days old or newer. Do not ask for `costs-enriched-base` for freshness checks or fiscal-period reports; use aggregated Kusto tools for complete-month reporting windows and reserve row-level detail for one-day drill-downs only. + + + ### 1.2 Year-over-year trends + + Ask `ftk-database-query` to run `monthly-cost-trend` with startDate set to the start of the prior comparison period. Get month-by-month billed and effective cost for the current comparison period and the same prior-year period. + + + ### 1.3 Service Portfolio Analysis + + Ask `ftk-database-query` to run `top-services-by-cost` with N=20 for the current comparison period and the prior-year comparison period. Identify the top services driving year-over-year spend changes. + + + ### 1.4 Quarterly Resource Group Trends + + Ask `ftk-database-query` to run `quarterly-cost-by-resource-group` with N=10, covering the current and prior-year comparison periods. Identify quarterly growth patterns and material resource-group shifts. + + + ### 1.5 Fiscal Year Anomalies + + Ask `ftk-database-query` to run `cost-anomaly-detection` across the current and prior-year comparison periods. Use deep investigation on any significant anomalies or year-over-year discontinuities. + + + ### 1.6 Savings Realization + + Ask `ftk-database-query` to run `savings-summary-report` for the current and prior-year comparison periods. Calculate ESR, total savings, and year-over-year savings movement. + + + ### 1.7 Commitment Performance + + Ask `ftk-database-query` to run `commitment-discount-utilization` for the current and prior-year comparison periods. Assess how commitment purchases changed year over year. + + + ### 1.8 Financial Hierarchy + + Ask `ftk-database-query` to run `cost-by-financial-hierarchy` with N=10 for the current and prior-year comparison periods. Understand cost allocation across billing profiles, teams, and applications. + + + **Checkpoint:** Confirm year-over-year comparison data collection is complete. + + + ### 1.9 Forecast + + Ask `ftk-database-query` to run `cost-forecasting-model` using the current comparison period as actuals and enough historical data to project the next fiscal checkpoint. For January runs, forecast through June 30. For July runs, forecast the next fiscal year planning baseline. + + + ### 1.10 Reservation Recommendations + + Ask `azure-capacity-manager` to run `benefit-recommendations` and ask `ftk-database-query` to run `reservation-recommendation-breakdown`. Identify commitments that could save money before fiscal year end. + + + ### 1.11 Regional Analysis + + Ask `ftk-database-query` to run `cost-by-region-trend` for the current and prior-year comparison periods. Identify regional cost shifts. + + + ### 1.12 Resource Type Efficiency + + Ask `ftk-hubs-agent` to run `resource-graph-query` for current Azure resource inventory, then ask `ftk-database-query` to run `top-resource-types-by-cost` with N=20 for the current and prior-year comparison periods. Track resource type evolution. + + + ### 1.13 Price Benchmarking + + Ask `ftk-database-query` to run `service-price-benchmarking` for the current and prior-year comparison periods. Benchmark pricing effectiveness year over year. + + + ### 1.14 Month-over-Month Volatility + + Ask `ftk-database-query` to run `monthly-cost-change-percentage` covering both comparison periods. Identify the most volatile months and distinguish month-over-month volatility from true year-over-year movement. + + + ### 1.15 Commitment Transactions + + Ask `ftk-database-query` to run `top-commitment-transactions` with N=20 for the current and prior-year comparison periods. Track major RI/SP purchases. If it returns zero rows or `ZERO_ROWS_RETURNED`, ask `ftk-hubs-agent` to run `data-freshness-check` and report whether `Transactions()` has the `TRANSACTIONS_ZERO_ROWS` diagnostic. Do not conclude there were no commitment purchases until the export, ingestion, and stored-function diagnostic is clear. + + + ### 1.16 Other Transactions + + Ask `ftk-database-query` to run `top-other-transactions` with N=20 for the current and prior-year comparison periods. If it returns zero rows or `ZERO_ROWS_RETURNED`, ask `ftk-hubs-agent` to run `data-freshness-check` and report whether `Transactions()` has the `TRANSACTIONS_ZERO_ROWS` diagnostic. Do not conclude there were no non-usage spend patterns until the export, ingestion, and stored-function diagnostic is clear. + + + ### 1.17 Fiscal FinOps KPI Scorecard + + Ask `ftk-database-query` to run the full FinOps KPI tool set from `src/queries/KPI.md` for the current fiscal comparison period and, where the query supports date windows, the prior-year comparison period: `percentage-unallocated-costs`, `percentage-untagged-costs`, `tagging-policy-compliance`, `allocation-accuracy-index`, `anomaly-detection-rate`, `anomaly-variance-total`, `monthly-cost-trend`, `cost-visibility-delay`, `data-update-frequency`, `macc-consumption-vs-commitment`, `ai-token-usage-breakdown`, `ai-daily-trend`, `ai-model-cost-comparison`, `commitment-utilization-score`, `compute-cost-per-core`, `savings-summary-report`, `compute-spend-commitment-coverage`, `commitment-discount-waste`, `cost-optimization-index`, `storage-tier-distribution`, and `cost-per-gb-stored`. + + Build the year-over-year KPI scorecard from those outputs. Separate direct KPI measurements from derived executive interpretation, and classify unavailable KPI rows as data sufficiency limitations with the exact source tool named. + + + **Checkpoint:** ALL data collected. Proceed to strategic analysis. + + + ## Phase 2: Strategic Analysis + + + ### 2.1 Year-over-year scorecard + + Grade year-over-year performance (A+ to F) across: cost management, savings realization, commitment coverage, tag compliance, forecast accuracy, and forecast risk. + + + ### 2.2 Forecast + + For January runs, project total fiscal year spend with Conservative/Expected/Optimistic scenarios and compare to annual budget. For July runs, create the next fiscal year planning baseline. + + + ### 2.3 Savings opportunities + + Identify quick-win optimization opportunities that can reduce costs before the next fiscal checkpoint. Prioritize by days remaining and implementation effort. + + + ### 2.4 Fiscal planning + + Based on year-over-year trends, recommend budget changes, commitment purchase strategy, and optimization roadmap. + + + ### 2.5 Detailed Findings + + 7 sections: Cost Analysis, Savings Analysis, Optimization, Governance, Market Positioning, Temporal Themes, Implementation Roadmap. + + + ### 2.6 Recommendations + + Prioritized actions: before the next fiscal checkpoint, next half-year, and next full fiscal year. Dollar amounts and owners for each. + + + ## Phase 3: Report + + + Professional executive report with tables, charts, emoji indicators. Include year-over-year variance, fiscal timeline, forecast scenarios, grade card, and planning recommendations. + + + Do not stop or yield until the report is complete and ready for the FinOps team. + + + ## Phase 4: Deliver + + + + **Visualizations:** Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum one trend chart and one comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed the chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables. Charts make the report immediately actionable for stakeholders who scan rather than read. + + **Teams and Outlook (financial results only):** Post the final report to our Teams channel. Include the year-over-year scorecard, forecast scenarios, and planning recommendations. Do not post intermediate results — only the completed report. Ask the selected delivery specialist to use `PostTeamsMessage` and `SendOutlookEmail` only when the delivery guard found each tool available once per run. If neither Teams nor Outlook delivery is configured or available, return the completed report in the run output with a note naming the skipped delivery paths. If any configured Teams or Outlook final delivery attempt fails, do not retry or probe alternate delivery paths; mark the task/run failed. + + + **Knowledge base (operational learnings only):** Save any new operational insights to the knowledge base — tool errors encountered, workarounds discovered, data quality observations, query patterns that worked or failed. Never save financial figures, cost amounts, savings numbers, or any customer financial data to the knowledge base. Financial detail goes to configured Teams and Outlook delivery only.' diff --git a/src/templates/sre-agent/recipes/finops-hub/config/built-in-tools.json b/src/templates/sre-agent/recipes/finops-hub/config/built-in-tools.json new file mode 100644 index 000000000..bfd49cc2f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/built-in-tools.json @@ -0,0 +1,40 @@ +{ + "overrides": [ + { + "name": "QueryLogAnalyticsByWorkspaceId", + "enabled": true + }, + { + "name": "QueryAppInsightsByAppId", + "enabled": true + }, + { + "name": "QueryAppInsightsByResourceId", + "enabled": true + }, + { + "name": "QueryLogAnalyticsByResourceId", + "enabled": true + }, + { + "name": "PlotScatter", + "enabled": true + }, + { + "name": "PlotHeatmap", + "enabled": true + }, + { + "name": "PlotBarChart", + "enabled": true + }, + { + "name": "PlotPieChart", + "enabled": true + }, + { + "name": "PlotAreaChartWithCorrelation", + "enabled": true + } + ] +} diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md new file mode 120000 index 000000000..2c7fa82d2 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md @@ -0,0 +1 @@ +../../../../../submodules/azcapman/skills/azure-capacity-management/SKILL.md \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs new file mode 120000 index 000000000..faec10874 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs @@ -0,0 +1 @@ +../../../../../../submodules/azcapman/docs \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts new file mode 120000 index 000000000..487d8d51b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts @@ -0,0 +1 @@ +../../../../../../submodules/azcapman/scripts \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/README.md new file mode 100644 index 000000000..2a8772d00 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/README.md @@ -0,0 +1,48 @@ +# Azure Cost Management skill + +Cost optimization and financial governance for Azure. Provides domain knowledge for Azure Advisor recommendations, commitment discounts (savings plans and reservations), budgets, cost exports, anomaly alerts, credits, and MACC tracking. + +## When this skill activates + +Triggered when you ask about: Azure Advisor, cost recommendations, savings plans, reservations, Azure budgets, cost exports, anomaly alerts, MACC, Azure credits, Azure Prepayment, commitment discounts, or cost optimization. + +## Prerequisites + +- Azure CLI authenticated (`az login`) +- Appropriate RBAC permissions for Cost Management APIs + +## Domains + +| Domain | Purpose | Key operations | +|--------|---------|----------------| +| **Azure Advisor** | Cost recommendations | Query, suppress, and manage recommendations (up to 90-day TTL suppression, bulk via management groups) | +| **Savings plans and reservations** | Commitment discount analysis | Benefit recommendations, coverage analysis, ROI calculations | +| **Budgets** | Budget management | Create budgets with up to 5 notifications, actual/forecasted thresholds, action groups | +| **Cost exports** | Scheduled data exports | FOCUS format exports to storage accounts with backfill support | +| **Anomaly alerts** | Cost spike detection | Enterprise-scale anomaly alert deployment with pagination | +| **Credits** | Azure Prepayment tracking | EA/MCA credit balances, expiration dates, consumption history | +| **MACC** | Consumption commitment tracking | Balance, decrements, milestone progress, eligible spend | + +## Reference documentation + +Each domain has a detailed reference file loaded on demand: + +| File | Contents | +|------|----------| +| `references/azure-advisor.md` | Recommendation queries, suppression workflows, management group bulk operations | +| `references/azure-savings-plans.md` | Benefit Recommendations API, savings plan vs reservation comparison, coverage analysis | +| `references/azure-budgets.md` | Budget creation, notification thresholds, action group integration | +| `references/azure-cost-exports.md` | FOCUS export configuration, backfill procedures, troubleshooting | +| `references/azure-anomaly-alerts.md` | Bulk anomaly alert deployment across subscriptions | +| `references/azure-credits.md` | EA/MCA credit balance tracking, expiration risk assessment | +| `references/azure-macc.md` | MACC balance monitoring, decrement tracking, milestone progress | + +## Quick examples + +```bash +# List cost recommendations +az advisor recommendation list --category Cost --output table + +# List budgets +az consumption budget list --output table +``` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/SKILL.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/SKILL.md new file mode 100644 index 000000000..41dcfd46e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/SKILL.md @@ -0,0 +1,195 @@ +--- +name: azure-cost-management +description: Azure cost optimization and financial governance. Use for Advisor recommendations, commitment discounts (reservations and savings plans), budgets, cost exports, anomaly alerts, credit and MACC tracking, orphaned resource detection, VM rightsizing, and retail price lookup. +license: MIT +compatibility: Requires Azure CLI authentication (az login) and appropriate RBAC permissions for Cost Management APIs. +metadata: + author: microsoft + version: "1.1.0" +allowed-tools: az pwsh curl +--- + +# Azure Cost Management + +Azure Cost Management and optimization skills. Provides recommendations, budget management, exports, alerts, and commitment tracking capabilities. + +## Domain Knowledge + +| Domain | Purpose | Key Operations | +|--------|---------|----------------| +| **azure-advisor** | Cost recommendations | Query, suppress, manage recommendations | +| **azure-savings-plans** | Savings plan analysis | Benefit recommendations, coverage, ROI | +| **azure-budgets** | Budget management | Create budgets, notifications, action groups | +| **azure-cost-exports** | Scheduled exports | FOCUS exports, backfill, troubleshooting | +| **azure-anomaly-alerts** | Cost anomaly detection | Bulk alert deployment across subscriptions | +| **azure-reservations** | Reserved instance analysis | Reservation recommendations, utilization, coverage, exchange/return | +| **azure-commitment-discount-decision** | Commitment discount framework | Reservations vs savings plans decision criteria, hybrid strategy | +| **azure-credits** | Credit tracking | Azure Prepayment balance, expiration risk | +| **azure-macc** | MACC commitment tracking | Balance, decrements, milestone tracking | +| **azure-orphaned-resources** | Waste detection | Resource Graph queries for orphaned/unused resources | +| **azure-retail-prices** | Price lookup | Public API for SKU pricing, cross-region comparison | +| **azure-vm-rightsizing** | VM optimization | Utilization analysis, SKU downsize recommendations | + +## Cost Optimization + +### Azure Advisor Recommendations + +```bash +az advisor recommendation list --category Cost --output table +``` + +**Suppression:** Up to 90-day TTL, bulk suppression via management groups. + +For detailed documentation: `references/azure-advisor.md` + +### Orphaned resources + +Detect unused resources generating waste with zero workload value. Immediate savings, zero risk. + +```bash +az graph query -q "resources | where type == 'microsoft.compute/disks' | where properties.diskState == 'Unattached' | project name, resourceGroup, sizeGb = properties.diskSizeGB" +``` + +Covers: unattached disks, unused NICs, orphaned public IPs, idle NAT gateways, orphaned snapshots, idle load balancers, empty availability sets, orphaned NSGs. + +For detailed documentation: `references/azure-orphaned-resources.md` + +### VM rightsizing + +Identify over-provisioned VMs using Advisor + Azure Monitor metrics, validate with retail pricing. + +- Thresholds: CPU P95 < 20%, memory avg < 30% +- Safety checks: burst requirements (P99), instance size flexibility, Hybrid Benefit + +For detailed documentation: `references/azure-vm-rightsizing.md` + +### Savings plans and reservations + +**Benefit Recommendations API** for: +- Savings plan purchase recommendations (up to 65% savings) +- Reservation recommendations (up to 72% savings) +- Coverage analysis and utilization monitoring +- Decision framework: when to use which commitment type + +For detailed documentation: +- `references/azure-savings-plans.md` — savings plan analysis and script +- `references/azure-reservations.md` — reserved instance analysis +- `references/azure-commitment-discount-decision.md` — decision framework + +### Azure Retail Prices + +Public API for looking up Azure pricing by SKU, region, and tier. No authentication required. + +``` +https://prices.azure.com/api/retail/prices?$filter=armSkuName eq 'Standard_D4s_v5' and armRegionName eq 'eastus' +``` + +Use for: price comparisons, rightsizing savings validation, cross-region cost analysis. + +For detailed documentation: `references/azure-retail-prices.md` + +## Budget & Alerts + +### Budgets + +- Up to 5 notifications per budget +- Action Groups at Subscription/Resource Group scope only +- Threshold types: Actual, Forecasted + +```bash +az consumption budget list --output table +``` + +For detailed documentation: `references/azure-budgets.md` + +### Anomaly Alerts + +Enterprise-scale deployment with pagination for large environments. + +For detailed documentation: `references/azure-anomaly-alerts.md` + +### Cost Exports + +FOCUS format exports to storage accounts with backfill support. + +For detailed documentation: `references/azure-cost-exports.md` + +## Commitment Tracking + +### Azure Credits (Prepayment) + +Track EA/MCA credit balances, expiration dates, consumption history. + +For detailed documentation: `references/azure-credits.md` + +### MACC (Azure Consumption Commitment) + +Track MACC balance, decrements, milestone progress, eligible spend. + +For detailed documentation: `references/azure-macc.md` + +## Reference documentation + +- **Optimization**: `references/azure-advisor.md`, `references/azure-savings-plans.md`, `references/azure-reservations.md` +- **Waste detection**: `references/azure-orphaned-resources.md` +- **Rightsizing**: `references/azure-vm-rightsizing.md`, `references/azure-retail-prices.md` +- **Decision framework**: `references/azure-commitment-discount-decision.md` +- **Budgets and alerts**: `references/azure-budgets.md`, `references/azure-anomaly-alerts.md`, `references/azure-cost-exports.md` +- **Commitments**: `references/azure-credits.md`, `references/azure-macc.md` + +Load the appropriate reference file when detailed workflows, API examples, or troubleshooting are needed. + +## Safety + +**Always confirm with the user before executing any delete, remove, or purge operation.** This includes `Remove-AzDisk`, `az network public-ip delete`, `az disk delete`, and any bulk cleanup scripts. Show the list of resources to be deleted and wait for explicit approval before proceeding. Never infer consent from a general "clean up orphaned resources" request. + +## Best practices + +### Cost API queries + +Use `az rest` with a JSON body rather than `az costmanagement query` — it is more reliable and supports the full query schema: + +```bash +az rest --method post \ + --url "https://management.azure.com/subscriptions//providers/Microsoft.CostManagement/query?api-version=2023-11-01" \ + --body '@cost-query.json' +``` + +### Free tier awareness + +Many Azure services have generous free allowances that explain $0 cost lines. Do not flag these as anomalies. Examples: +- Container Apps: 180K vCPU-sec and 360K GB-sec free per month +- Azure Functions: 1M executions free per month +- Log Analytics: first 5 GB/month free per workspace + +### Azure Quick Review (azqr) + +For broad orphaned resource scanning, [Azure Quick Review](https://azure.github.io/azqr/) (`azqr`) can scan entire subscriptions efficiently and identify orphaned resources, oversized SKUs, and missing tags in one pass. Complement the Resource Graph queries in `references/azure-orphaned-resources.md` with azqr for large environments. + +### Azure portal links + +Include deep links to resources when presenting recommendations. Use this format (includes tenant context): + +``` +https://portal.azure.com/#@/resource/subscriptions//resourceGroups//providers////overview +``` + +## Data classification + +When presenting cost data, label the source clearly so recommendations are auditable: + +- **ACTUAL DATA** — Retrieved from Azure Cost Management API +- **ACTUAL METRICS** — Retrieved from Azure Monitor +- **VALIDATED PRICING** — Retrieved from official Azure pricing pages (`prices.azure.com`) +- **ESTIMATED SAVINGS** — Calculated from actual data and validated pricing + +Never present estimates as actuals. + +## Common pitfalls + +- **Assuming costs**: Always query actual data from the Cost Management API before making recommendations. +- **Ignoring free tiers**: Validate $0 cost lines against known free allowances before treating them as anomalies. +- **Using `az costmanagement query`**: Prefer `az rest` — the CLI command has known reliability issues with complex queries. +- **Wrong date ranges**: Use 30 days for cost analysis, 14 days for utilization metrics. +- **Broken portal links**: Always include tenant ID in portal URLs. +- **Presenting estimates as actuals**: Use the data classification labels above to be explicit about the source of every number. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 new file mode 100644 index 000000000..95b45b9e6 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 @@ -0,0 +1,76 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# +.SYNOPSIS + Get Azure Cost Management benefit recommendations for savings plans and reserved instances. + +.DESCRIPTION + This script queries the Azure Cost Management API to retrieve benefit recommendations + based on historical usage patterns. It helps identify opportunities for cost savings + through Azure savings plans and reserved instances. + +.PARAMETER BillingScope + The billing scope to query. Can be a billing account or subscription. + Examples: + - "providers/Microsoft.Billing/billingAccounts/12345678" + - "subscriptions/12345678-1234-1234-1234-123456789012" + +.PARAMETER LookBackPeriod + Historical period to analyze for recommendations. + Valid values: Last7Days, Last30Days, Last60Days + Default: Last7Days + +.PARAMETER Term + Commitment term for savings plans. + Valid values: P1Y (1 year), P3Y (3 years) + Default: P3Y + +.EXAMPLE + .\Get-BenefitRecommendations.ps1 -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" + + Gets 3-year savings plan recommendations for a subscription based on last 7 days usage. + +.EXAMPLE + .\Get-BenefitRecommendations.ps1 -BillingScope "providers/Microsoft.Billing/billingAccounts/12345678" -LookBackPeriod "Last30Days" -Term "P1Y" + + Gets 1-year savings plan recommendations for a billing account based on last 30 days usage. + +.NOTES + Requires Azure PowerShell module and Cost Management Reader permissions on the specified scope. + + To find your billing account: Get-AzBillingAccount + To find subscriptions: Get-AzSubscription +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $true, HelpMessage = "Billing scope (billing account or subscription)")] + [string] + $BillingScope, + + [Parameter()] + [ValidateSet('Last7Days', 'Last30Days', 'Last60Days')] + [string] + $LookBackPeriod = 'Last7Days', + + [Parameter()] + [ValidateSet('P1Y', 'P3Y')] + [string] + $Term = 'P3Y' +) + +$url="https://management.azure.com/{0}/providers/Microsoft.CostManagement/benefitRecommendations?`$filter=properties/lookBackPeriod eq '{1}' AND properties/term eq '{2}'&`$expand=properties/usage,properties/allRecommendationDetails&api-version=2024-08-01" -f $BillingScope, $LookBackPeriod, $Term +$uri=[uri]::new($url) +$result = Invoke-AzRestMethod -Uri $uri.AbsoluteUri -Method GET +$jsonResult = $result.Content | ConvertFrom-Json + +Write-Output "" +Write-Output "Raw output" +$result.Content +Write-Output "" +Write-Output "Recommended savings plan" +$jsonResult.value.properties.recommendationDetails | Format-Table +Write-Output "" +Write-Output "All savings plan recommendations" +$jsonResult.value.properties.allRecommendationDetails.value | Format-Table \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md new file mode 100644 index 000000000..4735c55e1 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md @@ -0,0 +1,259 @@ +--- +name: Azure Advisor +description: Azure Advisor provides personalized recommendations for optimizing Azure resources across cost, security, reliability, operational excellence, and performance. This skill focuses on **cost recommendations** and recommendation management. +--- + +**Key Features:** +- Cost optimization recommendations (right-sizing, shutdown, reservations) +- Recommendation suppression with TTL (up to 90 days) +- Bulk suppression across management groups +- Integration with FinOps workflows + +--- + +## Querying Cost Recommendations + +### Azure CLI + +```bash +# List all cost recommendations for a subscription +az advisor recommendation list \ + --category Cost \ + --output table + +# List with details +az advisor recommendation list \ + --category Cost \ + --query "[].{Resource:resourceGroup, Impact:impact, Description:shortDescription.problem}" + +# Filter by impact +az advisor recommendation list \ + --category Cost \ + --query "[?impact=='High']" +``` + +### PowerShell + +```powershell +# Get all cost recommendations +Get-AzAdvisorRecommendation | + Where-Object { $_.Category -eq 'Cost' } + +# Get high-impact recommendations +Get-AzAdvisorRecommendation | + Where-Object { $_.Category -eq 'Cost' -and $_.Impact -eq 'High' } + +# Export to CSV +Get-AzAdvisorRecommendation | + Where-Object { $_.Category -eq 'Cost' } | + Select-Object ResourceId, Impact, ShortDescriptionProblem | + Export-Csv -Path "advisor-recommendations.csv" +``` + +### REST API + +> **Authentication note:** Use `az rest` in practice — it handles token acquisition automatically. The raw HTTP examples below are for documentation purposes only. + +```http +GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Advisor/recommendations?api-version=2023-01-01&$filter=Category eq 'Cost' +Authorization: Bearer {token} +``` + +--- + +## Common Cost Recommendation Types + +| Recommendation Type | ID | Description | +|--------------------|-----|-------------| +| Right-size VMs | `e10b1381-5f0a-47ff-8c7b-37bd13d7c974` | Resize underutilized VMs — see `references/azure-vm-rightsizing.md` for full validation workflow | +| Shutdown idle VMs | `89515250-1243-43d1-b4e7-f9437cedffd8` | Stop VMs with low utilization | +| Reserved instances | `84b1a508-fc21-49da-979e-96894f1665df` | Purchase RIs for consistent workloads | +| Delete unused disks | `48eda464-1485-4dcf-a674-d0905df5054a` | Remove unattached managed disks — see `references/azure-orphaned-resources.md` for expanded orphaned resource detection | + +--- + +## Suppressing Recommendations + +Azure Policy cannot disable Advisor recommendations. Instead, use the Advisor suppression API with TTL up to 90 days. + +### PowerShell Suppression Script + +```powershell +# Suppress specific recommendation types across a management group +.\Suppress-AdvisorRecommendations.ps1 -ManagementGroupId "your-mg" ` + -RecommendationTypeIds @( + "89515250-1243-43d1-b4e7-f9437cedffd8", # Shutdown idle VMs + "84b1a508-fc21-49da-979e-96894f1665df", # Reserved instances + "48eda464-1485-4dcf-a674-d0905df5054a" # Delete unused disks + ) -Days 30 -WhatIf + +# Execute suppression +.\Suppress-AdvisorRecommendations.ps1 -ManagementGroupId "your-mg" ` + -RecommendationTypeIds @(...) -Days 30 +``` + +### REST API Suppression + +> **Authentication note:** Use `az rest` in practice — it handles token acquisition automatically. The raw HTTP example below is for documentation purposes only. + +```http +PUT https://management.azure.com/{resourceUri}/providers/Microsoft.Advisor/recommendations/{recommendationId}/suppressions/{suppressionName}?api-version=2023-01-01 +Content-Type: application/json +Authorization: Bearer {token} + +{ + "properties": { + "ttl": "30:00:00:00" + } +} +``` + +**TTL Format:** `days:hours:minutes:seconds` (max 90 days) + +> **Dismiss vs postpone:** To permanently dismiss a recommendation instead of postponing it, omit the `ttl` property (send `"properties": {}` in the PUT body). The recommendation will remain hidden indefinitely with no automatic reappearance. Permanent dismissals can be reversed via the [Suppressions DELETE API](https://learn.microsoft.com/en-us/rest/api/advisor/suppressions/delete) or by clicking "Activate" under the Advisor portal's "Postponed & Dismissed" filter. Prefer postpone with TTL over permanent dismiss for cost recommendations, since dismissed recommendations silently stop surfacing even when resource conditions change. Reserve permanent dismissal for recommendations that are structurally irrelevant to your environment. + +### List Suppressions + +```http +GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Advisor/suppressions?api-version=2023-01-01 +``` + +### Delete Suppression + +```http +DELETE https://management.azure.com/{resourceUri}/providers/Microsoft.Advisor/recommendations/{recommendationId}/suppressions/{suppressionName}?api-version=2023-01-01 +``` + +--- + +## Scheduled Suppression Refresh + +Since suppression TTL is capped at 90 days, schedule weekly refreshes via: + +- **Azure Automation** - Runbook on schedule +- **CI/CD Pipeline** - GitHub Actions or Azure DevOps +- **Logic Apps** - Recurrence trigger + +Example Azure Automation schedule: + +```powershell +# Create automation schedule +New-AzAutomationSchedule -AutomationAccountName "MyAutomation" ` + -Name "WeeklyAdvisorSuppression" ` + -StartTime (Get-Date).AddDays(1) ` + -WeekInterval 1 ` + -DaysOfWeek "Monday" ` + -ResourceGroupName "automation-rg" +``` + +--- + +## Permissions + +| Action | Required Role | +|--------|---------------| +| View recommendations | Reader | +| Suppress recommendations | Advisor Contributor | +| Bulk management group operations | Advisor Contributor on MG and subscriptions | + +--- + +## Azure Resource Graph Queries + +### All Cost Recommendations + +```kusto +advisorresources +| where type == "microsoft.advisor/recommendations" +| where properties.category == "Cost" +| project + subscriptionId, + resourceGroup, + impact = properties.impact, + problem = properties.shortDescription.problem, + solution = properties.shortDescription.solution, + savings = properties.extendedProperties.savingsAmount +``` + +### High-Impact Recommendations with Savings + +```kusto +advisorresources +| where type == "microsoft.advisor/recommendations" +| where properties.category == "Cost" +| where properties.impact == "High" +| extend savings = todouble(properties.extendedProperties.savingsAmount) +| summarize + TotalSavings = sum(savings), + Count = count() + by subscriptionId +| order by TotalSavings desc +``` + +### Recommendations by Type + +```kusto +advisorresources +| where type == "microsoft.advisor/recommendations" +| where properties.category == "Cost" +| summarize Count = count() by tostring(properties.recommendationTypeId) +| order by Count desc +``` + +--- + +## Integration with FinOps Workflows + +### Export Recommendations for Analysis + +```powershell +# Get all cost recommendations across subscriptions +$recommendations = Get-AzSubscription | ForEach-Object { + Set-AzContext -Subscription $_.Id + Get-AzAdvisorRecommendation | + Where-Object { $_.Category -eq 'Cost' } +} + +# Calculate total potential savings +$totalSavings = $recommendations | + Where-Object { $_.ExtendedProperty["savingsAmount"] } | + ForEach-Object { [double]$_.ExtendedProperty["savingsAmount"] } | + Measure-Object -Sum + +Write-Host "Total potential monthly savings: $($totalSavings.Sum)" +``` + +### Prioritize by Impact and Savings + +```powershell +$recommendations | + Select-Object @{N='Resource';E={$_.ResourceId}}, + Impact, + @{N='Savings';E={[double]($_.ExtendedProperty["savingsAmount"] ?? 0)}}, + @{N='ImpactRank';E={ @{'High'=3;'Medium'=2;'Low'=1}[$_.Impact] }}, + @{N='Problem';E={$_.ShortDescriptionProblem}} | + Sort-Object -Property @{E='ImpactRank';D=$true}, @{E='Savings';D=$true} | + Select-Object Resource, Impact, Savings, Problem | + Format-Table +``` + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| No recommendations | New subscription | Wait 24-48 hours for analysis | +| Suppression fails | Missing permissions | Need Advisor Contributor role | +| Suppression expired | TTL exceeded | Re-run suppression script | +| Wrong savings estimate | Stale data | Refresh recommendations | + +--- + +## References + +- [Azure Advisor overview](https://learn.microsoft.com/azure/advisor/advisor-overview) +- [Cost recommendations](https://learn.microsoft.com/azure/advisor/advisor-cost-recommendations) +- [Suppress recommendations](https://learn.microsoft.com/azure/advisor/view-recommendations#dismissing-and-postponing-recommendations) +- [Advisor REST API](https://learn.microsoft.com/rest/api/advisor/) + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md new file mode 100644 index 000000000..8aa95b594 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md @@ -0,0 +1,292 @@ +--- +name: Azure Cost Anomaly Alerts +description: Deploy cost anomaly detection alerts across Azure subscriptions at enterprise scale. These alerts automatically notify stakeholders when Cost Management detects unusual spending patterns. +--- + +**Resource Type:** `Microsoft.CostManagement/scheduledActions` (InsightAlert type) + +**Key Features:** +- Automated cost anomaly detection +- Email notifications when anomalies detected +- Enterprise-scale bulk deployment with pagination +- Management group targeting + +--- + +## What Gets Deployed + +- **Cost Management scheduled action** named "AnomalyAlert" +- **Anomaly detection** monitoring at subscription level +- **Email notifications** to specified recipients when anomalies are detected + +--- + +## PowerShell Deployment + +### Prerequisites + +```powershell +# Install required modules +Install-Module -Name Az -Force -AllowClobber +Install-Module -Name Az.ResourceGraph -Force -AllowClobber # For bulk deployments + +# Authenticate +Connect-AzAccount +``` + +### Single Subscription Deployment + +```powershell +# Interactive subscription selection +./Deploy-AnomalyAlert.ps1 ` + -EmailRecipients @("admin@company.com", "finance@company.com") ` + -NotificationEmail "alerts@company.com" + +# Specific subscription +./Deploy-AnomalyAlert.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" + +# Preview without deploying +./Deploy-AnomalyAlert.ps1 ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" ` + -WhatIf + +# Automated/silent deployment +./Deploy-AnomalyAlert.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" ` + -Force -Quiet +``` + +### Enterprise Bulk Deployment + +```powershell +# Deploy to all subscriptions in management group +./Deploy-BulkALZ.ps1 ` + -TenantId "12345678-1234-1234-1234-123456789012" ` + -ManagementGroup "ALZ" ` + -EmailRecipients @("finops@company.com", "alerts@company.com") ` + -NotificationEmail "alerts@company.com" + +# Preview deployment +./Deploy-BulkALZ.ps1 ` + -TenantId "12345678-1234-1234-1234-123456789012" ` + -ManagementGroup "ALZ" ` + -EmailRecipients @("finops@company.com") ` + -NotificationEmail "alerts@company.com" ` + -WhatIf + +# Quiet enterprise deployment +./Deploy-BulkALZ.ps1 ` + -TenantId "12345678-1234-1234-1234-123456789012" ` + -ManagementGroup "ALZ" ` + -EmailRecipients @("finops@company.com") ` + -NotificationEmail "alerts@company.com" ` + -Quiet +``` + +### Parameters + +**Deploy-AnomalyAlert.ps1:** + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `EmailRecipients` | Yes | Array of email addresses for notifications | +| `NotificationEmail` | Yes | Primary email for the alert system | +| `SubscriptionId` | No | Target subscription (interactive if not provided) | +| `DeploymentName` | No | Custom deployment name | +| `Location` | No | Azure region (default: West US) | +| `Force` | No | Skip confirmation prompts | +| `Quiet` | No | Suppress verbose output | +| `WhatIf` | No | Preview without deploying | + +**Deploy-BulkALZ.ps1:** + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `TenantId` | Yes | Azure tenant ID | +| `ManagementGroup` | Yes | Management group name | +| `EmailRecipients` | Yes | Array of email addresses | +| `NotificationEmail` | Yes | Primary email for alerts | +| `WhatIf` | No | Preview without deploying | +| `Quiet` | No | Suppress warnings | + +--- + +## Enterprise Pagination + +The bulk deployment script handles large environments with automatic pagination: + +``` +Connecting to tenant... +Finding subscriptions in ALZ management group... +Querying subscriptions (page 1)... +Found 1000 subscriptions in this page (total: 1000) +Querying subscriptions (page 2)... +Found 1000 subscriptions in this page (total: 2000) +Querying subscriptions (page 3)... +Found 847 subscriptions in this page (total: 2847) +Total subscriptions found: 2847 +``` + +**Key Features:** +- Processes 1,000 subscriptions per query page +- Automatic pagination for 5,000+ subscription environments +- Real-time progress reporting +- Memory-efficient processing + +--- + +## Bicep Template + +```bicep +targetScope = 'subscription' + +@description('Email recipients for anomaly notifications') +param emailRecipients array + +@description('Primary notification email') +param notificationEmail string + +module anomalyAlert 'br/public:cost/subscription-scheduled-action:1.0.2' = { + name: 'anomaly-alert-deployment' + params: { + name: 'AnomalyAlert' + displayName: 'Cost Anomaly Alert' + kind: 'InsightAlert' + notification: { + to: emailRecipients + subject: 'Cost Anomaly Detected' + } + notificationEmail: notificationEmail + } +} +``` + +--- + +## Azure CLI Deployment + +```bash +az deployment sub create \ + --name "anomaly-alert-deployment" \ + --location "West US" \ + --template-file "anomaly-alert.bicep" \ + --parameters emailRecipients='["admin@company.com"]' \ + notificationEmail="alerts@company.com" +``` + +### Validation + +```bash +# Validate template +az deployment sub validate \ + --location "West US" \ + --template-file "anomaly-alert.bicep" \ + --parameters "@anomaly-alert.parameters.json" + +# What-if analysis +az deployment sub what-if \ + --location "West US" \ + --template-file "anomaly-alert.bicep" \ + --parameters "@anomaly-alert.parameters.json" +``` + +--- + +## Custom Bulk Deployment + +### Deploy to Filtered Subscriptions + +```powershell +# Deploy only to production subscriptions +$emailRecipients = @("finops@company.com") +$notificationEmail = "alerts@company.com" + +$subscriptions = Search-AzGraph -Query @" +ResourceContainers +| where type =~ 'microsoft.resources/subscriptions' +| where name contains 'Prod' or name contains 'Production' +| project subscriptionId, name +"@ + +Write-Host "Found $($subscriptions.Count) production subscriptions" + +foreach ($sub in $subscriptions) { + Write-Host "Deploying to: $($sub.name)" -ForegroundColor Yellow + ./Deploy-AnomalyAlert.ps1 ` + -SubscriptionId $sub.subscriptionId ` + -EmailRecipients $emailRecipients ` + -NotificationEmail $notificationEmail ` + -Force +} +``` + +### Deploy with Validation First + +```powershell +$managementGroupName = "Development" +$subscriptions = Search-AzGraph -Query @" +ResourceContainers +| where type =~ 'microsoft.resources/subscriptions' +| project subscriptionId, name +"@ -ManagementGroup $managementGroupName + +# Validation phase +Write-Host "=== VALIDATION PHASE ===" -ForegroundColor Magenta +foreach ($sub in $subscriptions) { + Write-Host "Validating: $($sub.name)" -ForegroundColor Cyan + ./Deploy-AnomalyAlert.ps1 ` + -SubscriptionId $sub.subscriptionId ` + -EmailRecipients @("test@company.com") ` + -NotificationEmail "test@company.com" ` + -WhatIf +} + +# Confirmation +$confirm = Read-Host "Proceed with deployment? (y/N)" +if ($confirm -eq 'y') { + Write-Host "=== DEPLOYMENT PHASE ===" -ForegroundColor Magenta + foreach ($sub in $subscriptions) { + ./Deploy-AnomalyAlert.ps1 ` + -SubscriptionId $sub.subscriptionId ` + -EmailRecipients @("alerts@company.com") ` + -NotificationEmail "alerts@company.com" ` + -Force + } +} +``` + +--- + +## Azure Resource Graph Queries + +| Purpose | Query | +|---------|-------| +| All subscriptions | `ResourceContainers \| where type =~ 'microsoft.resources/subscriptions' \| project subscriptionId, name` | +| Enabled only | `ResourceContainers \| where type =~ 'microsoft.resources/subscriptions' \| where properties.state == 'Enabled' \| project subscriptionId, name` | +| Name filter | `ResourceContainers \| where type =~ 'microsoft.resources/subscriptions' \| where name contains 'keyword' \| project subscriptionId, name` | + +--- + +## Troubleshooting + +| Issue | Cause | Solution | +|-------|-------|----------| +| Permission errors | Missing Contributor/Owner role | Verify role assignment on subscription | +| Authentication issues | Not signed in | Run `Connect-AzAccount` | +| Location conflicts | Existing alert in different region | Default West US usually works | +| Rate limiting | Too many concurrent requests | Add delays or reduce parallelism | +| Query timeout | Large management group | Pagination handles automatically | + +--- + +## References + +- [Cost anomaly alerts](https://learn.microsoft.com/azure/cost-management-billing/understand/analyze-unexpected-charges) +- [Scheduled actions API](https://learn.microsoft.com/rest/api/cost-management/scheduled-actions) + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-budgets.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-budgets.md new file mode 100644 index 000000000..2e4ae85ed --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-budgets.md @@ -0,0 +1,188 @@ +--- +name: Azure Budgets +description: Cost budgets track spending against a threshold and send notifications when exceeded. Supports email, role-based, and Action Group notifications for automation. +--- + +**Key Facts:** +- Up to 5 notifications per budget +- Action Groups only at Subscription/Resource Group scope +- Start date must be 1st of month, on or after June 1, 2017 +- BillingMonth/Quarter/Annual time grains for EA/MCA billing scopes + +## Supported Scopes + +| Scope | Format | Action Groups | +|-------|--------|---------------| +| Subscription | `/subscriptions/{subscriptionId}` | Yes | +| Resource Group | `/subscriptions/{subId}/resourceGroups/{rg}` | Yes | +| Billing Account (EA) | `/providers/Microsoft.Billing/billingAccounts/{enrollmentId}` | No | +| Billing Profile (MCA) | `/providers/Microsoft.Billing/billingAccounts/{accountId}/billingProfiles/{profileId}` | No | +| Invoice Section (MCA) | `...billingProfiles/{profileId}/invoiceSections/{sectionId}` | No | + +## Workflow: Create Budget with Notifications + +### Step 1: List Existing Budgets + +```bash +# List budgets at subscription scope +az consumption budget list \ + --query "[].{Name:name, Amount:amount, Spent:currentSpend.amount, TimeGrain:timeGrain}" \ + -o table +``` + +### Step 2: Create Budget via REST API + +The CLI `az consumption budget create` doesn't support notifications. Use REST API: + +```bash +# Create budget with email notifications +SUBSCRIPTION_ID=$(az account show --query id -o tsv) + +az rest --method PUT \ + --url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/providers/Microsoft.Consumption/budgets/MonthlyBudget?api-version=2024-08-01" \ + --body '{ + "properties": { + "category": "Cost", + "amount": 1000, + "timeGrain": "Monthly", + "timePeriod": { + "startDate": "2026-02-01", + "endDate": "2027-01-31" + }, + "notifications": { + "Actual_GreaterThan_80_Percent": { + "enabled": true, + "operator": "GreaterThan", + "threshold": 80, + "thresholdType": "Actual", + "contactEmails": ["finops@company.com"], + "contactRoles": ["Owner", "Contributor"] + }, + "Forecasted_GreaterThan_100_Percent": { + "enabled": true, + "operator": "GreaterThan", + "threshold": 100, + "thresholdType": "Forecasted", + "contactEmails": ["finops@company.com"] + } + } + } + }' +``` + +### Step 3: Verify Budget Created + +```bash +# Show budget details +az consumption budget show --budget-name "MonthlyBudget" -o table +``` + +## Workflow: Add Action Group for Automation + +Action Groups enable automated responses (Logic Apps, Azure Functions, webhooks) when budget thresholds are exceeded. + +### Step 1: Create or Identify Action Group + +```bash +# List existing action groups +az monitor action-group list \ + --query "[].{Name:name, ResourceGroup:resourceGroup}" \ + -o table + +# Create new action group (if needed) +az monitor action-group create \ + --name "BudgetAlerts" \ + --resource-group "monitoring-rg" \ + --short-name "BudgetAG" \ + --action email finops-team finops@company.com +``` + +### Step 2: Update Budget with Action Group + +```bash +SUBSCRIPTION_ID=$(az account show --query id -o tsv) +ACTION_GROUP_ID="/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/monitoring-rg/providers/microsoft.insights/actionGroups/BudgetAlerts" + +az rest --method PUT \ + --url "https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/providers/Microsoft.Consumption/budgets/MonthlyBudget?api-version=2024-08-01" \ + --body "{ + \"properties\": { + \"category\": \"Cost\", + \"amount\": 1000, + \"timeGrain\": \"Monthly\", + \"timePeriod\": { + \"startDate\": \"2026-02-01\", + \"endDate\": \"2027-01-31\" + }, + \"notifications\": { + \"Actual_GreaterThan_80_Percent\": { + \"enabled\": true, + \"operator\": \"GreaterThan\", + \"threshold\": 80, + \"thresholdType\": \"Actual\", + \"contactEmails\": [\"finops@company.com\"], + \"contactGroups\": [\"${ACTION_GROUP_ID}\"] + } + } + } + }" +``` + +## Notification Configuration + +| Field | Required | Description | +|-------|----------|-------------| +| `enabled` | Yes | Enable/disable this notification | +| `operator` | Yes | `GreaterThan`, `GreaterThanOrEqualTo` | +| `threshold` | Yes | Percentage (0-1000) | +| `thresholdType` | Yes | `Actual` or `Forecasted` | +| `contactEmails` | Conditional | Required if no contactGroups at sub/RG scope | +| `contactGroups` | No | Action Group resource IDs (sub/RG scope only) | +| `contactRoles` | No | Azure roles (Owner, Contributor, Reader) | +| `locale` | No | Notification language (en-us, ja-jp, etc.) | + +**Threshold types:** +- **Actual** - Triggers when accrued cost exceeds threshold +- **Forecasted** - Triggers when projected end-of-period cost exceeds threshold + +## Time Grain Options + +| Time Grain | Scope | Description | +|------------|-------|-------------| +| `Monthly` | All | Resets monthly | +| `Quarterly` | All | Resets quarterly | +| `Annually` | All | Resets annually | +| `BillingMonth` | EA/MCA billing | Aligns to billing period | +| `BillingQuarter` | EA/MCA billing | Aligns to billing period | +| `BillingAnnual` | EA/MCA billing | Aligns to billing period | + +## Common Operations + +### Delete Budget + +```bash +az consumption budget delete --budget-name "MonthlyBudget" +``` + +### List Budgets via REST (Any Scope) + +```bash +# EA Billing Account scope +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{enrollmentId}/providers/Microsoft.Consumption/budgets?api-version=2024-08-01" +``` + +## Best Practices + +1. **Use Forecasted alerts** at 100% to get early warning before overspend +2. **Combine with Action Groups** to trigger automation (scale down, notify Slack, create tickets) +3. **Set multiple thresholds** (50%, 80%, 100%) for progressive visibility +4. **Use filters** to create budgets for specific resource groups, tags, or resources +5. **For enterprise**, deploy budgets at billing scope with BillingMonth grain + +## References + +- [Tutorial: Create and manage budgets](https://learn.microsoft.com/azure/cost-management-billing/costs/tutorial-acm-create-budgets) +- [Budgets REST API](https://learn.microsoft.com/rest/api/consumption/budgets) +- [Action Groups](https://learn.microsoft.com/azure/azure-monitor/alerts/action-groups) +- [Manage costs with budgets](https://learn.microsoft.com/azure/cost-management-billing/manage/cost-management-budget-scenario) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-commitment-discount-decision.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-commitment-discount-decision.md new file mode 100644 index 000000000..6f7204182 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-commitment-discount-decision.md @@ -0,0 +1,218 @@ +--- +name: Commitment discount decision framework +description: Decision framework for choosing between Azure Reservations, Savings Plans, or pay-as-you-go based on workload characteristics, risk tolerance, and organizational maturity. Includes comparison criteria, hybrid strategies, and key performance indicators. +--- + +**Key Features:** +- Side-by-side comparison of reservations vs savings plans +- Decision criteria based on workload stability and flexibility needs +- Hybrid commitment strategy guidance +- Key performance indicators for commitment discount health +- FinOps Framework alignment with rate optimization capability + +--- + +## Decision flow + +Use this text-based decision flow to determine the right commitment type: + +1. **Do you have consistent compute usage for 30+ days?** + - No: Stay on pay-as-you-go, revisit in 30 days + - Yes: Continue to step 2 +2. **Is usage concentrated on specific VM SKUs in specific regions?** + - Yes: Start with reservations (up to 72% savings) + - No: Continue to step 3 +3. **Is usage spread across multiple VM types, regions, or services?** + - Yes: Start with savings plans (up to 65% savings) + - No: Continue to step 4 +4. **Do you need cancellation flexibility?** + - Yes: Reservations only (savings plans cannot be canceled) + - No: Continue to step 5 +5. **Do you have both stable and variable compute?** + - Yes: Use hybrid strategy (see below) + - No: Default to savings plans for simplicity + +--- + +## Comparison table + +| Factor | Reservations | Savings plans | Pay-as-you-go | +|--------|-------------|---------------|---------------| +| Maximum savings | Up to 72% | Up to 65% | 0% (baseline) | +| Flexibility | Low (specific SKU, region) | High (any eligible compute) | Maximum | +| Cancellation | Returns up to $50K/year | No cancellation or refund | N/A | +| Exchange | Yes, within same product family (prorated) | No (but can trade in reservations for savings plans) | N/A | +| Applies to | Specific resource type and region | All eligible compute services | All services | +| Benefit application order | First (highest priority) | Second (after reservations) | N/A | +| Scope options | Shared, management group, subscription, RG | Shared, management group, subscription, RG | N/A | +| Agreement types | EA, MCA, MPA, CSP, PAYG, Sponsorship | EA, MCA, MPA | All | +| Term options | 1 year, 3 years | 1 year, 3 years | None | +| Payment options | All upfront, monthly | All upfront, monthly | Usage-based | +| Instance size flexibility | Yes (within VM series) | N/A (applies to all compute) | N/A | + +--- + +## Hybrid commitment strategy + +The optimal approach for most organizations: + +1. **Buy reservations first** for stable, predictable workloads (baseline) +2. **Buy savings plans second** for variable or growing compute (covers the rest) +3. **Pay-as-you-go** for truly unpredictable or temporary workloads + +Key principle: Reservations are applied first in the benefit stack, so they always "win" for matching workloads. Savings plans catch remaining eligible charges that reservations don't cover. + +**Migration path:** If existing reservations no longer fit your workloads, you can trade them in for savings plans via self-service (no time limit). This is a one-way conversion — savings plans cannot be traded back to reservations. + +--- + +## Scope selection guidance + +| Scenario | Recommended scope | Rationale | +|----------|-------------------|-----------| +| Single team, dedicated workloads | Resource group | Maximum control, clear cost attribution | +| Shared infrastructure, multiple teams | Subscription | Balance of savings and governance | +| Enterprise-wide optimization | Shared or management group | Maximum savings, automatic benefit distribution | +| New to commitments | Shared | Safest starting point -- benefits auto-distribute | + +--- + +## Data requirements before committing + +- Minimum 30 days of consistent usage data (60 days preferred) +- Use the Benefit Recommendations API with `Last30Days` or `Last60Days` lookback +- Coefficient of variation (CV) in hourly usage: + - **< 0.3** = stable (reservation candidate) + - **0.3 - 0.6** = variable (savings plan candidate) + - **> 0.6** = volatile (stay on pay-as-you-go) +- Check for planned migrations, decommissions, or workload changes that would invalidate historical patterns + +### Evaluate usage stability + +```powershell +# Calculate coefficient of variation from hourly usage data +$hourlyUsage = @(10.2, 10.5, 10.1, 10.8, 10.3) # Replace with actual hourly data +$mean = ($hourlyUsage | Measure-Object -Average).Average +$stdDev = [Math]::Sqrt(($hourlyUsage | ForEach-Object { [Math]::Pow($_ - $mean, 2) } | Measure-Object -Sum).Sum / $hourlyUsage.Count) +$cv = $stdDev / $mean + +switch ($cv) { + { $_ -lt 0.3 } { Write-Host "CV: $([Math]::Round($cv, 3)) - Stable: reservation candidate"; break } + { $_ -lt 0.6 } { Write-Host "CV: $([Math]::Round($cv, 3)) - Variable: savings plan candidate"; break } + default { Write-Host "CV: $([Math]::Round($cv, 3)) - Volatile: stay on pay-as-you-go" } +} +``` + +--- + +## The 70% rule for management group scope + +The Benefit Recommendations API does not support management group scope. Microsoft's documented workaround: + +1. Get recommendations for each subscription individually +2. Sum the recommended commitment amounts +3. Purchase approximately 70% of the total (conservative start) +4. Wait 3 days for the recommendation engine to recalculate +5. Iterate -- get new recommendations that account for existing commitments +6. Repeat until incremental savings are negligible + +```powershell +# Aggregate recommendations across subscriptions by calling the API directly +$subscriptions = Get-AzSubscription +$totalRecommended = 0 + +foreach ($sub in $subscriptions) { + Set-AzContext -Subscription $sub.Id + $scope = "subscriptions/$($sub.Id)" + $url = "https://management.azure.com/$scope/providers/Microsoft.CostManagement/benefitRecommendations?`$filter=properties/lookBackPeriod eq 'Last30Days' AND properties/term eq 'P3Y'&`$expand=properties/allRecommendationDetails&api-version=2024-08-01" + $uri = [uri]::new($url) + $result = Invoke-AzRestMethod -Uri $uri.AbsoluteUri -Method GET + $recs = ($result.Content | ConvertFrom-Json).value + + foreach ($rec in $recs) { + $details = $rec.properties.recommendationDetails + if ($details -and $details.averageUtilizationPercentage -ge 90) { + $totalRecommended += $details.commitmentAmount + } + } +} + +$mgScopeCommitment = $totalRecommended * 0.7 +Write-Host "Total recommended: `$$totalRecommended/hr" +Write-Host "Management group purchase (70%): `$$mgScopeCommitment/hr" +``` + +--- + +## Waiting periods + +| Event | Wait period | Reason | +|-------|-------------|--------| +| After purchasing, before evaluating other commitment types | 7 days | Allows recommendation engine to recalculate across both reservation and savings plan models | +| Iterative same-type purchasing (management group workaround) | 3 days | Allows new commitment to affect subscription-level recommendations before next iteration | + +The recommendation engine uses recent utilization data. New commitments change the usage pattern, so recommendations generated before the engine recalculates may be inaccurate. + +--- + +## Key performance indicators + +| KPI | Formula | Target | Description | +|-----|---------|--------|-------------| +| Effective savings rate (ESR) | (List cost - effective cost) / list cost | >20% | Percentage savings vs on-demand pricing | +| Utilization rate | Used hours / committed hours | >90% | How much of the commitment is actually used | +| Coverage percentage | Covered cost / total eligible cost | 60-80% | What portion of eligible spend is under commitment | +| Wastage rate | Wasted cost / commitment cost | <10% | Unused commitment (use-it-or-lose-it per hour) | + +**Interpretation guidelines:** +- ESR below 10% indicates no commitment discounts in place -- opportunity for savings +- Utilization below 80% indicates overcommitment -- consider exchanging or not renewing +- Coverage above 80% may indicate overcommitment risk -- leave room for usage variability +- Target ESR varies by organization and industry -- track trend over time rather than targeting a specific number + +--- + +## FinOps Framework alignment + +This decision framework maps to the FinOps Framework's rate optimization capability: + +- **Inform**: Analyze current spend, identify commitment-eligible workloads, assess usage stability, track ESR/utilization/wastage +- **Optimize**: Purchase commitments based on this decision framework, exchange underutilized reservations, adjust commitment levels +- **Operate**: Establish governance processes for commitment purchases, renewals, and exchanges; monitor utilization weekly; report savings to stakeholders + +Link: [Rate Optimization (FinOps Framework)](https://www.finops.org/framework/capabilities/rate-optimization/) + +--- + +## Common mistakes + +| Mistake | Impact | Prevention | +|---------|--------|------------| +| Buying savings plans before reservations | Lower savings (reservations offer up to 72% vs 65%) | Always buy reservations first for stable workloads | +| Purchasing 100% coverage | High wastage risk | Target 60-80% coverage, leave buffer for variability | +| Using 7-day lookback for large purchases | Overcommitment risk | Use 30 or 60-day lookback for commitments over $1K/month | +| Ignoring pending migrations | Stranded commitments | Check with infrastructure teams before purchasing | +| No renewal governance | Expired commitments, lost savings | Set calendar reminders 30 days before expiry | +| Purchasing without checking existing commitments | Double coverage, wastage | Always check current utilization before new purchases | + +--- + +## Prerequisites + +- Understanding of current Azure spend patterns (30+ days of data) +- Access to Benefit Recommendations API (Cost Management Reader role) +- Knowledge of planned workload changes +- Stakeholder alignment on commitment term and risk tolerance + +--- + +## References + +- [Azure savings plan overview](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/savings-plan-compute-overview) +- [Azure Reservations overview](https://learn.microsoft.com/azure/cost-management-billing/reservations/save-compute-costs-reservations) +- [Decide between a savings plan and a reservation](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/decide-between-savings-plan-reservation) +- [Rate Optimization (FinOps Framework)](https://www.finops.org/framework/capabilities/rate-optimization/) +- [Choose commitment amount](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/choose-commitment-amount) +- [Benefit Recommendations API](https://learn.microsoft.com/rest/api/cost-management/benefit-recommendations) +- [Reservation trade-in to savings plans](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/reservation-trade-in) +- [Exchange and refund policies](https://learn.microsoft.com/azure/cost-management-billing/reservations/exchange-and-refund-azure-reservations) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-cost-exports.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-cost-exports.md new file mode 100644 index 000000000..005bef6ef --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-cost-exports.md @@ -0,0 +1,178 @@ +--- +name: Azure Cost Management Exports +description: Cost Management exports automatically export cost and usage data to Azure Storage on a recurring schedule. Exports are the foundation for FinOps data pipelines and are required for FinOps Hubs. +--- + +## Supported Scopes + +| Agreement | Scope | Format | Recommended | +|-----------|-------|--------|-------------| +| **EA** | Billing Account | `/providers/Microsoft.Billing/billingAccounts/{enrollmentId}` | ✅ | +| **EA** | Department | `/providers/Microsoft.Billing/billingAccounts/{enrollmentId}/departments/{deptId}` | | +| **EA** | Enrollment Account | `/providers/Microsoft.Billing/billingAccounts/{enrollmentId}/enrollmentAccounts/{accountId}` | | +| **MCA** | Billing Profile | `/providers/Microsoft.Billing/billingAccounts/{accountId}/billingProfiles/{profileId}` | ✅ | +| **MCA** | Invoice Section | `...billingProfiles/{profileId}/invoiceSections/{sectionId}` | | +| **MPA** | Customer | `/providers/Microsoft.Billing/billingAccounts/{accountId}/customers/{customerId}` | | +| All | Subscription | `/subscriptions/{subscriptionId}` | | +| All | Resource Group | `/subscriptions/{subId}/resourceGroups/{rgName}` | | + +**Why billing scope?** Billing account (EA) and billing profile (MCA) include price sheets, reservation recommendations, and complete cost visibility across all subscriptions. + +## Workflow: Create Export at Billing Scope + +### Step 1: List Existing Exports + +```bash +# EA Billing Account scope +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{enrollmentId}/providers/Microsoft.CostManagement/exports?api-version=2023-08-01" \ + --query "value[].{Name:name, Type:properties.definition.type, Status:properties.schedule.status}" \ + -o table + +# MCA Billing Profile scope +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{accountId}/billingProfiles/{profileId}/providers/Microsoft.CostManagement/exports?api-version=2023-08-01" \ + --query "value[].{Name:name, Type:properties.definition.type, Status:properties.schedule.status}" \ + -o table +``` + +### Step 2: Create Export via REST API + +```bash +# EA Billing Account - FOCUS cost export +SCOPE="/providers/Microsoft.Billing/billingAccounts/{enrollmentId}" + +az rest --method PUT \ + --url "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/exports/ftk-costs-daily?api-version=2023-08-01" \ + --body '{ + "properties": { + "format": "Parquet", + "deliveryInfo": { + "destination": { + "resourceId": "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Storage/storageAccounts/{account}", + "container": "msexports", + "rootFolderPath": "billingAccounts/{enrollmentId}" + } + }, + "definition": { + "type": "FocusCost", + "timeframe": "MonthToDate", + "dataSet": { + "granularity": "Daily" + } + }, + "schedule": { + "status": "Active", + "recurrence": "Daily", + "recurrencePeriod": { + "from": "2026-01-01T00:00:00Z", + "to": "2027-12-31T00:00:00Z" + } + } + } + }' +``` + +### Step 3: Run Export Immediately + +```bash +# Trigger export run +az rest --method POST \ + --url "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/exports/ftk-costs-daily/run?api-version=2023-08-01" +``` + +### Step 4: Verify Data Landed + +```bash +# List blobs in export container +az storage blob list \ + --account-name {storageAccount} \ + --container-name msexports \ + --prefix "billingAccounts/{enrollmentId}" \ + --auth-mode login \ + --query "[].{Name:name, Size:properties.contentLength}" \ + -o table +``` + +## Workflow: Historical Backfill + +### FinOps Toolkit PowerShell (Recommended) + +```powershell +# Backfill 12 months at billing scope +New-FinOpsCostExport -Name "ftk-costs" ` + -Scope "/providers/Microsoft.Billing/billingAccounts/{enrollmentId}" ` + -StorageAccountId "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Storage/storageAccounts/{account}" ` + -Backfill 12 ` + -Execute +``` + +### REST API (One Month at a Time) + +```bash +SCOPE="/providers/Microsoft.Billing/billingAccounts/{enrollmentId}" + +az rest --method PUT \ + --url "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/exports/backfill-jan2025?api-version=2023-08-01" \ + --body '{ + "properties": { + "format": "Parquet", + "deliveryInfo": { + "destination": { + "resourceId": "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Storage/storageAccounts/{account}", + "container": "msexports", + "rootFolderPath": "backfill" + } + }, + "definition": { + "type": "FocusCost", + "timeframe": "Custom", + "timePeriod": { + "from": "2025-01-01T00:00:00Z", + "to": "2025-01-31T23:59:59Z" + } + } + } + }' + +# Run the backfill +az rest --method POST \ + --url "https://management.azure.com${SCOPE}/providers/Microsoft.CostManagement/exports/backfill-jan2025/run?api-version=2023-08-01" +``` + +## Dataset Types by Scope + +| Dataset | EA Billing | MCA Profile | Subscription | +|---------|------------|-------------|--------------| +| **FocusCost** | ✅ | ✅ | ✅ | +| **ActualCost** | ✅ | ✅ | ✅ | +| **AmortizedCost** | ✅ | ✅ | ✅ | +| **PriceSheet** | ✅ | ✅ | ❌ | +| **ReservationRecommendations** | ✅ | ✅ | ❌ | +| **ReservationDetails** | ✅ | ✅ | ❌ | +| **ReservationTransactions** | ✅ | ✅ | ❌ | + +## Common Issues + +### "Unauthorized" Error +**Fix:** Assign Cost Management Contributor or Owner role at the billing scope + +### Export Created But No Data +**Fix:** Trigger immediate run: +```bash +az rest --method POST \ + --url "https://management.azure.com/{scope}/providers/Microsoft.CostManagement/exports/{exportName}/run?api-version=2023-08-01" +``` + +## Best Practices + +1. **Use billing scope** (EA enrollment / MCA profile) for complete data including price sheets +2. **Use FOCUS format** - combines actual/amortized, reduces storage +3. **Use Parquet with Snappy** compression for best performance +4. **Create backfill in one-month chunks** to avoid timeouts + +## References + +- [Tutorial: Create and manage exports](https://learn.microsoft.com/azure/cost-management-billing/costs/tutorial-improved-exports) +- [Exports REST API](https://learn.microsoft.com/rest/api/cost-management/exports) +- [Understand and work with scopes](https://learn.microsoft.com/azure/cost-management-billing/costs/understand-work-scopes) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-credits.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-credits.md new file mode 100644 index 000000000..618068df4 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-credits.md @@ -0,0 +1,163 @@ +--- +name: Azure Credits (Prepayment) +description: Azure Prepayment (formerly Monetary Commitment) provides prepaid funds that cover eligible Azure services. Credits have **expiration dates** - unused credits are lost. Credits may also be granted via promotions or strategic investments. +--- + +**Key distinction from MACC:** +- **Azure Prepayment**: Prepaid credits covering eligible services - consumption covered by prepayment does NOT count toward MACC +- **MACC**: Contractual commitment tracking total consumption + +## How Credits Are Applied + +Credits are automatically applied to eligible charges when an invoice is generated. The remaining balance after credits is paid via other payment methods. + +**Products NOT covered by credits:** +- Azure Marketplace products +- Azure support plans +- Canonical products (Ubuntu Pro) +- Citrix Virtual Apps and Desktops +- Visual Studio subscriptions (Monthly/Annual) + +## Workflow: Assess Credit Health + +### Step 1: Identify Agreement Type + +EA and MCA use different APIs. Check agreement type first: + +```bash +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2020-05-01" \ + --query "value[].{Name:name, Type:properties.agreementType}" +``` + +### Step 2: Get Current Balance + +**For EA:** +```bash +CURRENT_PERIOD=$(date +%Y%m) +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//billingPeriods/${CURRENT_PERIOD}/providers/Microsoft.Consumption/balances?api-version=2024-08-01" \ + --query "{Beginning:properties.beginningBalance, Ending:properties.endingBalance, Utilized:properties.utilized, Overage:properties.serviceOverage}" +``` + +**For MCA:** +```bash +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//billingProfiles//providers/Microsoft.Consumption/lots?api-version=2023-03-01" \ + --query "value[?properties.status=='Active'].{Source:properties.source, Original:properties.originalAmount.value, Remaining:properties.closedBalance.value, Expires:properties.expirationDate}" +``` + +### Step 3: Check Expiration Risk + +Query credits expiring in next 90 days: + +```bash +# MCA - find expiring credits +NINETY_DAYS=$(date -v+90d +%Y-%m-%d) # macOS +# NINETY_DAYS=$(date -d "+90 days" +%Y-%m-%d) # Linux + +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//billingProfiles//providers/Microsoft.Consumption/lots?api-version=2023-03-01" \ + --query "value[?properties.status=='Active'].{Source:properties.source, Balance:properties.closedBalance.value, Expires:properties.expirationDate}" | \ + jq --arg date "$NINETY_DAYS" '[.[] | select(.Expires <= $date)]' +``` + +### Step 4: Assess Risk Level + +| Situation | Risk | Action | +|-----------|------|--------| +| No credits expiring in 90 days | Low | Monitor quarterly | +| Credits expiring, balance < monthly consumption | Low | Will be consumed naturally | +| Credits expiring, balance > monthly consumption | High | Accelerate consumption or lose credits | +| Credits already expired | Loss | Review for future prevention | + +## EA Balance API + +Query balance for a specific billing period (YYYYMM format): + +```bash +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//billingPeriods//providers/Microsoft.Consumption/balances?api-version=2024-08-01" +``` + +**Response fields:** + +| Field | Description | +|-------|-------------| +| `beginningBalance` | Starting Azure Prepayment balance for the month | +| `endingBalance` | Remaining balance (updated daily for open periods) | +| `newPurchases` | New Azure Prepayment purchases during month | +| `adjustments` | Total adjustment amount | +| `adjustmentDetails[]` | Array of credit types and amounts | +| `utilized` | Amount of Azure Prepayment consumed | +| `serviceOverage` | Overage for Azure services | +| `chargesBilledSeparately` | Charges billed separately from Prepayment | +| `azureMarketplaceServiceCharges` | Total Marketplace charges | +| `currency` | ISO currency code (e.g., USD) | + +**Credit types in adjustmentDetails:** + +| Credit Type | Description | +|-------------|-------------| +| `Promo Credit` | Promotional credits | +| `Strategic Investment Credit` | Microsoft investment credits | +| `Billing Correction Credit` | Billing adjustments | +| `Reservations - Exchange Credit` | RI exchange credits | + +## MCA Credit Lots API + +Query credit lots for a billing profile: + +```bash +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//billingProfiles//providers/Microsoft.Consumption/lots?api-version=2023-03-01" +``` + +**Response fields:** + +| Field | Description | +|-------|-------------| +| `originalAmount` | Original credit amount | +| `closedBalance` | Remaining credit balance (as of last invoice) | +| `source` | Credit source (e.g., "Azure Promotional Credit") | +| `startDate` | When credit became active | +| `expirationDate` | When credit expires | +| `poNumber` | PO number of invoice where credit was billed | + +## MCA Credit Events API + +Query credit transactions over time: + +```bash +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//billingProfiles//providers/Microsoft.Consumption/events?api-version=2023-03-01&startDate=YYYY-MM-DD&endDate=YYYY-MM-DD" +``` + +**Response fields:** + +| Field | Description | +|-------|-------------| +| `transactionDate` | When transaction occurred | +| `description` | Description of the transaction | +| `newCredit` | New credits added | +| `adjustments` | Credit adjustments | +| `creditExpired` | Credits that expired | +| `charges` | Charges applied against credits | +| `closedBalance` | Balance after transaction | +| `eventType` | PendingCharges, SettledCharges, PendingNewCredit, etc. | +| `invoiceNumber` | Invoice number (empty for pending) | + +## Important Notes + +1. **EA vs MCA**: Query patterns differ significantly - verify agreement type first +2. **Billing period format**: EA uses YYYYMM (e.g., 202207 for July 2022) +3. **Credit expiration**: Unused credits expire and cannot be recovered +4. **Overage**: When credits exhausted, charges appear as `serviceOverage` (EA) or standard invoiced charges (MCA) +5. **Permissions**: Requires billing account reader or billing profile reader role + +## References + +- [View Azure credits balance (EA)](https://learn.microsoft.com/azure/cost-management-billing/manage/ea-portal-enrollment-invoices#view-enrollment-credit-balance) +- [Track Azure credit balance (MCA)](https://learn.microsoft.com/azure/cost-management-billing/manage/mca-check-azure-credits-balance) +- [Consumption Balances API](https://learn.microsoft.com/rest/api/consumption/balances) +- [Consumption Lots API](https://learn.microsoft.com/rest/api/consumption/lots) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-macc.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-macc.md new file mode 100644 index 000000000..9030a0017 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-macc.md @@ -0,0 +1,122 @@ +--- +name: Azure MACC (Microsoft Azure Consumption Commitment) +description: MACC is a contractual commitment to spend a specific amount on Azure over a defined period (typically 3-5 years). Missing the commitment results in a **shortfall charge** - an invoice for the remaining balance converted to Azure Prepayment credit. +--- + +## Eligibility Rules + +Understanding what counts toward MACC is critical to avoid surprises. + +**Counts toward MACC:** +- Direct Azure consumption billed to your account +- Azure Prepayment purchases (the purchase itself, not consumption from it) +- Azure Marketplace offers with "Azure benefit eligible" badge (100% of pretax amount) + +**Does NOT count toward MACC:** +- Consumption covered by Azure Prepayment credits +- Consumption covered by shortfall credits (the trap!) +- Marketplace offers without the eligible badge +- Purchases not linked to your billing account +- Hybrid/on-premises license usage + +**The shortfall trap:** If MACC is missed, the shortfall becomes Prepayment credit. Consumption against that credit does NOT count toward any future MACC commitment. + +## Workflow: Assess MACC Status + +### Step 1: Get Current Position + +Query the Lots API for active commitments: + +```bash +# List billing accounts first +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2020-05-01" \ + --query "value[].{Name:name, DisplayName:properties.displayName}" + +# Get MACC commitments (replace ) +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//providers/Microsoft.Consumption/lots?api-version=2021-05-01&\$filter=source%20eq%20%27ConsumptionCommitment%27" \ + --query "value[?properties.status=='Active'].{Original:properties.originalAmount.value, Remaining:properties.closedBalance.value, StartDate:properties.startDate, EndDate:properties.expirationDate}" +``` + +**Key fields:** +- `originalAmount` - Total commitment amount +- `closedBalance` - Remaining balance as of last invoice +- `purchasedDate` - When MACC was purchased +- `startDate` - When MACC became active +- `expirationDate` - Deadline +- `status` - Active, Completed, Expired, or Canceled + +### Step 2: Calculate Burn Rate + +Query recent decrement events: + +```bash +# Get decrements for last 6 months (adjust dates) +az rest --method GET \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts//providers/Microsoft.Consumption/events?api-version=2021-05-01&startDate=2024-07-01&endDate=2025-01-01&\$filter=lotsource%20eq%20%27ConsumptionCommitment%27" \ + --query "value[].{Date:properties.transactionDate, Decrement:properties.charges.value, Remaining:properties.closedBalance.value, Invoice:properties.invoiceNumber}" +``` + +**Event fields:** +- `transactionDate` - When event occurred +- `description` - Description of the event +- `charges` - MACC decrement amount +- `closedBalance` - Remaining balance after event +- `invoiceNumber` - Invoice that triggered the decrement +- `eventType` - SettledCharges (only type for MACC) +- `billingProfileDisplayName` - Billing profile name (MCA only) + +Calculate average monthly decrement from results. + +### Step 3: Assess Risk + +``` +Required Monthly Rate = closedBalance ÷ Months Until Expiration +Actual Monthly Rate = Sum of decrements ÷ Number of months +``` + +| Situation | Risk Level | Action | +|-----------|------------|--------| +| Actual > Required × 1.1 | Low | Monitor quarterly | +| Actual within ±10% of Required | Medium | Monitor monthly | +| Actual < Required × 0.9 | High | Acceleration needed | + +### Step 4: Check for Milestones + +Some MACCs have interim milestones with their own deadlines and shortfall penalties. Check the Azure portal: **Cost Management + Billing → Credits + Commitments → MACC → Milestones tab**. + +Milestones are not exposed via API - use portal to verify. + +## Accelerating MACC Burn + +When behind on commitment: + +1. **Accelerate planned projects** - Move deployments forward +2. **Purchase Reservations/Savings Plans** - Purchases count toward MACC +3. **Azure Marketplace** - Find "Azure benefit eligible" solutions +4. **Contact Microsoft** - Discuss commitment amendments + +## Alerts + +Microsoft automatically emails Billing Account Admins: +- 90 days before MACC expiration +- 60 days before MACC expiration +- 30 days before MACC expiration +- Same intervals for milestone deadlines + +No configuration needed - alerts are automatic for accounts not on track. + +## Prerequisites + +- **EA:** Enterprise Administrator role required +- **MCA:** Owner, Contributor, or Reader on billing account +- **Direct agreements only** - Indirect (partner) agreements cannot use portal/API + +## References + +- [Track your MACC](https://learn.microsoft.com/azure/cost-management-billing/manage/track-consumption-commitment) - Portal and API guidance +- [MACC FAQ](https://learn.microsoft.com/marketplace/macc-frequently-asked-questions) - Marketplace eligibility details +- [Azure benefit eligible offers](https://learn.microsoft.com/marketplace/azure-consumption-commitment-benefit) - Finding eligible Marketplace solutions +- [Consumption Lots API](https://learn.microsoft.com/rest/api/consumption/lots) - API reference +- [Consumption Events API](https://learn.microsoft.com/rest/api/consumption/events) - API reference diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-orphaned-resources.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-orphaned-resources.md new file mode 100644 index 000000000..062caabd8 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-orphaned-resources.md @@ -0,0 +1,329 @@ +--- +name: Azure Orphaned Resources +description: Azure Resource Graph queries to detect unused and orphaned resources generating waste with zero workload value. Covers unattached disks, unused NICs, orphaned public IPs, idle load balancers, empty availability sets, orphaned NSGs, idle NAT gateways, and stale snapshots with safe cleanup patterns. +--- + +**Key Features:** +- Resource Graph queries for 8 orphaned resource types +- Immediate savings with zero performance risk +- Safe cleanup patterns with `-WhatIf` / `--dry-run` +- Cost estimation guidance per resource type +- Automation via Azure Policy and scheduled queries + +--- + +## Why orphaned resources matter + +Orphaned resources are Azure resources that remain provisioned after the workloads they supported are deleted, scaled down, or reconfigured. They generate charges with zero workload value — pure waste. Common causes: VM deletions that leave disks and NICs behind, IP address releases that don't clean up the public IP, and load balancers left after AKS cluster teardown. + +These are the lowest-risk cost optimization opportunities because removing them has no impact on running workloads. + +--- + +## Prerequisites + +- Azure CLI (`az login`) or Azure PowerShell (`Connect-AzAccount`) +- **Reader** role on target subscriptions +- Azure Resource Graph access (enabled by default for all Microsoft Entra ID users) + +--- + +## Detection queries + +### Unattached managed disks + +Disks in `Unattached` state are not connected to any VM. Typical monthly cost: $1.54–$122.88/disk depending on tier and size. + +```bash +az graph query -q " +resources +| where type == 'microsoft.compute/disks' +| where properties.diskState == 'Unattached' +| project name, resourceGroup, subscriptionId, + sku = properties.sku.name, + sizeGb = properties.diskSizeGB, + location, + timeCreated = properties.timeCreated +| order by sizeGb desc +" --first 1000 +``` + +### Unused network interfaces + +NICs not attached to any VM. Created during VM provisioning and left behind on deletion. + +```bash +az graph query -q " +resources +| where type == 'microsoft.network/networkinterfaces' +| where isnull(properties.virtualMachine) +| where isnull(properties.virtualMachineScaleSet) +| where isnull(properties.privateEndpoint) +| project name, resourceGroup, subscriptionId, location, + privateIp = properties.ipConfigurations[0].properties.privateIPAddress +" --first 1000 +``` + +**Note:** NICs attached to private endpoints (`properties.privateEndpoint != null`) or VMSS instances (`properties.virtualMachineScaleSet != null`) are not orphaned — both are excluded. + +### Orphaned public IP addresses + +Public IPs not associated with any resource. Standard SKU public IPs cost ~$3.65/month even when idle. + +```bash +az graph query -q " +resources +| where type == 'microsoft.network/publicipaddresses' +| where isnull(properties.ipConfiguration) +| where isnull(properties.natGateway) +| project name, resourceGroup, subscriptionId, location, + sku = sku.name, + ipAddress = properties.ipAddress, + allocationMethod = properties.publicIPAllocationMethod +" --first 1000 +``` + +### Idle NAT gateways + +NAT gateways with no associated subnets. Charged at ~$32.85/month plus data processing fees. + +```bash +az graph query -q " +resources +| where type == 'microsoft.network/natgateways' +| where isnull(properties.subnets) or array_length(properties.subnets) == 0 +| project name, resourceGroup, subscriptionId, location +" --first 1000 +``` + +### Orphaned snapshots + +Snapshots where the source disk no longer exists. Filter to snapshots older than 30 days to avoid catching in-progress operations. + +```bash +az graph query -q " +resources +| where type == 'microsoft.compute/snapshots' +| where todatetime(properties.timeCreated) < ago(30d) +| extend sourceDisk = tostring(properties.creationData.sourceResourceId) +| where not(sourceDisk has '/snapshots/') +| join kind=leftanti ( + resources + | where type == 'microsoft.compute/disks' + | project id +) on \$left.sourceDisk == \$right.id +| project name, resourceGroup, subscriptionId, location, + sizeGb = properties.diskSizeGB, + created = properties.timeCreated, + sourceDisk +| order by sizeGb desc +" --first 1000 +``` + +### Idle load balancers + +Load balancers with empty backend pools — no VMs or VMSSes behind them. + +```bash +az graph query -q " +resources +| where type == 'microsoft.network/loadbalancers' +| where isnull(properties.backendAddressPools) + or array_length(properties.backendAddressPools) == 0 +| project name, resourceGroup, subscriptionId, location, + sku = sku.name +" --first 1000 +``` + +**Note:** Standard SKU load balancers cost ~$18.25/month when idle. Basic SKU load balancers are free but should still be cleaned up. + +### Empty availability sets + +Availability sets with no VMs. No direct cost, but they clutter the environment and may prevent resource cleanup. + +```bash +az graph query -q " +resources +| where type == 'microsoft.compute/availabilitysets' +| where isnull(properties.virtualMachines) or array_length(properties.virtualMachines) == 0 +| project name, resourceGroup, subscriptionId, location +" --first 1000 +``` + +### Orphaned network security groups + +NSGs not attached to any NIC or subnet. No direct cost, but they add management overhead and security audit noise. + +```bash +az graph query -q " +resources +| where type == 'microsoft.network/networksecuritygroups' +| where isnull(properties.networkInterfaces) or array_length(properties.networkInterfaces) == 0 +| where isnull(properties.subnets) or array_length(properties.subnets) == 0 +| project name, resourceGroup, subscriptionId, location, + rulesCount = array_length(properties.securityRules) +" --first 1000 +``` + +--- + +## Cost estimation by resource type + +| Resource Type | Typical Monthly Cost | Detection Confidence | +|--------------|---------------------|---------------------| +| Managed disks (unattached) | $1.54–$122.88/disk (varies by SKU tier) | High — `Unattached` is definitive; `Reserved` state disks (temporarily held during VM provisioning) are excluded | +| Public IPs (Standard SKU) | ~$3.65/IP | High — no `ipConfiguration` is definitive | +| NAT gateways (idle) | ~$32.85 + data fees | High — no subnets is definitive | +| Load balancers (Standard, empty) | ~$18.25/LB | High — empty backend pools | +| Snapshots (orphaned) | $0.05/GB/month | Medium — source disk deleted but snapshot may be intentional backup; snapshot-to-snapshot chains are excluded | +| NICs (unused) | Free (but blocks cleanup) | Medium — check for pending VM deployments | +| Availability sets (empty) | Free (clutter) | High — no VMs attached | +| NSGs (orphaned) | Free (audit noise) | Medium — may be pre-provisioned for deployment templates | + +--- + +## Safe cleanup patterns + +### PowerShell with -WhatIf + +```powershell +# Preview disk cleanup (dry run) +$disks = Search-AzGraph -Query " +resources +| where type == 'microsoft.compute/disks' +| where properties.diskState == 'Unattached' +| project name, resourceGroup, subscriptionId +" + +foreach ($disk in $disks) { + Remove-AzDisk -ResourceGroupName $disk.resourceGroup ` + -DiskName $disk.name -WhatIf +} + +# Execute cleanup (remove -WhatIf) +foreach ($disk in $disks) { + Remove-AzDisk -ResourceGroupName $disk.resourceGroup ` + -DiskName $disk.name -Force +} +``` + +### Azure CLI with --dry-run + +Azure CLI `delete` commands do not have a `--dry-run` flag. Instead, list first and review before deleting: + +```bash +# List orphaned public IPs (review step) +az graph query -q " +resources +| where type == 'microsoft.network/publicipaddresses' +| where isnull(properties.ipConfiguration) +| where isnull(properties.natGateway) +| project name, resourceGroup, subscriptionId +" --first 1000 -o table + +# Delete after review (per resource) +az network public-ip delete --name --resource-group +``` + +### Bulk cleanup script + +> **Confirm before running.** Always show the list of resources to the user and get explicit approval before executing. + +```powershell +# Bulk delete unattached disks across subscriptions +$disks = Search-AzGraph -Query " +resources +| where type == 'microsoft.compute/disks' +| where properties.diskState == 'Unattached' +| project name, resourceGroup, subscriptionId +" -First 1000 + +# Show what will be deleted and confirm +Write-Host "Found $($disks.Count) unattached disk(s):" +$disks | Format-Table name, resourceGroup, subscriptionId -AutoSize + +$confirm = Read-Host "Delete all $($disks.Count) disk(s)? Type 'yes' to confirm" +if ($confirm -ne 'yes') { + Write-Host "Aborted." + return +} + +$totalRemoved = 0 +foreach ($disk in $disks) { + try { + Set-AzContext -Subscription $disk.subscriptionId -ErrorAction Stop | Out-Null + Remove-AzDisk -ResourceGroupName $disk.resourceGroup ` + -DiskName $disk.name -Force -ErrorAction Stop + $totalRemoved++ + } catch { + Write-Warning "Skipping $($disk.name) in $($disk.subscriptionId): $_" + } +} +Write-Host "Removed $totalRemoved of $($disks.Count) unattached disks" +``` + +--- + +## Automation + +### Azure Policy (audit mode) + +Use built-in Azure Policy definitions to audit orphaned resources: + +| Policy | Description | +|--------|-------------| +| `Audit unattached managed disks` | Flags disks with `diskState == Unattached` | +| `Audit unused public IP addresses` | Flags public IPs with no association | + +Deploy at management group scope for enterprise-wide coverage. + +### Scheduled Resource Graph queries + +Use Azure Automation or Logic Apps to run detection queries on a weekly schedule and send results via email or Teams webhook: + +```powershell +# Azure Automation runbook pattern +param ( + [Parameter(Mandatory = $true)] + [string]$TeamsWebhookUrl +) + +$orphanedDisks = Search-AzGraph -Query " +resources +| where type == 'microsoft.compute/disks' +| where properties.diskState == 'Unattached' +| summarize Count = count() +" + +if ($orphanedDisks.Count -gt 0) { + # NOTE: Actual cost depends on disk SKU tier (Standard HDD ~$0.045/GB, Premium SSD ~$0.17-$0.38/GB). + # Use references/azure-retail-prices.md for per-SKU pricing validation. + $body = @{ + title = "Orphaned Resource Alert" + text = "$($orphanedDisks.Count) unattached disks found. Review and clean up to reduce waste." + } | ConvertTo-Json + + Invoke-RestMethod -Uri $TeamsWebhookUrl -Method Post -Body $body -ContentType 'application/json' +} +``` + +--- + +## Permissions + +| Action | Required Role | +|--------|---------------| +| Run Resource Graph queries | Reader | +| Delete resources | Contributor on resource group | +| Deploy Azure Policy | Resource Policy Contributor | +| Azure Automation runbooks | Automation Contributor | + +--- + +## References + +- [Azure Resource Graph overview](https://learn.microsoft.com/azure/governance/resource-graph/overview) +- [Azure Resource Graph query samples](https://learn.microsoft.com/azure/governance/resource-graph/samples/starter) +- [Azure Policy built-in definitions](https://learn.microsoft.com/azure/governance/policy/samples/built-in-policies) +- [Manage unattached disks](https://learn.microsoft.com/azure/virtual-machines/windows/find-unattached-disks) +- [Usage Optimization (FinOps Framework)](https://www.finops.org/framework/capabilities/usage-optimization/) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-reservations.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-reservations.md new file mode 100644 index 000000000..90f35aff0 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-reservations.md @@ -0,0 +1,353 @@ +--- +name: Azure Reservations +description: Query the Azure Cost Management Benefit Recommendations API to retrieve reserved instance purchase recommendations. Analyze potential savings, utilization, coverage, and optimal commitment amounts for specific Azure resource types. +--- + +**Key Features:** +- Up to 72% savings vs pay-as-you-go pricing for stable workloads +- Resource-type specific (VMs, SQL DB, Cosmos DB, App Service, Synapse, Storage, etc.) +- Instance size flexibility within VM series +- Self-service returns (up to $50K/year at time of writing; see [current limits](https://learn.microsoft.com/azure/cost-management-billing/reservations/exchange-and-refund-azure-reservations)) and exchanges within product family +- 1-year and 3-year terms +- Applied before savings plans in the benefit stack + +--- + +## Benefit Recommendations API + +The same Benefit Recommendations API endpoint used for savings plans also returns reservation recommendations. The key difference is the `kind` filter parameter. + +> **Authentication note:** Use `az rest` in practice — it handles token acquisition automatically. The raw HTTP examples in this file are for documentation purposes only. + +### Request + +```http +GET https://management.azure.com/{billingScope}/providers/Microsoft.CostManagement/benefitRecommendations?$filter=properties/lookBackPeriod eq '{lookBackPeriod}' AND properties/term eq '{term}'&$expand=properties/usage,properties/allRecommendationDetails&api-version=2024-08-01 +Authorization: Bearer {token} +``` + +When no `kind` filter is specified, the API returns both savings plan and reservation recommendations. The `kind` property is at the top level of each result (not under `properties`), so filter client-side: + +```powershell +# Filter API results for reservations only +$reservations = $jsonResult.value | Where-Object { $_.kind -eq 'Reservation' } +``` + +**Note:** The documented `$filter` query parameters support `properties/lookBackPeriod`, `properties/term`, `properties/scope`, `properties/subscriptionId`, and `properties/resourceGroup`. Filtering by `kind` is not a documented server-side filter — do it client-side after retrieving results. + +### Parameters + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `billingScope` | Yes | - | Billing account, subscription, or resource group scope | +| `lookBackPeriod` | No | Last7Days | Analysis period: Last7Days, Last30Days, Last60Days | +| `term` | No | P3Y | Reservation term: P1Y (1-year) or P3Y (3-year) | +| `kind` | No | - | Top-level property on results: `Reservation` or `SavingsPlan`. Filter client-side (not a supported `$filter` param). | + +### Scope formats + +| Scope Type | Format | +|------------|--------| +| Billing Account | `providers/Microsoft.Billing/billingAccounts/{billingAccountId}` | +| Billing Profile | `providers/Microsoft.Billing/billingAccounts/{billingAccountId}/billingProfiles/{billingProfileId}` | +| Subscription | `subscriptions/{subscriptionId}` | +| Resource Group | `subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}` | + +--- + +## PowerShell examples + +The `Get-BenefitRecommendations.ps1` script (see `azure-savings-plans.md` for full source) works for both savings plans and reservations. Filter the results for reservation recommendations: + +### Get reservation recommendations only + +```powershell +# Get all benefit recommendations and parse JSON +$scope = "subscriptions/12345678-1234-1234-1234-123456789012" +$url = "https://management.azure.com/$scope/providers/Microsoft.CostManagement/benefitRecommendations?`$filter=properties/lookBackPeriod eq 'Last30Days' AND properties/term eq 'P3Y'&`$expand=properties/usage,properties/allRecommendationDetails&api-version=2024-08-01" +$uri = [uri]::new($url) +$result = Invoke-AzRestMethod -Uri $uri.AbsoluteUri -Method GET +$jsonResult = $result.Content | ConvertFrom-Json + +# Filter for reservation recommendations only (kind is top-level, not under properties) +$reservations = $jsonResult.value | Where-Object { $_.kind -eq 'Reservation' } + +# Display summary +$reservations | ForEach-Object { + $rec = $_.properties + Write-Host "ARM SKU: $($rec.armSkuName)" + Write-Host " Commitment: $($rec.recommendationDetails.commitmentAmount)/hr" + Write-Host " Savings: $($rec.recommendationDetails.savingsPercentage)%" + Write-Host " Term: $($rec.term)" + Write-Host "" +} +``` + +### Compare reservation vs savings plan recommendations + +```powershell +$scope = "subscriptions/$subscriptionId" +$url = "https://management.azure.com/$scope/providers/Microsoft.CostManagement/benefitRecommendations?`$filter=properties/lookBackPeriod eq 'Last30Days' AND properties/term eq 'P3Y'&`$expand=properties/allRecommendationDetails&api-version=2024-08-01" +$uri = [uri]::new($url) +$result = Invoke-AzRestMethod -Uri $uri.AbsoluteUri -Method GET +$all = ($result.Content | ConvertFrom-Json).value + +$reservationSavings = ($all | Where-Object { $_.kind -eq 'Reservation' } | + Measure-Object -Property { $_.properties.recommendationDetails.savingsAmount } -Sum).Sum + +$savingsPlanSavings = ($all | Where-Object { $_.kind -eq 'SavingsPlan' } | + Measure-Object -Property { $_.properties.recommendationDetails.savingsAmount } -Sum).Sum + +Write-Host "Total reservation savings: `$$reservationSavings" +Write-Host "Total savings plan savings: `$$savingsPlanSavings" +``` + +--- + +## Eligible resource types + +| Resource type | Flexibility | Notes | +|---------------|-------------|-------| +| Virtual machines | Instance size flexibility within series | Ratio-based application across sizes in the same series | +| Azure SQL Database | vCore-based | Applies to General Purpose and Business Critical tiers | +| Azure Cosmos DB | Throughput (RU/s) | Provisioned throughput reservations | +| App Service | Isolated v2 stamps | Isolated tier only | +| Azure Synapse Analytics | Data warehouse units | Compute reservations | +| Azure Managed Disks | Premium SSD capacity | Specific disk sizes | +| Azure Blob Storage | Reserved capacity | Hot, cool, and archive access tiers | +| Azure Files | Reserved capacity | Premium file shares | +| Azure Data Explorer | Markup units | Compute reservations | +| Azure VMware Solution | Node reservations | Host-level reservations | +| Red Hat plans | Software plans | RHEL VMs | +| SUSE plans | Software plans | SLES VMs | +| Azure Databricks | DBU commitments | Pre-purchase plans | + +--- + +## Scope and flexibility + +### Scope options + +| Scope | Description | +|-------|-------------| +| Shared | Applies across all subscriptions in the billing context (maximum flexibility) | +| Single subscription | Applies only to resources in one subscription | +| Single resource group | Applies only to resources in one resource group | +| Management group | Applies across subscriptions in a management group | + +### Instance size flexibility + +Within a VM series (e.g., D-series), a reservation for one size automatically applies to other sizes in the same series using a ratio-based approach. + +Example for D-series: + +| VM Size | Ratio | +|---------|-------| +| Standard_D1 | 1 | +| Standard_D2 | 2 | +| Standard_D4 | 4 | +| Standard_D8 | 8 | + +A reservation for one Standard_D4 (ratio 4) can cover four Standard_D1 instances (ratio 1 each) or two Standard_D2 instances (ratio 2 each). + +**Important:** Reservations are region-specific. A reservation purchased for East US does not apply to resources in West US. + +--- + +## Exchange and return policy + +| Action | Policy | +|--------|--------| +| Returns | Self-service cancellation with prorated refund. Up to $50,000 USD (or equivalent) in returns per rolling 12-month window. Early termination fee is not currently charged. | +| Exchanges | Within the same product family only. Prorated value applied to new reservation. Exchange refunds do NOT count against the $50K return limit. | +| Trade-in | Existing reservations can be traded in for savings plans via self-service (no time limit). | + +### Compute reservation exchange grace period + +For compute reservations (VMs, Dedicated Host, App Service), cross-series and cross-region exchanges are currently allowed under an extended grace period "until further notice." Microsoft will provide at least 6 months advance notice before ending this grace period. After it ends, compute reservation exchanges will be limited to within the same instance size flexibility group only. + +### Reservation types that cannot be exchanged or refunded + +Azure Databricks, Synapse Analytics Pre-purchase, Red Hat plans, SUSE Linux plans, Microsoft Defender for Cloud Pre-Purchase, and Microsoft Sentinel Pre-Purchase. + +**Important:** These policies differ significantly from savings plans, which have no cancellation, return, or exchange option. Consider reservation trade-in to savings plans as an alternative exit path. + +### Calculate refund for a specific reservation + +```bash +# Calculate the refund amount for a specific reservation return (not the aggregate $50K balance) +az rest --method POST \ + --url "https://management.azure.com/providers/Microsoft.Capacity/calculateRefund?api-version=2022-11-01" \ + --body '{ + "id": "/providers/Microsoft.Capacity/reservationOrders/{reservationOrderId}", + "properties": { + "scope": "Reservation", + "reservationToReturn": { + "reservationId": "/providers/Microsoft.Capacity/reservationOrders/{orderId}/reservations/{reservationId}", + "quantity": 1 + } + } + }' +``` + +--- + +## Benefit application order + +Reservations and savings plans follow a strict application order: + +1. **Reservations are applied first** in the benefit stack +2. **Savings plans are applied second** to remaining eligible charges +3. This means reservations "win" for matching workloads; savings plans catch the rest + +Within reservations, the most specific scope is applied first: + +1. Resource group scope +2. Subscription scope +3. Management group scope +4. Shared scope + +--- + +## Utilization monitoring + +### Azure CLI + +```bash +# Daily utilization summary for a reservation order +az consumption reservation summary list \ + --reservation-order-id {orderId} \ + --grain daily \ + --start-date 2026-01-01 \ + --end-date 2026-01-31 +``` + +### REST API + +> **Authentication note:** Use `az rest` in practice — it handles token acquisition automatically. + +```http +GET https://management.azure.com/providers/Microsoft.Capacity/reservationOrders/{reservationOrderId}/providers/Microsoft.Consumption/reservationSummaries?grain=daily&$filter=properties/usageDate ge 2026-01-01 AND properties/usageDate le 2026-01-31&api-version=2024-08-01 +Authorization: Bearer {token} +``` + +### Azure Resource Graph -- Advisor purchase recommendations + +Query cross-subscription Advisor recommendations for VM reserved instance purchases (recommendationTypeId is specific to VM reservations): + +```kusto +advisorresources +| where type == "microsoft.advisor/recommendations" +| where properties.category == "Cost" +| where properties.recommendationTypeId == "84b1a508-fc21-49da-979e-96894f1665df" +| extend + savings = todouble(properties.extendedProperties.savingsAmount), + annualSavings = todouble(properties.extendedProperties.annualSavingsAmount) +| project subscriptionId, resourceGroup, savings, annualSavings, + problem = properties.shortDescription.problem, + solution = properties.shortDescription.solution +| order by savings desc +``` + +**Note:** This query surfaces Advisor purchase recommendations, not utilization data. For utilization monitoring, use the Azure CLI or REST API examples above. + +--- + +## Eligibility + +### Agreement types + +| Agreement Type | Offer IDs | Can purchase reservations | +|----------------|----------------|--------------------------| +| EA | MS-AZR-0017P, MS-AZR-0148P | Yes | +| MCA | - | Yes | +| MPA | - | Yes | +| CSP | - | Yes (partners purchase via Partner Center; customers cannot self-service manage) | +| Pay-As-You-Go | MS-AZR-0003P, MS-AZR-0023P | Yes | +| Azure Sponsorship | MS-AZR-0036P | Yes | + +### Required roles + +| Action | Required role | +|--------|---------------| +| View recommendations | Cost Management Reader | +| View utilization | Cost Management Reader or Reservation Reader | +| Purchase reservations | Owner or Reservation Purchaser | +| Manage reservations | Owner or Reservation Administrator | + +--- + +## Payment options + +| Option | Description | +|--------|-------------| +| All upfront | Pay the full commitment amount at purchase | +| Monthly | Pay in monthly installments over the term | + +Payment frequency does not affect the discount amount — only cash flow timing. Total cost is the same for either option. + +--- + +## Auto-renewal + +Reservations can be configured for automatic renewal before expiration. Review utilization data before renewal to confirm the commitment level and SKU are still appropriate. Auto-renewal is enabled by default for new purchases — disable it in the Azure portal if you prefer manual renewal. + +--- + +## Coverage limitations + +Reservation discounts cover the **compute or capacity portion** of the specified resource type only. The following are NOT covered: + +- Software licensing (Windows Server, SQL Server — use Azure Hybrid Benefit separately) +- Networking charges +- Storage costs (except for Azure Blob Storage and Azure Files reserved capacity) +- Marketplace purchases + +--- + +## Best practices + +1. **Normalize usage for at least 30 days** before purchasing to ensure stable baseline +2. **Use instance size flexibility** - buy the normalized size for maximum coverage within a VM series +3. **Monitor utilization weekly** - exchange underutilized reservations before waste accumulates +4. **Start with shared scope** for maximum flexibility across subscriptions +5. **Use the 3-day stale data guard** - Microsoft provides the lower of 3-day and lookback-period recommendations as a safeguard against overcommitment +6. **Compare with savings plans** - use the Benefit Recommendations API to evaluate both options before purchasing +7. **Layer reservations and savings plans** - buy reservations for stable, predictable workloads; use savings plans as a safety net for variable compute + +See `references/azure-commitment-discount-decision.md` for the full decision framework. + +--- + +## Troubleshooting + +| Problem | Cause | Solution | +|---------|-------|----------| +| Low utilization | VM stopped/deallocated or wrong SKU | Check VM state, consider exchange for a different SKU or region | +| Reservation not applying | Scope mismatch or region mismatch | Verify scope and region settings match the target resources | +| No recommendations | Insufficient usage history | Wait for 7+ days of consistent usage before querying | +| Exchange failed | Exceeded $50K return limit | Check remaining return balance in Azure portal | +| Wrong VM size covered | Instance size flexibility ratio | Review the flexibility group ratio table for the VM series | +| Reservation expired | Term ended | Purchase a new reservation; set calendar reminders before expiration | + +--- + +## Prerequisites + +- Azure PowerShell module (`Install-Module -Name Az`) or Azure CLI +- Authenticated Azure session (`Connect-AzAccount` or `az login`) +- **Cost Management Reader** permissions on the billing scope (for recommendations) +- **Owner** or **Reservation Purchaser** role (for purchasing) + +--- + +## References + +- [Azure Reservations overview](https://learn.microsoft.com/azure/cost-management-billing/reservations/save-compute-costs-reservations) +- [Reservation recommendations](https://learn.microsoft.com/azure/cost-management-billing/reservations/reserved-instance-purchase-recommendations) +- [Instance size flexibility](https://learn.microsoft.com/azure/virtual-machines/reserved-vm-instance-size-flexibility) +- [Self-service exchanges and refunds](https://learn.microsoft.com/azure/cost-management-billing/reservations/exchange-and-refund-azure-reservations) +- [Benefit Recommendations API](https://learn.microsoft.com/rest/api/cost-management/benefit-recommendations) +- [Manage reservations](https://learn.microsoft.com/azure/cost-management-billing/reservations/manage-reserved-vm-instance) +- [Reservation trade-in to savings plans](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/reservation-trade-in) +- [Reservation exchange policy changes](https://learn.microsoft.com/azure/cost-management-billing/reservations/reservation-exchange-policy-changes) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-retail-prices.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-retail-prices.md new file mode 100644 index 000000000..469084eeb --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-retail-prices.md @@ -0,0 +1,263 @@ +--- +name: Azure Retail Prices +description: Query the Azure Retail Prices API (prices.azure.com) to look up public pricing for any Azure service by SKU, region, and tier. Public API, no authentication required. Use for price comparisons, rightsizing calculations, and validating Advisor savings estimates. +--- + +**Key Features:** +- Public API — no authentication required +- OData filter syntax for precise queries +- Coverage across all Azure services and regions +- Reserved vs pay-as-you-go price comparison +- Cross-region price comparison +- Pagination support for large result sets + +--- + +## Base URL + +``` +https://prices.azure.com/api/retail/prices +``` + +No API key or Azure authentication needed. Rate-limited but generous for interactive use. + +--- + +## OData filter syntax + +### Common filter properties + +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| `serviceName` | string | Azure service name | `Virtual Machines`, `Storage` | +| `armSkuName` | string | ARM SKU identifier | `Standard_D4s_v5`, `Standard_LRS` | +| `armRegionName` | string | Azure region | `eastus`, `westeurope` | +| `skuName` | string | Human-readable SKU | `D4s v5`, `D4s v5 Low Priority` | +| `priceType` | string | Pricing model | `Consumption`, `Reservation` | +| `currencyCode` | string | ISO currency code | `USD`, `EUR` | +| `productName` | string | Product family | `Virtual Machines DS Series` | +| `meterName` | string | Meter name | `D4s v5`, `D4s v5 Spot` | +| `type` | string | Rate type | `Consumption`, `DevTestConsumption` | +| `reservationTerm` | string | RI term length | `1 Year`, `3 Years` | +| `tierMinimumUnits` | number | Volume tier minimum | `0` | + +### Filter operators + +``` +eq - equals +ne - not equals +gt - greater than +lt - less than +ge - greater than or equal +le - less than or equal +and - logical AND +or - logical OR +contains(field, 'value') - substring match +``` + +--- + +## Common query patterns + +### VM pricing by SKU and region + +```bash +curl -s "https://prices.azure.com/api/retail/prices?\$filter=armSkuName eq 'Standard_D4s_v5' and armRegionName eq 'eastus' and priceType eq 'Consumption'" | jq '.Items[] | {skuName, retailPrice, unitOfMeasure, meterName}' +``` + +```powershell +$response = Invoke-RestMethod "https://prices.azure.com/api/retail/prices?`$filter=armSkuName eq 'Standard_D4s_v5' and armRegionName eq 'eastus' and priceType eq 'Consumption'" +$response.Items | Select-Object skuName, retailPrice, unitOfMeasure, meterName | Format-Table +``` + +### Storage pricing by tier and redundancy + +```bash +curl -s "https://prices.azure.com/api/retail/prices?\$filter=serviceName eq 'Storage' and armRegionName eq 'eastus' and skuName eq 'Hot LRS' and productName eq 'Azure Data Lake Storage Gen2'" | jq '.Items[] | {meterName, retailPrice, unitOfMeasure}' +``` + +### Reserved vs pay-as-you-go price comparison + +```powershell +# Get PAYG and reserved prices for a VM SKU +$sku = "Standard_D4s_v5" +$region = "eastus" + +$payg = Invoke-RestMethod "https://prices.azure.com/api/retail/prices?`$filter=armSkuName eq '$sku' and armRegionName eq '$region' and priceType eq 'Consumption'" +$ri1yr = Invoke-RestMethod "https://prices.azure.com/api/retail/prices?`$filter=armSkuName eq '$sku' and armRegionName eq '$region' and priceType eq 'Reservation' and reservationTerm eq '1 Year'" +$ri3yr = Invoke-RestMethod "https://prices.azure.com/api/retail/prices?`$filter=armSkuName eq '$sku' and armRegionName eq '$region' and priceType eq 'Reservation' and reservationTerm eq '3 Years'" + +# Calculate hourly equivalent rates +$paygHourly = ($payg.Items | Where-Object { $_.meterName -eq 'D4s v5' -and $_.type -eq 'Consumption' }).retailPrice +# Reservation retailPrice is already the hourly equivalent rate (unitOfMeasure = "1 Hour") +$ri1yrHourly = ($ri1yr.Items | Where-Object { $_.meterName -eq 'D4s v5' }).retailPrice +$ri3yrHourly = ($ri3yr.Items | Where-Object { $_.meterName -eq 'D4s v5' }).retailPrice + +Write-Host "PAYG hourly: `$$([math]::Round($paygHourly, 4))" +Write-Host "1-yr RI hourly: `$$([math]::Round($ri1yrHourly, 4)) ($([math]::Round((1 - $ri1yrHourly/$paygHourly) * 100, 1))% savings)" +Write-Host "3-yr RI hourly: `$$([math]::Round($ri3yrHourly, 4)) ($([math]::Round((1 - $ri3yrHourly/$paygHourly) * 100, 1))% savings)" +``` + +### Cross-region price comparison + +```powershell +$sku = "Standard_D4s_v5" +$regions = @("eastus", "westus2", "westeurope", "southeastasia") + +$results = foreach ($region in $regions) { + $response = Invoke-RestMethod "https://prices.azure.com/api/retail/prices?`$filter=armSkuName eq '$sku' and armRegionName eq '$region' and priceType eq 'Consumption'" + $price = ($response.Items | Where-Object { $_.meterName -eq 'D4s v5' -and $_.type -eq 'Consumption' }).retailPrice + [PSCustomObject]@{ + Region = $region + HourlyPrice = $price + MonthlyEstimate = [math]::Round($price * 730, 2) + } +} + +$results | Sort-Object HourlyPrice | Format-Table +``` + +--- + +## Response structure + +```json +{ + "BillingCurrency": "USD", + "CustomerEntityId": "Default", + "CustomerEntityType": "Retail", + "Items": [ + { + "currencyCode": "USD", + "tierMinimumUnits": 0.0, + "retailPrice": 0.192, + "unitPrice": 0.192, + "armRegionName": "eastus", + "location": "US East", + "effectiveStartDate": "2023-04-01T00:00:00Z", + "meterId": "...", + "meterName": "D4s v5", + "productId": "...", + "skuId": "...", + "productName": "Virtual Machines DSv5 Series", + "skuName": "D4s v5", + "serviceName": "Virtual Machines", + "serviceId": "...", + "serviceFamily": "Compute", + "unitOfMeasure": "1 Hour", + "type": "Consumption", + "isPrimaryMeterRegion": true, + "armSkuName": "Standard_D4s_v5" + } + ], + "NextPageLink": "https://prices.azure.com/api/retail/prices?$skip=100&...", + "Count": 1 +} +``` + +### Key fields + +| Field | Description | +|-------|-------------| +| `retailPrice` | List price (no discounts applied) | +| `unitPrice` | Same as `retailPrice` for retail customers | +| `unitOfMeasure` | Billing unit: `1 Hour`, `1 GB/Month`, `10,000 Transactions` | +| `armSkuName` | ARM SKU for programmatic cross-reference | +| `isPrimaryMeterRegion` | `true` for the canonical region meter; filter on this to avoid duplicates | +| `type` | `Consumption` (PAYG), `DevTestConsumption` (Dev/Test), `Reservation` | +| `reservationTerm` | Present only for `Reservation` type: `1 Year` or `3 Years` | + +--- + +## Pagination + +Results are paginated at 100 items per page. Use `NextPageLink` to iterate: + +```powershell +function Get-AllRetailPrices { + param([string]$Filter) + + $url = "https://prices.azure.com/api/retail/prices?`$filter=$Filter" + $allItems = @() + + while ($url) { + $response = Invoke-RestMethod $url + $allItems += $response.Items + $url = $response.NextPageLink + } + + return $allItems +} + +# Usage +$prices = Get-AllRetailPrices -Filter "serviceName eq 'Virtual Machines' and armRegionName eq 'eastus' and priceType eq 'Consumption'" +Write-Host "Found $($prices.Count) pricing records" +``` + +```bash +# Bash pagination with jq +url="https://prices.azure.com/api/retail/prices?\$filter=armSkuName eq 'Standard_D4s_v5' and armRegionName eq 'eastus'" +while [ "$url" != "null" ] && [ -n "$url" ]; do + response=$(curl -s "$url") + echo "$response" | jq '.Items[]' + url=$(echo "$response" | jq -r '.NextPageLink') +done +``` + +--- + +## Integration patterns + +### Validate Advisor savings estimates + +Cross-reference Advisor right-size recommendations with actual retail prices to validate savings claims: + +```powershell +# Get Advisor right-size recommendation details +$rec = Get-AzAdvisorRecommendation | + Where-Object { $_.RecommendationTypeId -eq 'e10b1381-5f0a-47ff-8c7b-37bd13d7c974' } | + Select-Object -First 1 + +$currentSku = $rec.ExtendedProperty["currentSku"] +$targetSku = $rec.ExtendedProperty["targetSku"] +$region = $rec.ExtendedProperty["regionId"] + +# Look up actual prices +$currentPrice = (Get-AllRetailPrices -Filter "armSkuName eq '$currentSku' and armRegionName eq '$region' and priceType eq 'Consumption'" | + Where-Object { $_.isPrimaryMeterRegion -and $_.type -eq 'Consumption' }).retailPrice + +$targetPrice = (Get-AllRetailPrices -Filter "armSkuName eq '$targetSku' and armRegionName eq '$region' and priceType eq 'Consumption'" | + Where-Object { $_.isPrimaryMeterRegion -and $_.type -eq 'Consumption' }).retailPrice + +$monthlySavings = ($currentPrice - $targetPrice) * 730 +Write-Host "Current: $currentSku @ `$$currentPrice/hr" +Write-Host "Target: $targetSku @ `$$targetPrice/hr" +Write-Host "Monthly savings: `$$([math]::Round($monthlySavings, 2))" +``` + +### Calculate rightsizing savings + +See `references/azure-vm-rightsizing.md` for the full rightsizing workflow that uses this API to validate target SKU pricing. + +--- + +## Limitations + +| Limitation | Impact | +|-----------|--------| +| **Retail/list prices only** | No EA/MCA negotiated rates, no discount-adjusted prices | +| **No real-time availability** | Prices may lag behind actual availability by hours | +| **Rate limiting** | No published limits, but excessive requests may be throttled | +| **No savings plan pricing** | Savings plan effective rates are not exposed (use Benefit Recommendations API instead) | +| **Currency conversion** | Prices are listed per currency; exchange rates are Microsoft-determined | + +**Important:** Retail prices are useful for relative comparisons (SKU A vs SKU B, region X vs region Y) and for estimating savings percentages. For actual bill amounts, use Cost Management APIs or FinOps hubs cost data. + +--- + +## References + +- [Azure Retail Prices API overview](https://learn.microsoft.com/rest/api/cost-management/retail-prices/azure-retail-prices) +- [Retail Prices OData query examples](https://learn.microsoft.com/rest/api/cost-management/retail-prices/azure-retail-prices#api-examples) +- [Azure pricing calculator](https://azure.microsoft.com/pricing/calculator/) +- [Rate Optimization (FinOps Framework)](https://www.finops.org/framework/capabilities/rate-optimization/) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-savings-plans.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-savings-plans.md new file mode 100644 index 000000000..af480f3f7 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-savings-plans.md @@ -0,0 +1,424 @@ +--- +name: Azure Savings Plans +description: Query the Azure Cost Management Benefit Recommendations API to retrieve savings plan purchase recommendations based on historical compute usage patterns. Analyze potential savings (up to 65% vs PAYG), coverage percentages, and optimal commitment amounts for flexible compute workloads. +--- + +**Key Features:** +- Historical usage analysis (7, 30, or 60 days lookback) +- Up to 10 commitment level recommendations +- Savings calculations vs pay-as-you-go pricing +- Coverage and utilization projections +- Support for 1-year and 3-year terms + +--- + +## Benefit Recommendations API + +### PowerShell Script + +```powershell +# Basic usage with subscription scope +.\Get-BenefitRecommendations.ps1 ` + -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" + +# Advanced: billing account, 30-day lookback, 1-year term +.\Get-BenefitRecommendations.ps1 ` + -BillingScope "providers/Microsoft.Billing/billingAccounts/12345678" ` + -LookBackPeriod "Last30Days" ` + -Term "P1Y" + +# Resource group scope +.\Get-BenefitRecommendations.ps1 ` + -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/myResourceGroup" +``` + +### Parameters + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `BillingScope` | Yes | - | Billing account, subscription, or resource group scope | +| `LookBackPeriod` | No | Last7Days | Analysis period: Last7Days, Last30Days, Last60Days. Script default is Last7Days; API default (when omitted from REST call) is Last60Days | +| `Term` | No | P3Y | Savings plan term: P1Y (1-year) or P3Y (3-year) | + +### Scope Formats + +| Scope Type | Format | +|------------|--------| +| Billing Account | `providers/Microsoft.Billing/billingAccounts/{billingAccountId}` | +| Billing Profile (MCA) | `providers/Microsoft.Billing/billingAccounts/{billingAccountId}/billingProfiles/{billingProfileId}` | +| Subscription | `subscriptions/{subscriptionId}` | +| Resource Group | `subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}` | + +--- + +## Output Metrics + +The API returns detailed financial projections: + +| Metric | Description | +|--------|-------------| +| **commitmentAmount** | Hourly commitment amount at specified granularity | +| **savingsAmount** | Total amount saved for the lookback period | +| **savingsPercentage** | Savings percentage vs pay-as-you-go | +| **coveragePercentage** | Estimated benefit coverage for the lookback period | +| **averageUtilizationPercentage** | Estimated average utilization with this commitment | +| **totalCost** | Sum of benefit cost and overage cost | +| **benefitCost** | commitmentAmount × totalHours | +| **overageCost** | Charges exceeding the commitment | +| **wastageCost** | Unused portion of the benefit cost | + +--- + +## REST API + +> **Authentication note:** Use `az rest` in practice — it handles token acquisition automatically. The raw HTTP examples below are for documentation purposes only. + +### Request + +```http +GET https://management.azure.com/{billingScope}/providers/Microsoft.CostManagement/benefitRecommendations?$filter=properties/lookBackPeriod eq 'Last30Days' AND properties/term eq 'P3Y'&$expand=properties/usage,properties/allRecommendationDetails&api-version=2024-08-01 +Authorization: Bearer {token} +``` + +All parameters are passed via OData `$filter` query parameters, not a request body. The `$expand` parameter controls which detail sections are returned: + +| $expand value | Effect | +|---------------|--------| +| `properties/allRecommendationDetails` | Returns all 10 commitment level recommendations (required for comparison analysis) | +| `properties/usage` | Returns hourly usage data for the lookback period | + +To filter for savings plans only, add `AND properties/kind eq 'SavingsPlan'` to the `$filter`. Without a `kind` filter, the API returns both savings plan and reservation recommendations. + +### Scope values + +| Scope | Description | +|-------|-------------| +| `Shared` | Analyzes usage across entire billing scope (default, optimal savings) | +| `Single` | Resource-specific recommendations | + +**Note:** Add `AND properties/scope eq 'Shared'` to the `$filter` to specify scope. Default behavior analyzes shared scope. + +### Response structure + +```json +{ + "value": [ + { + "properties": { + "firstConsumptionDate": "2026-01-01", + "lastConsumptionDate": "2026-01-21", + "lookBackPeriod": "Last30Days", + "term": "P3Y", + "totalHours": 720, + "scope": "Shared", + "kind": "SavingsPlan", + "currencyCode": "USD", + "costWithoutBenefit": 11000, + "recommendationDetails": { + "commitmentAmount": 10.5, + "savingsAmount": 2500, + "savingsPercentage": 25.5, + "coveragePercentage": 85.2, + "averageUtilizationPercentage": 92.3, + "totalCost": 8500, + "benefitCost": 7560, + "overageCost": 940, + "wastageCost": 580 + }, + "allRecommendationDetails": { + "value": [ + { "commitmentAmount": 5.0, "savingsPercentage": 15.2, "averageUtilizationPercentage": 98.1 }, + { "commitmentAmount": 10.5, "savingsPercentage": 25.5, "averageUtilizationPercentage": 92.3 }, + { "commitmentAmount": 15.0, "savingsPercentage": 28.1, "averageUtilizationPercentage": 85.7 } + ] + } + } + } + ] +} +``` + +**Note:** The `allRecommendationDetails` array only appears when `$expand=properties/allRecommendationDetails` is included in the request. The `recommendationDetails` object always contains the single best recommendation. + +--- + +## Analysis Examples + +### Find Optimal Commitment Level + +```powershell +# Get recommendations +$result = .\Get-BenefitRecommendations.ps1 ` + -BillingScope "subscriptions/$subscriptionId" ` + -LookBackPeriod "Last30Days" ` + -Term "P3Y" + +# Find recommendation with best savings/utilization balance +$optimal = $result.recommendations | + Where-Object { $_.averageUtilizationPercentage -ge 90 } | + Sort-Object savingsAmount -Descending | + Select-Object -First 1 + +Write-Host "Optimal hourly commitment: $($optimal.commitmentAmount)" +Write-Host "Projected monthly savings: $($optimal.savingsAmount)" +Write-Host "Coverage: $($optimal.coveragePercentage)%" +``` + +### Compare 1-Year vs 3-Year Terms + +```powershell +$scope = "subscriptions/$subscriptionId" + +$oneYear = .\Get-BenefitRecommendations.ps1 -BillingScope $scope -Term "P1Y" +$threeYear = .\Get-BenefitRecommendations.ps1 -BillingScope $scope -Term "P3Y" + +# Compare top recommendations +$comparison = @{ + "1-Year" = @{ + Commitment = $oneYear.recommendations[0].commitmentAmount + Savings = $oneYear.recommendations[0].savingsPercentage + } + "3-Year" = @{ + Commitment = $threeYear.recommendations[0].commitmentAmount + Savings = $threeYear.recommendations[0].savingsPercentage + } +} + +$comparison | ConvertTo-Json +``` + +--- + +## Integration with FinOps analysis + +### Utilization analysis + +```powershell +# Assess whether the recommended commitment level will be fully utilized +# Key metric: averageUtilizationPercentage — the projected percentage of committed hours that would be consumed +# Target: >90% utilization = good commitment fit; <80% = consider lower commitment + +$optimal = $result.recommendations | + Where-Object { $_.averageUtilizationPercentage -ge 90 } | + Sort-Object savingsAmount -Descending | + Select-Object -First 1 + +$wastageRate = (1 - ($optimal.averageUtilizationPercentage / 100)) * $optimal.benefitCost +Write-Host "Projected hourly commitment: $($optimal.commitmentAmount)" +Write-Host "Projected savings (lookback period): $($optimal.savingsAmount)" +Write-Host "Projected wastage (lookback period): $wastageRate" +Write-Host "Utilization: $($optimal.averageUtilizationPercentage)%" +``` + +**Important:** The `savingsAmount` from the API represents total savings over the lookback period (7, 30, or 60 days), not annual savings. Do not divide by 12 to get monthly figures — instead scale proportionally from the lookback window. + +### Risk assessment + +```powershell +# Evaluate commitment risk based on utilization variance +$recommendations = $result.recommendations + +foreach ($rec in $recommendations) { + $risk = switch ($rec.averageUtilizationPercentage) { + { $_ -ge 95 } { "Low - High utilization, minimal waste"; break } + { $_ -ge 85 } { "Medium - Good utilization, some flexibility"; break } + { $_ -ge 70 } { "High - Consider lower commitment"; break } + default { "Very High - Significant underutilization risk" } + } + + Write-Host "Commitment: $($rec.commitmentAmount)/hr - Risk: $risk" +} +``` + +--- + +## Savings plan policies + +### Eligibility + +Savings plans are available for these agreement types only: +- Enterprise Agreement (EA): Offer IDs MS-AZR-0017P, MS-AZR-0148P +- Microsoft Customer Agreement (MCA) +- Microsoft Partner Agreement (MPA) + +**Not available** for CSP (Cloud Solution Provider), Pay-As-You-Go, or free/trial subscriptions. + +### Cancellation and refund policy + +Savings plan purchases **cannot be canceled or refunded**. This is a hard constraint — there is no self-service cancellation, no exchange, and no early termination option. This is the most significant policy difference from reservations (which allow up to $50K/year in returns). + +### Payment options + +| Option | Description | +|--------|-------------| +| All upfront | Pay the full commitment amount at purchase (total cost is the same) | +| Monthly | Pay in monthly installments over the term (total cost is the same) | + +Payment frequency does not affect the discount amount — only cash flow timing. + +### Auto-renewal + +Savings plans can be configured for automatic renewal before expiration. Set this at purchase time or update later in the Azure portal. Review utilization before renewal to confirm the commitment level is still appropriate. + +--- + +## Discount application mechanics + +### How benefits are applied + +Savings plan discounts are applied **hourly** on a use-it-or-lose-it basis: + +1. Each hour, Azure calculates your eligible compute charges +2. The savings plan benefit is applied to the product with the **greatest discount first** (maximizing your savings) +3. Any unused commitment for that hour is **lost** — it does not roll over +4. Reservations are always applied **before** savings plans in the benefit stack + +### Scope processing order + +When multiple commitment discounts exist, benefits are applied in this order: +1. Resource group scope (most specific) +2. Subscription scope +3. Management group scope +4. Shared scope (broadest) + +### Coverage limitations + +Savings plans cover **compute charges only**. The following are NOT covered: +- Software licensing (Windows Server, SQL Server — use Azure Hybrid Benefit separately) +- Networking charges +- Storage costs +- Marketplace purchases + +--- + +## Recommendation guidance + +### The 3-day stale data guard + +Microsoft runs simulations using only the last 3 days of usage as a safeguard against overcommitment from stale data. The recommendation engine provides the **lower** of the 3-day and full lookback-period recommendations. This means short usage spikes within the lookback window will not inflate recommendations. + +### 7-day waiting period + +After purchasing a savings plan or reservation, wait at least **7 days** before evaluating further commitment recommendations. The recommendation engine needs time to recalculate based on the new benefit coverage. Purchasing immediately can result in double-coverage and wastage. + +### Management group workaround + +The Benefit Recommendations API does not support management group scope. Microsoft's documented workaround: +1. Get recommendations for each subscription individually +2. Sum the recommended commitment amounts +3. Purchase approximately **70%** of the total (conservative start) +4. Wait 3 days for the recommendation engine to recalculate +5. Iterate — get new recommendations accounting for existing commitments +6. Repeat until incremental savings are negligible + +### Savings quantification + +Savings plans provide up to **65% savings** compared to pay-as-you-go pricing. Actual savings depend on: +- Commitment term (3-year provides deeper discounts than 1-year) +- Utilization rate (higher utilization = more realized savings) +- Workload consistency (stable usage patterns maximize benefit) + +For comparison, reservations offer up to **72% savings** but with less flexibility. See `references/azure-commitment-discount-decision.md` for the decision framework. + +--- + +## Script source + +The `Get-BenefitRecommendations.ps1` script is embedded below for self-contained use. This script uses `Invoke-AzRestMethod` with the correct GET method and OData filter parameters. + +```powershell +<# +.SYNOPSIS + Get Azure Cost Management benefit recommendations for savings plans and reserved instances. + +.DESCRIPTION + This script queries the Azure Cost Management API to retrieve benefit recommendations + based on historical usage patterns. It helps identify opportunities for cost savings + through Azure savings plans and reserved instances. + +.PARAMETER BillingScope + The billing scope to query. Can be a billing account or subscription. + Examples: + - "providers/Microsoft.Billing/billingAccounts/12345678" + - "subscriptions/12345678-1234-1234-1234-123456789012" + +.PARAMETER LookBackPeriod + Historical period to analyze for recommendations. + Valid values: Last7Days, Last30Days, Last60Days + Default: Last7Days + +.PARAMETER Term + Commitment term for savings plans. + Valid values: P1Y (1 year), P3Y (3 years) + Default: P3Y + +.EXAMPLE + .\Get-BenefitRecommendations.ps1 -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" + + Gets 3-year savings plan recommendations for a subscription based on last 7 days usage. + +.EXAMPLE + .\Get-BenefitRecommendations.ps1 -BillingScope "providers/Microsoft.Billing/billingAccounts/12345678" -LookBackPeriod "Last30Days" -Term "P1Y" + + Gets 1-year savings plan recommendations for a billing account based on last 30 days usage. + +.NOTES + Requires Azure PowerShell module and Cost Management Reader permissions on the specified scope. + + To find your billing account: Get-AzBillingAccount + To find subscriptions: Get-AzSubscription +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $true, HelpMessage = "Billing scope (billing account or subscription)")] + [string] + $BillingScope, + + [Parameter()] + [ValidateSet('Last7Days', 'Last30Days', 'Last60Days')] + [string] + $LookBackPeriod = 'Last7Days', + + [Parameter()] + [ValidateSet('P1Y', 'P3Y')] + [string] + $Term = 'P3Y' +) + +$url="https://management.azure.com/{0}/providers/Microsoft.CostManagement/benefitRecommendations?`$filter=properties/lookBackPeriod eq '{1}' AND properties/term eq '{2}'&`$expand=properties/usage,properties/allRecommendationDetails&api-version=2024-08-01" -f $BillingScope, $lookBackPeriod, $term +$uri=[uri]::new($url) +$result = Invoke-AzRestMethod -Uri $uri.AbsoluteUri -Method GET +$jsonResult = $result.Content | ConvertFrom-Json + +Write-Output "" +Write-Output "Raw output" +$result.Content +Write-Output "" +Write-Output "Recommended savings plan" +$jsonResult.value.properties.recommendationDetails | Format-Table +Write-Output "" +Write-Output "All savings plan recommendations" +$jsonResult.value.properties.allRecommendationDetails.value | Format-Table +``` + +--- + +## Prerequisites + +- Azure PowerShell module (`Install-Module -Name Az`) +- Authenticated Azure session (`Connect-AzAccount`) +- **Cost Management Reader** permissions on the billing scope +- Valid billing account ID or subscription ID +- Agreement type: EA (MS-AZR-0017P or MS-AZR-0148P), MCA, or MPA + +--- + +## References + +- [Benefit Recommendations API](https://learn.microsoft.com/rest/api/cost-management/benefit-recommendations) +- [Azure savings plan overview](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/savings-plan-compute-overview) +- [Choose commitment amount](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/choose-commitment-amount) +- [How saving plan discount is applied](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/discount-application) +- [Decide between a savings plan and a reservation](https://learn.microsoft.com/azure/cost-management-billing/savings-plan/decide-between-savings-plan-reservation) +- [Rate Optimization (FinOps Framework)](https://www.finops.org/framework/capabilities/rate-optimization/) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-vm-rightsizing.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-vm-rightsizing.md new file mode 100644 index 000000000..25f03dad9 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-vm-rightsizing.md @@ -0,0 +1,293 @@ +--- +name: Azure VM Rightsizing +description: Workflow for identifying over-provisioned VMs using Azure Advisor recommendations and Azure Monitor metrics, then recommending SKU downsizes validated against retail pricing. Covers CPU, memory, and disk IO utilization analysis with safety checks for burst requirements and Hybrid Benefit status. +--- + +**Key Features:** +- Azure Advisor right-size VM candidate identification +- Azure Monitor / Log Analytics utilization metric collection +- Utilization thresholds: CPU P95 < 20%, memory avg < 30% +- Target SKU recommendation with retail price validation +- Safety checks: burst requirements, instance size flexibility, Hybrid Benefit + +--- + +## Overview + +VM rightsizing is the highest-value single resource optimization in most Azure environments. The workflow: + +1. **Identify candidates** — Advisor flags underutilized VMs +2. **Collect metrics** — Azure Monitor confirms utilization patterns +3. **Recommend target SKU** — downsize within the VM family +4. **Validate pricing** — confirm savings with Retail Prices API +5. **Safety check** — burst, flexibility, licensing + +--- + +## Step 1: Identify candidates via Azure Advisor + +Azure Advisor recommendation type `e10b1381-5f0a-47ff-8c7b-37bd13d7c974` identifies VMs for rightsizing based on 7-day utilization analysis. + +### Azure CLI + +```bash +az advisor recommendation list \ + --category Cost \ + --query "[?recommendationTypeId=='e10b1381-5f0a-47ff-8c7b-37bd13d7c974'].{ + Resource: resourceMetadata.resourceId, + CurrentSku: extendedProperties.currentSku, + TargetSku: extendedProperties.targetSku, + Savings: extendedProperties.savingsAmount, + Region: extendedProperties.regionId + }" \ + --output table +``` + +### Resource Graph (cross-subscription) + +```kusto +advisorresources +| where type == "microsoft.advisor/recommendations" +| where properties.recommendationTypeId == "e10b1381-5f0a-47ff-8c7b-37bd13d7c974" +| extend currentSku = tostring(properties.extendedProperties.currentSku) +| extend targetSku = tostring(properties.extendedProperties.targetSku) +| extend savings = todouble(properties.extendedProperties.savingsAmount) +| extend vmId = tostring(properties.resourceMetadata.resourceId) +| extend region = tostring(properties.extendedProperties.regionId) +| project vmId, currentSku, targetSku, savings, region, subscriptionId +| order by savings desc +``` + +See `references/azure-advisor.md` for full Advisor query patterns and suppression management. + +--- + +## Step 2: Collect utilization metrics + +Advisor's built-in analysis uses 7 days of data. For higher confidence, collect 14–30 days of metrics from Azure Monitor. + +### CPU utilization (Azure Monitor) + +```bash +# Average, P95, and max CPU over 14 days +az monitor metrics list \ + --resource "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Compute/virtualMachines/{vmName}" \ + --metric "Percentage CPU" \ + --start-time $(date -u -d "14 days ago" +%Y-%m-%dT%H:%M:%SZ) \ + --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ + --interval PT1H \ + --aggregation Average Maximum \ + --query "value[0].timeseries[0].data[].{Time: timeStamp, Avg: average, Max: maximum}" +``` + +### Memory utilization (requires VM Insights) + +Memory metrics require the Azure Monitor Agent (AMA) or Log Analytics agent. Query via Log Analytics workspace: + +```kusto +// Memory utilization over 14 days +InsightsMetrics +| where TimeGenerated > ago(14d) +| where Origin == "vm.azm.ms" +| where Namespace == "Memory" +| where Name == "AvailableMB" +| extend TotalMB = todouble(Tags["vm.azm.ms/memorySizeMB"]) +| extend UsedPercent = (TotalMB - Val) / TotalMB * 100 +| summarize + AvgMemoryPercent = avg(UsedPercent), + P95MemoryPercent = percentile(UsedPercent, 95), + MaxMemoryPercent = max(UsedPercent) + by Computer +``` + +### Disk IO utilization + +```kusto +// Disk IOPS and throughput over 14 days +InsightsMetrics +| where TimeGenerated > ago(14d) +| where Origin == "vm.azm.ms" +| where Namespace == "LogicalDisk" +| where Name in ("ReadsPerSecond", "WritesPerSecond", "ReadBytesPerSecond", "WriteBytesPerSecond") +| summarize + AvgValue = avg(Val), + P95Value = percentile(Val, 95), + MaxValue = max(Val) + by Computer, Name +| order by Computer, Name +``` + +### Combined utilization summary + +```kusto +// Combined VM utilization summary for rightsizing analysis +let cpu = Perf +| where TimeGenerated > ago(14d) +| where ObjectName == "Processor" and CounterName == "% Processor Time" and InstanceName == "_Total" +| summarize CpuAvg = avg(CounterValue), CpuP95 = percentile(CounterValue, 95), CpuMax = max(CounterValue) by Computer; +let mem = InsightsMetrics +| where TimeGenerated > ago(14d) +| where Origin == "vm.azm.ms" and Namespace == "Memory" and Name == "AvailableMB" +| extend TotalMB = todouble(Tags["vm.azm.ms/memorySizeMB"]) +| extend UsedPercent = (TotalMB - Val) / TotalMB * 100 +| summarize MemAvg = avg(UsedPercent), MemP95 = percentile(UsedPercent, 95) by Computer; +cpu | join kind=leftouter mem on Computer +| project Computer, CpuAvg, CpuP95, CpuMax, MemAvg, MemP95 +| extend RightsizeCandidate = CpuP95 < 20 and (isnull(MemAvg) or MemAvg < 30) +| order by RightsizeCandidate desc, CpuP95 asc +``` + +--- + +## Step 3: Determine rightsizing thresholds + +| Metric | Threshold | Interpretation | +|--------|-----------|----------------| +| CPU P95 | < 20% | Strong downsize candidate | +| CPU P95 | 20–40% | Moderate candidate, verify burst patterns | +| CPU P95 | > 40% | Likely right-sized, skip | +| Memory avg | < 30% | Strong downsize candidate (if available) | +| Memory avg | 30–50% | Moderate candidate | +| Memory avg | > 50% | Likely right-sized for memory | + +**Note:** If memory metrics are unavailable (no VM Insights), rely on CPU only but be more conservative — use CPU P95 < 15% as the threshold to account for unknown memory pressure. + +**Agent compatibility note:** The `Perf` table is populated by the legacy Microsoft Monitoring Agent (MMA). Environments using the Azure Monitor Agent (AMA) should query CPU from `InsightsMetrics | where Namespace == 'Processor' and Name == 'UtilizationPercentage'` instead. + +--- + +## Step 4: Recommend target SKU + +### Get current VM specs via Resource Graph + +```kusto +resources +| where type == "microsoft.compute/virtualmachines" +| where name == "{vmName}" +| extend vmSize = tostring(properties.hardwareProfile.vmSize) +| extend location = location +| project name, vmSize, location, resourceGroup, subscriptionId +``` + +### Compare against target SKU pricing + +Use the Retail Prices API (see `references/azure-retail-prices.md`) to validate savings: + +```powershell +function Get-VmSkuPrice { + param([string]$Sku, [string]$Region) + $response = Invoke-RestMethod "https://prices.azure.com/api/retail/prices?`$filter=armSkuName eq '$Sku' and armRegionName eq '$Region' and priceType eq 'Consumption'" + return ($response.Items | Where-Object { $_.isPrimaryMeterRegion -and $_.type -eq 'Consumption' -and $_.meterName -notmatch 'Spot|Low Priority' } | Select-Object -First 1).retailPrice +} + +# Example: D4s_v5 -> D2s_v5 in eastus +$currentPrice = Get-VmSkuPrice -Sku "Standard_D4s_v5" -Region "eastus" +$targetPrice = Get-VmSkuPrice -Sku "Standard_D2s_v5" -Region "eastus" +$monthlySavings = ($currentPrice - $targetPrice) * 730 + +Write-Host "Current: Standard_D4s_v5 @ `$$currentPrice/hr" +Write-Host "Target: Standard_D2s_v5 @ `$$targetPrice/hr" +Write-Host "Monthly savings: `$$([math]::Round($monthlySavings, 2))" +Write-Host "Annual savings: `$$([math]::Round($monthlySavings * 12, 2))" +``` + +### Common downsize paths + +| Current Family | Typical Downsize | Notes | +|---------------|-----------------|-------| +| D-series (general purpose) | Halve vCPU count | D4s_v5 -> D2s_v5 | +| E-series (memory optimized) | Halve vCPU count | E8s_v5 -> E4s_v5 | +| F-series (compute optimized) | Halve vCPU count | F8s_v2 -> F4s_v2 | +| B-series (burstable) | Already burstable — verify CPU credits | Often right-sized | +| Cross-family | D-series -> B-series | For consistently low utilization | + +--- + +## Step 5: Safety checks + +### Burst requirements + +Check P99 CPU to ensure burst capacity is preserved: + +```kusto +Perf +| where TimeGenerated > ago(14d) +| where ObjectName == "Processor" and CounterName == "% Processor Time" and InstanceName == "_Total" +| where Computer == "{vmName}" +| summarize P99 = percentile(CounterValue, 99), Max = max(CounterValue) by Computer +``` + +If P99 > 80%, the VM has burst patterns that a smaller SKU may not handle. Consider B-series (burstable) instead of downsizing within the same family. + +### Instance size flexibility + +Azure Reservations support [instance size flexibility](https://learn.microsoft.com/azure/virtual-machines/reserved-vm-instance-size-flexibility) within a VM series. Downsizing within the same series (e.g., D4s_v5 -> D2s_v5) preserves reservation coverage with an adjusted ratio. + +Check if the VM is covered by a reservation: + +```kusto +advisorresources +| where type == "microsoft.advisor/recommendations" +| where properties.category == "Cost" +| where properties.recommendationTypeId == "e10b1381-5f0a-47ff-8c7b-37bd13d7c974" +| extend vmId = tostring(properties.resourceMetadata.resourceId) +| extend currentSku = tostring(properties.extendedProperties.currentSku) +| extend targetSku = tostring(properties.extendedProperties.targetSku) +| project vmId, currentSku, targetSku +``` + +If the VM is covered by a reservation and the downsize stays within the same series, the reservation automatically adjusts. Cross-series moves forfeit reservation coverage. + +### Azure Hybrid Benefit status + +Check if the VM uses Azure Hybrid Benefit (AHUB) for Windows or SQL licensing: + +```bash +az vm show --name {vmName} --resource-group {rg} \ + --query "{licenseType: licenseType, osType: storageProfile.osDisk.osType}" +``` + +| `licenseType` value | Meaning | +|--------------------|---------| +| `Windows_Server` | AHUB for Windows Server | +| `Windows_Client` | AHUB for Windows Client | +| `RHEL_BYOS` | BYOS for Red Hat | +| `SLES_BYOS` | BYOS for SUSE | +| `null` | No AHUB — paying full license cost | + +Ensure the target SKU preserves the same `licenseType` setting during resize. + +--- + +## Limitations + +| Limitation | Impact | Mitigation | +|-----------|--------|------------| +| Memory metrics require VM Insights | No memory data without agent | Deploy AMA agent, use CPU-only with conservative thresholds | +| Advisor uses 7-day window | May miss weekly patterns | Supplement with 14–30 day Azure Monitor analysis | +| No application-level metrics | CPU/memory don't capture app performance | Coordinate with app owners before resize | +| Resize requires VM restart | Brief downtime | Schedule during maintenance window | +| Cross-series resize loses reservation | Reservation coverage forfeited | Stay within same series when possible | + +--- + +## Permissions + +| Action | Required Role | +|--------|---------------| +| Query Advisor recommendations | Reader | +| Query Azure Monitor metrics | Monitoring Reader | +| Query Log Analytics workspace | Log Analytics Reader | +| Resize VM | Virtual Machine Contributor | +| Query Resource Graph | Reader | + +--- + +## References + +- [Right-size VMs (Azure Advisor)](https://learn.microsoft.com/azure/advisor/advisor-cost-recommendations#right-size-or-shutdown-underutilized-virtual-machines) +- [VM Insights overview](https://learn.microsoft.com/azure/azure-monitor/vm/vminsights-overview) +- [Instance size flexibility](https://learn.microsoft.com/azure/virtual-machines/reserved-vm-instance-size-flexibility) +- [Azure Monitor metrics](https://learn.microsoft.com/azure/azure-monitor/essentials/data-platform-metrics) +- [Azure Retail Prices API](https://learn.microsoft.com/rest/api/cost-management/retail-prices/azure-retail-prices) +- [Usage Optimization (FinOps Framework)](https://www.finops.org/framework/capabilities/usage-optimization/) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/README.md new file mode 100644 index 000000000..7ace98a82 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/README.md @@ -0,0 +1,103 @@ +# FinOps Toolkit skill + +KQL-based cost analysis and infrastructure deployment for [FinOps hubs](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/finops-hubs-overview). Provides a query catalog of 37 pre-built KQL queries, database schema documentation, hub deployment workflows, and a structured think-execute framework for financial analysis. + +## When this skill activates + +Triggered when you ask about: FinOps hubs, FinOps toolkit, KQL queries, Kusto, cost data analysis, Hub database, Costs function, Prices function, Recommendations function, FinOps hubs deployment, Azure Data Explorer, or ADX cluster. + +## Prerequisites + +- Azure CLI authenticated (`az login`) +- Azure MCP Server (provided by the plugin) +- AllDatabasesViewer access to a FinOps hubs ADX cluster +- Environment configured in `.ftk/environments.local.md` (use `/ftk-hubs-connect`) + +## Core rules + +1. Read the reference docs before writing any query +2. Verify schema before any query (check database guide) +3. Never guess column names or data +4. Show query before execution +5. Stop if confidence < 70% + +## Database functions + +The FinOps hubs database exposes four analytic functions: + +| Function | Purpose | Key columns | +|----------|---------|-------------| +| `Costs()` | Cost and usage analytics (FOCUS-aligned) | `BilledCost`, `EffectiveCost`, `ContractedCost`, `ListCost`, `ServiceName`, `ResourceName`, `Tags` | +| `Prices()` | Price sheets with list, contracted, and effective pricing | `ListUnitPrice`, `ContractedUnitPrice`, `x_EffectiveUnitPrice`, `PricingUnit` | +| `Recommendations()` | Reservation and savings plan recommendations | `x_EffectiveCostBefore`, `x_EffectiveCostAfter`, `x_EffectiveCostSavings` | +| `Transactions()` | Commitment purchases, refunds, and exchanges | `BilledCost`, `ChargeCategory`, `x_SkuTerm`, `x_TransactionType` | + +Columns prefixed with `x_` are toolkit enrichments added during ingestion (e.g., `x_ResourceGroupName`, `x_CommitmentDiscountSavings`, `x_TotalSavings`). + +## Query catalog + +37 pre-built KQL queries in `references/queries/catalog/`. Always check the catalog before writing custom KQL. + +| Query | Purpose | Parameters | +|-------|---------|------------| +| `costs-enriched-base.kql` | Full enrichment base for scoped custom drill-downs | `startDate`, `endDate` | +| `monthly-cost-trend.kql` | Billed and effective cost by month | `startDate`, `endDate` | +| `monthly-cost-change-percentage.kql` | Month-over-month cost change % | `startDate`, `endDate` | +| `top-services-by-cost.kql` | Top N services by cost | `N`, `startDate`, `endDate` | +| `top-resource-types-by-cost.kql` | Top N resource types by cost | `N`, `startDate`, `endDate` | +| `top-resource-groups-by-cost.kql` | Top N resource groups by cost | `N`, `startDate`, `endDate` | +| `quarterly-cost-by-resource-group.kql` | Resource group costs by quarter | `N`, `startDate`, `endDate` | +| `cost-by-region-trend.kql` | Effective cost by Azure region | `startDate`, `endDate` | +| `cost-by-financial-hierarchy.kql` | Cost by billing profile, team, product, app | `N`, `startDate`, `endDate` | +| `ai-cost-by-application.kql` | Azure OpenAI cost by application/team/environment | `startDate`, `endDate` | +| `ai-daily-trend.kql` | Daily Azure OpenAI cost and token trend | `startDate`, `endDate` | +| `ai-model-cost-comparison.kql` | Azure OpenAI model cost efficiency | `startDate`, `endDate` | +| `ai-token-usage-breakdown.kql` | Azure OpenAI tokens by model and direction | `startDate`, `endDate` | +| `cost-anomaly-detection.kql` | Statistical anomaly detection | `numberOfMonths`, `interval` | +| `cost-forecasting-model.kql` | Future cost projections | `forecastPeriods`, `interval` | +| `service-price-benchmarking.kql` | Price comparison across tiers | `startDate`, `endDate` | +| `commitment-discount-utilization.kql` | RI/SP utilization analysis | `startDate`, `endDate` | +| `savings-summary-report.kql` | Total savings and ESR KPI | `startDate`, `endDate` | +| `top-commitment-transactions.kql` | Top N RI/SP purchases | `N`, `startDate`, `endDate` | +| `top-other-transactions.kql` | Top N non-usage transactions | `N`, `startDate`, `endDate` | +| `reservation-recommendation-breakdown.kql` | Reservation recommendations with break-even | Filter by service/region | + +In this recipe, `references/queries/INDEX.md` is local source guidance; deployed SRE Agent instances receive executable query tools and Knowledge Sources, not skill additional files. + +## Hub deployment + +The skill covers FinOps hubs infrastructure deployment via Azure portal, PowerShell (`Deploy-FinOpsHub`), or Bicep modules. Architecture includes: + +- Storage Account (Data Lake Gen2) for data staging +- Azure Data Factory for ingestion pipelines +- Azure Data Explorer or Microsoft Fabric RTI for analytics +- Key Vault for managed identity credentials + +Estimated cost: ~$120/mo + $10/mo per $1M in monitored spend. + +See `references/finops-hubs-deployment.md` for deployment methods, scope configuration, backfill, Fabric setup, and dashboard/Power BI report setup. + +## Reference documentation + +| File | Contents | +|------|----------| +| `references/finops-hubs.md` | Analysis guide: KQL execution, query catalog protocol, tool matrix, performance rules, quality checklist | +| `references/finops-hubs-deployment.md` | Deployment: prerequisites, methods (portal/PowerShell/Bicep), exports, backfill, Fabric, dashboards | +| `references/settings-format.md` | `.ftk/environments.local.md` format: named environments with cluster-uri, tenant, subscription | +| `src/queries/INDEX.md` | Local canonical query-to-scenario matrix with parameters and usage guidance for all 37 pre-built KQL queries | +| `src/queries/finops-hub-database-guide.md` | Local canonical database schema: all four functions, column definitions, enrichment columns, query best practices | +| `references/workflows/ftk-hubs-connect.md` | Hub discovery via Resource Graph, connection validation, environment persistence | +| `references/workflows/ftk-hubs-healthCheck.md` | Version comparison against stable/dev releases, data freshness check | + +## Query execution + +```json +{ + "cluster-uri": "", + "database": "Hub", + "tenant": "", + "query": "" +} +``` + +Always use the "Hub" database (never "Ingestion"). Always include `tenant` for cross-tenant scenarios. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/SKILL.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/SKILL.md new file mode 100644 index 000000000..65fe3c6cf --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/SKILL.md @@ -0,0 +1,373 @@ +--- +name: finops-toolkit +description: This skill should be used when the user asks about "FinOps hubs", "FinOps toolkit", "KQL queries", "Kusto", "cost data analysis", "Hub database", "Costs function", "Prices function", "Recommendations function", "FinOps hubs deployment", "Azure Data Explorer", "ADX cluster", or any FinOps hubs operations. +license: MIT +compatibility: Requires Azure MCP Server and Azure CLI authentication. For queries, requires AllDatabasesViewer access to the FinOps hub ADX cluster. +metadata: + author: microsoft + version: "1.0" +--- + +# FinOps Toolkit + +FinOps hubs are a scalable platform for cloud cost analytics, insights, and optimization built on Azure Data Explorer (Kusto) or Microsoft Fabric RTI. This skill covers KQL-based cost analysis and hub infrastructure deployment. + +## Task routing + +Load only the references relevant to the task at hand. + +> **Maintainer note:** The references in this table intentionally use **shorthand skill paths** for readability. They are **not** a claim that the repo contains literal `toolkit/...`, `focus/...`, or bare `.kql` files next to `SKILL.md`. +> +> The packaging flow copies `src/templates/agent-skills/**` into `release/agent-skills` and zips that content **without rewriting paths** (see `src/scripts/Build-Toolkit.ps1` and `src/scripts/Package-Toolkit.ps1`). Resolve the shorthand in this table as follows: +> +> - `toolkit/...` → `references/docs-mslearn/toolkit/...` +> - `focus/...` → `references/docs-mslearn/focus/...` +> - bare `.kql` names → `references/queries/catalog/...` +> - `references/...` paths are already literal +> +> **Do not flag this table as a packaging bug again unless the packaging scripts change.** + +| Task | Load these references first | +|------|-----------------------------| +| Write or run a KQL query | `references/finops-hubs.md`, `references/queries/finops-hub-database-guide.md` | +| Use a pre-built query | Use the attached Kusto tool with the matching query name; use uploaded Knowledge Sources for schema and output-style guidance. | +| Deploy a new hub | `references/finops-hubs-deployment.md`, `toolkit/hubs/deploy.md`, `toolkit/hubs/template.md` | +| Upgrade a hub | `references/finops-hubs-deployment.md`, `toolkit/hubs/upgrade.md`, `toolkit/hubs/compatibility.md` | +| Savings / ESR analysis | `toolkit/hubs/savings-calculations.md`, `savings-summary-report.kql`, `commitment-discount-utilization.kql` | +| Reservation recommendations | `reservation-recommendation-breakdown.kql`, `toolkit/hubs/savings-calculations.md` | +| FOCUS columns / mapping | `focus/what-is-focus.md`, `focus/mapping.md` | +| Power BI setup | `toolkit/power-bi/setup.md`, `toolkit/power-bi/connector.md` | +| Troubleshooting / errors | `toolkit/help/troubleshooting.md`, `toolkit/help/errors.md` | +| PowerShell commands | `toolkit/powershell/powershell-commands.md` + the specific command file | +| Connect to hub for first time | `references/workflows/ftk-hubs-connect.md`, `references/settings-format.md` | +| Check hub health / version | `references/workflows/ftk-hubs-healthCheck.md`, `toolkit/hubs/compatibility.md` | + +## Database functions + +The Hub database exposes four analytic functions. Always use the `Hub` database — never `Ingestion`. + +| Function | Purpose | Key columns | +|----------|---------|-------------| +| `Costs()` | Cost and usage analytics (FOCUS-aligned) | `BilledCost`, `EffectiveCost`, `ContractedCost`, `ListCost`, `ServiceName`, `ResourceName`, `Tags` | +| `Prices()` | Price sheets with list, contracted, and effective pricing | `ListUnitPrice`, `ContractedUnitPrice`, `x_EffectiveUnitPrice`, `PricingUnit` | +| `Recommendations()` | Reservation and savings plan recommendations | `x_EffectiveCostBefore`, `x_EffectiveCostAfter`, `x_EffectiveCostSavings` | +| `Transactions()` | Commitment purchases, refunds, and exchanges | `BilledCost`, `ChargeCategory`, `x_SkuTerm`, `x_TransactionType` | + +Columns prefixed with `x_` are toolkit enrichments added during ingestion (e.g., `x_ResourceGroupName`, `x_CommitmentDiscountSavings`, `x_TotalSavings`). Full column definitions: `references/queries/finops-hub-database-guide.md`. + +## Query execution + +- Uses **KQL (Kusto)**, not SQL +- Default analysis window: 30 days +- Always include `tenant` — cross-tenant (B2B) scenarios fail without it + +Environment settings are read from `.ftk/environments.local.md` at the project root. Use the `default` environment unless the user specifies one. See `references/settings-format.md` for the file format. + +```json +{ + "cluster-uri": "", + "database": "Hub", + "tenant": "", + "query": "" +} +``` + +## Query catalog + +Use the attached Kusto tools before writing custom KQL. The tool names mirror the canonical `src/queries/catalog` query IDs. In deployed SRE Agent instances, skill reference files are build-time source material and are not sent as skill `additionalFiles`; rely on the attached tools and uploaded Knowledge Sources at runtime. + +| Query | Description | +|-------|-------------| +| [costs-enriched-base.kql](references/queries/catalog/costs-enriched-base.kql) | Base query with full enrichment and savings logic for all cost columns. Use for scoped row-level custom analytics or repeated drill-downs. | +| [monthly-cost-trend.kql](references/queries/catalog/monthly-cost-trend.kql) | Total billed and effective cost by month for trend analysis and executive reporting. | +| [monthly-cost-change-percentage.kql](references/queries/catalog/monthly-cost-change-percentage.kql) | Month-over-month cost change percentage for both billed and effective costs. | +| [top-services-by-cost.kql](references/queries/catalog/top-services-by-cost.kql) | Top N Azure services by cost. Key for cost visibility. | +| [top-resource-types-by-cost.kql](references/queries/catalog/top-resource-types-by-cost.kql) | Top N resource types by cost and usage. | +| [top-resource-groups-by-cost.kql](references/queries/catalog/top-resource-groups-by-cost.kql) | Top N resource groups by effective cost. | +| [quarterly-cost-by-resource-group.kql](references/queries/catalog/quarterly-cost-by-resource-group.kql) | Effective cost by resource group for quarterly or multi-month reporting. | +| [cost-by-region-trend.kql](references/queries/catalog/cost-by-region-trend.kql) | Effective cost by Azure region for regional cost driver analysis. | +| [cost-by-financial-hierarchy.kql](references/queries/catalog/cost-by-financial-hierarchy.kql) | Cost allocation by billing profile, invoice section, team, product, and app for showback/chargeback. | +| [ai-cost-by-application.kql](references/queries/catalog/ai-cost-by-application.kql) | Azure OpenAI costs by application, cost center, team, and environment tags. | +| [ai-daily-trend.kql](references/queries/catalog/ai-daily-trend.kql) | Daily Azure OpenAI token and effective cost trend. | +| [ai-model-cost-comparison.kql](references/queries/catalog/ai-model-cost-comparison.kql) | Azure OpenAI model cost efficiency and discount comparison. | +| [ai-token-usage-breakdown.kql](references/queries/catalog/ai-token-usage-breakdown.kql) | Azure OpenAI token consumption and cost by model and direction. | +| [cost-anomaly-detection.kql](references/queries/catalog/cost-anomaly-detection.kql) | Detect unusual cost spikes or drops using statistical anomaly detection. | +| [anomaly-detection-rate.kql](references/queries/catalog/anomaly-detection-rate.kql) | Measure the share of effective spend on anomaly-flagged daily buckets. | +| [anomaly-variance-total.kql](references/queries/catalog/anomaly-variance-total.kql) | Quantify unpredicted spend variance for anomaly events. | +| [cost-forecasting-model.kql](references/queries/catalog/cost-forecasting-model.kql) | Project future costs for budgeting and planning with configurable forecast horizon. | +| [service-price-benchmarking.kql](references/queries/catalog/service-price-benchmarking.kql) | Compare list, contracted, effective, negotiated, and commitment prices by service. | +| [commitment-discount-utilization.kql](references/queries/catalog/commitment-discount-utilization.kql) | Reservation and savings plan utilization analysis for rate optimization. | +| [commitment-utilization-score.kql](references/queries/catalog/commitment-utilization-score.kql) | Commitment utilization amount, potential, and score by commitment and currency. | +| [commitment-discount-waste.kql](references/queries/catalog/commitment-discount-waste.kql) | Unused commitment value as a share of total commitment cost. | +| [compute-spend-commitment-coverage.kql](references/queries/catalog/compute-spend-commitment-coverage.kql) | Share of compute spend covered by commitment discounts. | +| [cost-optimization-index.kql](references/queries/catalog/cost-optimization-index.kql) | Hub-wide Cost Optimization Index from current recommendations and windowed cost. | +| [macc-consumption-vs-commitment.kql](references/queries/catalog/macc-consumption-vs-commitment.kql) | MACC consumption versus commitment drawdown by billing profile and month. | +| [savings-summary-report.kql](references/queries/catalog/savings-summary-report.kql) | Total realized savings and Effective Savings Rate KPI. | +| [top-commitment-transactions.kql](references/queries/catalog/top-commitment-transactions.kql) | Top N reservation or savings plan purchases by cost impact. | +| [top-other-transactions.kql](references/queries/catalog/top-other-transactions.kql) | Top N non-commitment, non-usage transactions. | +| [reservation-recommendation-breakdown.kql](references/queries/catalog/reservation-recommendation-breakdown.kql) | Microsoft reservation recommendations with projected savings and break-even analysis. | +| [allocation-accuracy-index.kql](references/queries/catalog/allocation-accuracy-index.kql) | Directly attributed cost as a share of total effective cost. | +| [percentage-unallocated-costs.kql](references/queries/catalog/percentage-unallocated-costs.kql) | Share of effective cost without allocation evidence. | +| [percentage-untagged-costs.kql](references/queries/catalog/percentage-untagged-costs.kql) | Share of effective cost associated with resources that have no tags. | +| [tagging-policy-compliance.kql](references/queries/catalog/tagging-policy-compliance.kql) | Cost-weighted compliance with required tag keys. | +| [compute-cost-per-core.kql](references/queries/catalog/compute-cost-per-core.kql) | Hourly and effective average compute cost per consumed vCPU core hour. | +| [cost-per-gb-stored.kql](references/queries/catalog/cost-per-gb-stored.kql) | Storage cost per normalized GB-month. | +| [storage-tier-distribution.kql](references/queries/catalog/storage-tier-distribution.kql) | Storage cost and GB-month distribution by access-tier bucket. | +| [cost-visibility-delay.kql](references/queries/catalog/cost-visibility-delay.kql) | Cost data visibility delay from charge period end to Hub ingestion. | +| [data-update-frequency.kql](references/queries/catalog/data-update-frequency.kql) | Hub ingestion update cadence from distinct ingestion timestamps. | + +## Infrastructure deployment + +Deployment targets: Azure Data Explorer clusters, Microsoft Fabric workspaces, Cost Management exports, Power BI dashboards. + +Key commands: `az deployment`, `az kusto`, `az storage`. PowerShell: `Deploy-FinOpsHub`. + +Estimated cost: ~$120/mo + $10/mo per $1M in monitored spend. + +For detailed documentation: `references/finops-hubs-deployment.md` + +## Reference files + +| File | Description | +|------|-------------| +| [references/finops-hubs.md](references/finops-hubs.md) | Analysis guide: KQL execution, query catalog protocol, tool matrix, performance rules. **Read before any cost query.** | +| [references/finops-hubs-deployment.md](references/finops-hubs-deployment.md) | Deployment and configuration: ADX clusters, Fabric, Data Factory, exports, Key Vault, Power BI dashboards. | +| [references/settings-format.md](references/settings-format.md) | Format specification for `.ftk/environments.local.md` — named environments with cluster-uri, tenant, subscription, and resource-group. | +| `src/queries/INDEX.md` | Build-time canonical query catalog with scenario-to-query matrix, parameter docs, and usage guidance for all 37 pre-built KQL queries. The deployed SRE Agent receives executable tools rather than these files as skill attachments. | +| `src/queries/finops-hub-database-guide.md` | Build-time canonical Hub database schema reference. Runtime schema guidance should come from uploaded Knowledge Sources and attached query tools. | +| [references/workflows/ftk-hubs-connect.md](references/workflows/ftk-hubs-connect.md) | Workflow to discover FinOps hub instances via Resource Graph, connect, and save environment config. | +| [references/workflows/ftk-hubs-healthCheck.md](references/workflows/ftk-hubs-healthCheck.md) | Health check workflow: version comparison against stable/dev releases, upgrade guidance, and diagnostic steps. | + +## Microsoft Learn documentation + +Official Microsoft documentation for FinOps and the FinOps toolkit. Source: [learn.microsoft.com](https://learn.microsoft.com/cloud-computing/finops/). + +### FinOps overview + +| File | Description | +|------|-------------| +| [overview.md](references/docs-mslearn/overview.md) | Microsoft Cloud FinOps overview | +| [implementing-finops-guide.md](references/docs-mslearn/implementing-finops-guide.md) | Guide to implementing FinOps in Azure | +| [conduct-iteration.md](references/docs-mslearn/conduct-iteration.md) | Conducting a FinOps iteration | + +### FinOps Framework + +| File | Description | +|------|-------------| +| [finops-framework.md](references/docs-mslearn/framework/finops-framework.md) | FinOps Framework overview | +| [capabilities.md](references/docs-mslearn/framework/capabilities.md) | FinOps capabilities reference | + +#### Understand Usage & Cost + +| File | Description | +|------|-------------| +| [understand-cloud-usage-cost.md](references/docs-mslearn/framework/understand/understand-cloud-usage-cost.md) | Understand pillar overview | +| [ingestion.md](references/docs-mslearn/framework/understand/ingestion.md) | Data ingestion | +| [allocation.md](references/docs-mslearn/framework/understand/allocation.md) | Cost allocation | +| [reporting.md](references/docs-mslearn/framework/understand/reporting.md) | Reporting and analytics | +| [anomalies.md](references/docs-mslearn/framework/understand/anomalies.md) | Anomaly management | + +#### Quantify business value + +| File | Description | +|------|-------------| +| [quantify-business-value.md](references/docs-mslearn/framework/quantify/quantify-business-value.md) | Quantify pillar overview | +| [planning.md](references/docs-mslearn/framework/quantify/planning.md) | Planning and estimating | +| [budgeting.md](references/docs-mslearn/framework/quantify/budgeting.md) | Budgeting | +| [forecasting.md](references/docs-mslearn/framework/quantify/forecasting.md) | Forecasting | +| [benchmarking.md](references/docs-mslearn/framework/quantify/benchmarking.md) | Benchmarking | +| [unit-economics.md](references/docs-mslearn/framework/quantify/unit-economics.md) | Unit economics | + +#### Optimize cloud usage and cost + +| File | Description | +|------|-------------| +| [optimize-cloud-usage-cost.md](references/docs-mslearn/framework/optimize/optimize-cloud-usage-cost.md) | Optimize pillar overview | +| [architecting.md](references/docs-mslearn/framework/optimize/architecting.md) | Architecting for cloud | +| [workloads.md](references/docs-mslearn/framework/optimize/workloads.md) | Usage optimization | +| [rates.md](references/docs-mslearn/framework/optimize/rates.md) | Rate optimization | +| [licensing.md](references/docs-mslearn/framework/optimize/licensing.md) | Licensing and SaaS | +| [sustainability.md](references/docs-mslearn/framework/optimize/sustainability.md) | Cloud sustainability | + +#### Manage the FinOps practice + +| File | Description | +|------|-------------| +| [manage-finops.md](references/docs-mslearn/framework/manage/manage-finops.md) | Manage pillar overview | +| [onboarding.md](references/docs-mslearn/framework/manage/onboarding.md) | FinOps onboarding | +| [education.md](references/docs-mslearn/framework/manage/education.md) | FinOps education and enablement | +| [operations.md](references/docs-mslearn/framework/manage/operations.md) | FinOps operations | +| [governance.md](references/docs-mslearn/framework/manage/governance.md) | FinOps and governance | +| [assessment.md](references/docs-mslearn/framework/manage/assessment.md) | FinOps assessment | +| [invoicing-chargeback.md](references/docs-mslearn/framework/manage/invoicing-chargeback.md) | Invoicing and chargeback | +| [tools-services.md](references/docs-mslearn/framework/manage/tools-services.md) | Tools and services | +| [intersecting-disciplines.md](references/docs-mslearn/framework/manage/intersecting-disciplines.md) | Intersecting disciplines | + +### FOCUS + +| File | Description | +|------|-------------| +| [what-is-focus.md](references/docs-mslearn/focus/what-is-focus.md) | What is FOCUS (FinOps Open Cost and Usage Specification) | +| [mapping.md](references/docs-mslearn/focus/mapping.md) | FOCUS column mapping | +| [metadata.md](references/docs-mslearn/focus/metadata.md) | FOCUS metadata | +| [convert.md](references/docs-mslearn/focus/convert.md) | Converting data to FOCUS | +| [validate.md](references/docs-mslearn/focus/validate.md) | Validating FOCUS data | +| [conformance-summary.md](references/docs-mslearn/focus/conformance-summary.md) | FOCUS conformance summary | +| [conformance-full-report.md](references/docs-mslearn/focus/conformance-full-report.md) | FOCUS conformance full report | + +### Cost optimization best practices + +| File | Description | +|------|-------------| +| [general.md](references/docs-mslearn/best-practices/general.md) | General cost optimization best practices | +| [compute.md](references/docs-mslearn/best-practices/compute.md) | Compute cost optimization | +| [databases.md](references/docs-mslearn/best-practices/databases.md) | Database cost optimization | +| [networking.md](references/docs-mslearn/best-practices/networking.md) | Networking cost optimization | +| [storage.md](references/docs-mslearn/best-practices/storage.md) | Storage cost optimization | +| [web.md](references/docs-mslearn/best-practices/web.md) | Web and app service cost optimization | +| [library.md](references/docs-mslearn/best-practices/library.md) | Best practices library | + +### FinOps toolkit + +| File | Description | +|------|-------------| +| [finops-toolkit-overview.md](references/docs-mslearn/toolkit/finops-toolkit-overview.md) | FinOps toolkit overview | +| [changelog.md](references/docs-mslearn/toolkit/changelog.md) | Toolkit changelog | +| [roadmap.md](references/docs-mslearn/toolkit/roadmap.md) | Toolkit roadmap | +| [open-data.md](references/docs-mslearn/toolkit/open-data.md) | Open data (pricing units, regions, services, resource types) | +| [data-lake-storage-connectivity.md](references/docs-mslearn/toolkit/data-lake-storage-connectivity.md) | Data lake storage connectivity | + +### FinOps hubs + +| File | Description | +|------|-------------| +| [finops-hubs-overview.md](references/docs-mslearn/toolkit/hubs/finops-hubs-overview.md) | FinOps hubs overview | +| [deploy.md](references/docs-mslearn/toolkit/hubs/deploy.md) | Deploy FinOps hubs | +| [upgrade.md](references/docs-mslearn/toolkit/hubs/upgrade.md) | Upgrade FinOps hubs | +| [template.md](references/docs-mslearn/toolkit/hubs/template.md) | Hub Bicep template reference | +| [data-model.md](references/docs-mslearn/toolkit/hubs/data-model.md) | Hub database data model. **Read for authoritative schema reference.** | +| [data-processing.md](references/docs-mslearn/toolkit/hubs/data-processing.md) | Data processing pipeline | +| [savings-calculations.md](references/docs-mslearn/toolkit/hubs/savings-calculations.md) | Savings calculations methodology | +| [compatibility.md](references/docs-mslearn/toolkit/hubs/compatibility.md) | Version compatibility matrix | +| [configure-scopes.md](references/docs-mslearn/toolkit/hubs/configure-scopes.md) | Configure cost export scopes | +| [configure-dashboards.md](references/docs-mslearn/toolkit/hubs/configure-dashboards.md) | Configure dashboards | +| [configure-remote-hubs.md](references/docs-mslearn/toolkit/hubs/configure-remote-hubs.md) | Configure remote hubs | +| [configure-ai.md](references/docs-mslearn/toolkit/hubs/configure-ai.md) | Configure AI copilot for FinOps hubs | +| [private-networking.md](references/docs-mslearn/toolkit/hubs/private-networking.md) | Private networking configuration | + +### Alerts + +| File | Description | +|------|-------------| +| [finops-alerts-overview.md](references/docs-mslearn/toolkit/alerts/finops-alerts-overview.md) | FinOps alerts overview | +| [configure-finops-alerts.md](references/docs-mslearn/toolkit/alerts/configure-finops-alerts.md) | Configure FinOps alerts | + +### Bicep registry + +| File | Description | +|------|-------------| +| [modules.md](references/docs-mslearn/toolkit/bicep-registry/modules.md) | Bicep registry modules | +| [scheduled-actions.md](references/docs-mslearn/toolkit/bicep-registry/scheduled-actions.md) | Scheduled actions module | + +### Optimization engine + +| File | Description | +|------|-------------| +| [overview.md](references/docs-mslearn/toolkit/optimization-engine/overview.md) | Optimization engine overview | +| [setup-options.md](references/docs-mslearn/toolkit/optimization-engine/setup-options.md) | Setup options | +| [configure-workspaces.md](references/docs-mslearn/toolkit/optimization-engine/configure-workspaces.md) | Configure workspaces | +| [customize.md](references/docs-mslearn/toolkit/optimization-engine/customize.md) | Customize the optimization engine | +| [reports.md](references/docs-mslearn/toolkit/optimization-engine/reports.md) | Optimization reports | +| [suppress-recommendations.md](references/docs-mslearn/toolkit/optimization-engine/suppress-recommendations.md) | Suppress recommendations | +| [troubleshooting.md](references/docs-mslearn/toolkit/optimization-engine/troubleshooting.md) | Troubleshooting | +| [faq.md](references/docs-mslearn/toolkit/optimization-engine/faq.md) | Frequently asked questions | + +### Power BI + +| File | Description | +|------|-------------| +| [reports.md](references/docs-mslearn/toolkit/power-bi/reports.md) | Power BI reports overview | +| [setup.md](references/docs-mslearn/toolkit/power-bi/setup.md) | Power BI setup | +| [connector.md](references/docs-mslearn/toolkit/power-bi/connector.md) | FinOps toolkit Power BI connector | +| [template-app.md](references/docs-mslearn/toolkit/power-bi/template-app.md) | Power BI template app | +| [help-me-choose.md](references/docs-mslearn/toolkit/power-bi/help-me-choose.md) | Help me choose a Power BI report | +| [cost-summary.md](references/docs-mslearn/toolkit/power-bi/cost-summary.md) | Cost summary report | +| [rate-optimization.md](references/docs-mslearn/toolkit/power-bi/rate-optimization.md) | Rate optimization report | +| [workload-optimization.md](references/docs-mslearn/toolkit/power-bi/workload-optimization.md) | Usage optimization report | +| [governance.md](references/docs-mslearn/toolkit/power-bi/governance.md) | Governance report | +| [data-ingestion.md](references/docs-mslearn/toolkit/power-bi/data-ingestion.md) | Data ingestion report | +| [invoicing.md](references/docs-mslearn/toolkit/power-bi/invoicing.md) | Invoicing report | + +### Workbooks + +| File | Description | +|------|-------------| +| [finops-workbooks-overview.md](references/docs-mslearn/toolkit/workbooks/finops-workbooks-overview.md) | FinOps workbooks overview | +| [customize-workbooks.md](references/docs-mslearn/toolkit/workbooks/customize-workbooks.md) | Customize workbooks | +| [optimization.md](references/docs-mslearn/toolkit/workbooks/optimization.md) | Optimization workbook | +| [governance.md](references/docs-mslearn/toolkit/workbooks/governance.md) | Governance workbook | + +### Fabric + +| File | Description | +|------|-------------| +| [create-fabric-workspace-finops.md](references/docs-mslearn/fabric/create-fabric-workspace-finops.md) | Create a Fabric workspace for FinOps | + +### PowerShell commands + +| File | Description | +|------|-------------| +| [powershell-commands.md](references/docs-mslearn/toolkit/powershell/powershell-commands.md) | PowerShell commands overview | + +#### Cost Management commands + +| File | Description | +|------|-------------| +| [cost-management-commands.md](references/docs-mslearn/toolkit/powershell/cost/cost-management-commands.md) | Cost Management commands overview | +| [get-finopscostexport.md](references/docs-mslearn/toolkit/powershell/cost/get-finopscostexport.md) | Get-FinOpsCostExport | +| [new-finopscostexport.md](references/docs-mslearn/toolkit/powershell/cost/new-finopscostexport.md) | New-FinOpsCostExport | +| [start-finopscostexport.md](references/docs-mslearn/toolkit/powershell/cost/start-finopscostexport.md) | Start-FinOpsCostExport | +| [remove-finopscostexport.md](references/docs-mslearn/toolkit/powershell/cost/remove-finopscostexport.md) | Remove-FinOpsCostExport | +| [add-finopsserviceprincipal.md](references/docs-mslearn/toolkit/powershell/cost/add-finopsserviceprincipal.md) | Add-FinOpsServicePrincipal | + +#### Open data commands + +| File | Description | +|------|-------------| +| [open-data-commands.md](references/docs-mslearn/toolkit/powershell/data/open-data-commands.md) | Open data commands overview | +| [get-finopspricingunit.md](references/docs-mslearn/toolkit/powershell/data/get-finopspricingunit.md) | Get-FinOpsPricingUnit | +| [get-finopsregion.md](references/docs-mslearn/toolkit/powershell/data/get-finopsregion.md) | Get-FinOpsRegion | +| [get-finopsresourcetype.md](references/docs-mslearn/toolkit/powershell/data/get-finopsresourcetype.md) | Get-FinOpsResourceType | +| [get-finopsservice.md](references/docs-mslearn/toolkit/powershell/data/get-finopsservice.md) | Get-FinOpsService | + +#### FinOps hubs commands + +| File | Description | +|------|-------------| +| [finops-hubs-commands.md](references/docs-mslearn/toolkit/powershell/hubs/finops-hubs-commands.md) | FinOps hubs commands overview | +| [deploy-finopshub.md](references/docs-mslearn/toolkit/powershell/hubs/deploy-finopshub.md) | Deploy-FinOpsHub | +| [get-finopshub.md](references/docs-mslearn/toolkit/powershell/hubs/get-finopshub.md) | Get-FinOpsHub | +| [initialize-finopshubdeployment.md](references/docs-mslearn/toolkit/powershell/hubs/initialize-finopshubdeployment.md) | Initialize-FinOpsHubDeployment | +| [register-finopshubproviders.md](references/docs-mslearn/toolkit/powershell/hubs/register-finopshubproviders.md) | Register-FinOpsHubProviders | +| [remove-finopshub.md](references/docs-mslearn/toolkit/powershell/hubs/remove-finopshub.md) | Remove-FinOpsHub | +| [remove-finopshubscope.md](references/docs-mslearn/toolkit/powershell/hubs/remove-finopshubscope.md) | Remove-FinOpsHubScope | + +#### Toolkit commands + +| File | Description | +|------|-------------| +| [finops-toolkit-commands.md](references/docs-mslearn/toolkit/powershell/toolkit/finops-toolkit-commands.md) | Toolkit commands overview | +| [get-finopstoolkitversion.md](references/docs-mslearn/toolkit/powershell/toolkit/get-finopstoolkitversion.md) | Get-FinOpsToolkitVersion | + +### Help and support + +| File | Description | +|------|-------------| +| [help-options.md](references/docs-mslearn/toolkit/help/help-options.md) | Help options | +| [support.md](references/docs-mslearn/toolkit/help/support.md) | Support | +| [troubleshooting.md](references/docs-mslearn/toolkit/help/troubleshooting.md) | Troubleshooting | +| [errors.md](references/docs-mslearn/toolkit/help/errors.md) | Error reference | +| [deploy.md](references/docs-mslearn/toolkit/help/deploy.md) | Deployment help | +| [data-dictionary.md](references/docs-mslearn/toolkit/help/data-dictionary.md) | Data dictionary | +| [terms.md](references/docs-mslearn/toolkit/help/terms.md) | Terms and definitions | +| [contributors.md](references/docs-mslearn/toolkit/help/contributors.md) | Contributors | diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-anomaly-detection.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-anomaly-detection.md new file mode 100644 index 000000000..7d54e7d7a --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-anomaly-detection.md @@ -0,0 +1,171 @@ +--- +name: cost-anomaly-detection +description: Detects unusual cost changes in FinOps hubs by establishing baseline spend, surfacing anomalies, and identifying the services, subscriptions, regions, resource groups, resources, or usage types driving the deviation +author: FinOps Toolkit Team +version: 1.0.0 +license: Apache-2.0 +--- + +# Cost anomaly detection + +## Purpose +Use this reference to detect unusual cost behavior in a FinOps hub, determine whether a cost change is a short-lived spike or a sustained baseline shift, and identify the drivers that require investigation. + +## When to use +- “Are there any cost anomalies?” +- “What changed unexpectedly in the last few days or weeks?” +- “Did we have an unusual spike or drop?” +- “Which service, subscription, or resource group caused the anomaly?” +- Weekly operational review, budget alert triage, or incident follow-up + +## Grounding +Use these canonical assets first: +- `cost-anomaly-detection.kql` +- `monthly-cost-change-percentage.kql` +- `Costs()` + +Use the FinOps hub database guide and query catalog as the authoritative source for valid columns and query patterns. + +## How this skill works + +### Step 1: Define the anomaly window +- Default to the last 30 to 90 days for recent anomaly checks. +- Use a longer lookback if you need to distinguish a one-time event from seasonality or a new normal. +- Keep the investigation window explicit so baseline and anomaly periods are comparable. + +### Step 2: Start with the catalog query +Use `cost-anomaly-detection.kql` first to surface unusual movement in total daily cost. + +Questions to answer: +- Which dates are flagged as anomalous? +- Are anomalies positive spikes, negative drops, or repeated oscillations? +- Does the pattern look isolated or sustained? + +### Step 3: Quantify recent change +Use `monthly-cost-change-percentage.kql` when you need to explain whether the anomaly also appears in month-over-month movement. + +This is especially helpful when: +- the anomaly appears near a month boundary +- stakeholders want a simple percentage summary +- you need to distinguish a daily outlier from a broader monthly shift + +### Step 4: Decompose the anomaly with `Costs()` +Use `Costs()` to identify which dimensions explain the anomaly. + +Common fields to test: +- `ServiceName` +- `SubAccountName` +- `RegionName` +- `x_ResourceGroupName` +- `ResourceName` +- `ResourceType` +- `x_UsageType` + +#### Example: daily service anomaly breakdown +```kusto +let startDate = ago(30d); +let endDate = now(); +Costs() +| where ChargePeriodStart between (startDate .. endDate) +| summarize EffectiveCost = sum(EffectiveCost) by Day = startofday(ChargePeriodStart), ServiceName +| order by Day asc, EffectiveCost desc +``` + +#### Example: subscription anomaly breakdown +```kusto +let startDate = ago(30d); +let endDate = now(); +Costs() +| where ChargePeriodStart between (startDate .. endDate) +| summarize EffectiveCost = sum(EffectiveCost) by Day = startofday(ChargePeriodStart), SubAccountName +| order by Day asc, EffectiveCost desc +``` + +#### Example: resource group and resource investigation +```kusto +let startDate = ago(14d); +let endDate = now(); +Costs() +| where ChargePeriodStart between (startDate .. endDate) +| summarize EffectiveCost = sum(EffectiveCost) by Day = startofday(ChargePeriodStart), x_ResourceGroupName, ResourceName, ResourceType +| order by Day asc, EffectiveCost desc +``` + +Use the same pattern to isolate whether the anomaly is concentrated in `RegionName` or `x_UsageType`. + +### Step 5: Classify the anomaly pattern +After reviewing `cost-anomaly-detection.kql` and targeted `Costs()` breakdowns, classify the result: +- **Spike:** abrupt increase followed by reversion +- **Drop:** abrupt decrease followed by reversion +- **Step change:** abrupt increase or decrease that persists +- **Drift:** gradual movement away from prior baseline +- **Concentrated anomaly:** mostly explained by one `ServiceName`, `SubAccountName`, or `x_ResourceGroupName` +- **Broad anomaly:** spread across multiple dimensions + +### Step 6: Name the primary driver +State the primary driver explicitly: +- top `ServiceName` contributor +- top `SubAccountName` contributor +- top `RegionName` contributor +- top `x_ResourceGroupName` contributor +- top `ResourceName` or `ResourceType` contributor when the anomaly is workload-specific + +### Step 7: Determine likely meaning +Interpret the anomaly before recommending action: +- **Expected business event:** planned launch, migration, scale-out, or month-end processing +- **Operational issue:** runaway workload, misconfiguration, or failed cleanup +- **Data-quality concern:** unexpected drop or gap that may indicate ingest delay or incomplete data +- **Optimization opportunity:** sustained increase tied to inefficient resource or usage patterns + +## Output format + +### 1. Executive summary +- Anomaly detected: yes or no +- Most significant anomaly date or period +- Estimated impact in cost and percentage terms +- Primary driver by `ServiceName`, `SubAccountName`, `RegionName`, `x_ResourceGroupName`, `ResourceName`, or `ResourceType` +- One-sentence conclusion + +### 2. Anomaly details +- Detection window analyzed +- Baseline behavior described in plain language +- Observed anomaly pattern: spike, drop, step change, or drift +- Magnitude of deviation from normal +- Whether the anomaly appears isolated or ongoing + +### 3. Driver breakdown + +| Dimension | Top value | Why it matters | +| --- | --- | --- | +| ServiceName | [value] | Largest service contributor | +| SubAccountName | [value] | Largest subscription contributor | +| RegionName | [value] | Regional concentration | +| x_ResourceGroupName | [value] | Workload grouping most affected | +| ResourceType | [value] | Resource class driving change | + +### 4. Interpretation +- What changed first? +- What dimension explains the largest share of the anomaly? +- Does the anomaly indicate a one-time event or a baseline reset? +- Does the pattern require immediate action, monitoring, or routine follow-up? + +### 5. Recommended next step +- Investigate the largest driver when change is concentrated +- Review workload or deployment events around the anomaly date +- Compare against monthly movement if leadership wants trend context +- Continue monitoring if the anomaly is understood and expected + +## Best practices +1. Start with `cost-anomaly-detection.kql` before writing custom anomaly logic. +2. Use `Costs()` to explain the anomaly, not just to confirm it exists. +3. Break down anomalies by `ServiceName`, `SubAccountName`, `RegionName`, and `x_ResourceGroupName` before jumping to conclusions. +4. Use `ResourceName`, `ResourceType`, and `x_UsageType` when the anomaly appears concentrated in a narrow workload slice. +5. Use `monthly-cost-change-percentage.kql` when stakeholders need month-over-month context. +6. Distinguish a short spike from a sustained step change. +7. Treat large negative anomalies as possible data or ingestion issues until validated. + +## See also +- `queries/INDEX.md` +- `queries/finops-hub-database-guide.md` +- `cost-anomaly-detection.kql` +- `monthly-cost-change-percentage.kql` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-comparison.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-comparison.md new file mode 100644 index 000000000..dce63261b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-comparison.md @@ -0,0 +1,293 @@ +--- +name: cost-comparison +description: Compares FinOps hubs cost across time periods, subscriptions, regions, resource groups, billing hierarchy, and optional tags to explain spending differences and benchmark efficiency +author: FinOps Toolkit Team +version: 1.0.0 +license: Apache-2.0 +--- + +# Cost comparison + +## Purpose +Use FinOps hubs data to compare cost across two or more periods or groups, quantify the size of the difference, and explain which services, subscriptions, regions, resource groups, or billing-hierarchy nodes account for the change. + +## When to use +- "Compare costs between period A and period B" +- "Show me month-over-month changes" +- "Which subscription, region, or service is more expensive?" +- "Compare production and non-production costs" +- "Benchmark billing profiles, invoice sections, or resource groups" +- Keywords: compare, comparison, versus, vs, difference, benchmark, relative, month-over-month + +## Prerequisites +- Confirm the hub connection, reporting window, and any required filters. +- Use `references/queries/finops-hub-database-guide.md` to verify available FinOps hubs fields and enrichment columns. +- Use `references/queries/INDEX.md` to select the closest starting query. +- Prefer scenario-specific aggregate queries first. Use `costs-enriched-base.kql` only for scoped row-level drill-downs after aggregate queries do not answer the question. + +## Recommended comparison dimensions +Choose the first grouping that best matches the question: + +- `ServiceName` for side-by-side service comparison across periods or groups +- `SubAccountName` for subscription or sub-account comparison +- `RegionName` for regional comparison +- `x_ResourceGroupName` for resource-group comparison +- `x_BillingProfileName` and `x_InvoiceSectionName` for billing-hierarchy comparison + +Tag-based grouping is optional. If your organization uses tags and coverage is good enough, compare `Tags['team']`, `Tags['product']`, `Tags['application']`, or `Tags['environment']`. + +If tags are missing, blank, or tag coverage is incomplete, fall back to `ServiceName`, `SubAccountName`, `RegionName`, `x_ResourceGroupName`, `x_BillingProfileName`, or `x_InvoiceSectionName` instead. + +Treat blank tag values as incomplete metadata, not as a reliable business grouping. + +## Recommended query assets +- `monthly-cost-change-percentage.kql` for month-over-month change analysis +- `cost-by-region-trend.kql` for region-led comparisons and trend context +- `cost-by-financial-hierarchy.kql` for billing profile and invoice section comparisons +- `costs-enriched-base.kql` only for scoped row-level drill-downs when the aggregate catalog queries do not provide enough detail + +## Analysis workflow + +### Step 1: Identify the comparison type +Confirm whether the request is: + +- period versus period +- month-over-month +- before versus after an optimization or migration +- subscription versus subscription +- region versus region +- resource group versus resource group +- billing profile or invoice section versus peers + +Also confirm whether the user wants a technical comparison, a finance or allocation comparison, or both. + +### Step 2: Choose the strongest base dimension +Start with one high-signal non-tag dimension before adding more detail: + +- `ServiceName` when comparing what changed across equal time windows +- `SubAccountName` when comparing subscriptions or business-owned scopes +- `RegionName` when testing whether geography explains the difference +- `x_ResourceGroupName` when operational ownership matters most +- `x_BillingProfileName` and `x_InvoiceSectionName` when the comparison is for showback or chargeback + +### Step 3: Build comparable datasets + +**Side-by-side period comparison by service** + +This pattern works well for comparing equal windows by `ServiceName`. + +```kusto +let currentStart = datetime(2024-02-01); +let currentEnd = datetime(2024-03-01); +let previousStart = datetime(2024-01-01); +let previousEnd = datetime(2024-02-01); +union +( + Costs() + | where ChargePeriodStart >= currentStart and ChargePeriodStart < currentEnd + | summarize EffectiveCost = sum(EffectiveCost) by ServiceName + | extend ComparisonGroup = 'Current period' +), +( + Costs() + | where ChargePeriodStart >= previousStart and ChargePeriodStart < previousEnd + | summarize EffectiveCost = sum(EffectiveCost) by ServiceName + | extend ComparisonGroup = 'Previous period' +) +| order by ServiceName asc, ComparisonGroup asc +``` + +**Month-over-month comparison** + +Start with `monthly-cost-change-percentage.kql` to quantify the overall shift, then drill into the main driver dimension. + +```kusto +let startDate = startofmonth(ago(90d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by Month = startofmonth(ChargePeriodStart), ServiceName +| order by Month asc, EffectiveCost desc +``` + +**Region comparison** + +Use `cost-by-region-trend.kql` when the question is whether `RegionName` explains cost variance. + +```kusto +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by RegionName, ServiceName +| order by RegionName asc, EffectiveCost desc +``` + +**Billing-hierarchy comparison** + +Use `cost-by-financial-hierarchy.kql` when the baseline needs to follow finance ownership. + +```kusto +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) + by x_BillingProfileName, x_InvoiceSectionName, SubAccountName +| order by EffectiveCost desc +``` + +### Step 4: Calculate comparison metrics +For each comparable row, calculate: + +- **Absolute difference:** `Difference = CostA - CostB` +- **Percentage difference:** `% Difference = ((CostA - CostB) / CostB) * 100` +- **Ratio:** `Ratio = CostA / CostB` +- **Share of total:** each row's cost divided by total cost for its group + +When period lengths differ, normalize to a daily average before interpreting the result. + +### Step 5: Identify the largest differences +Look for: + +- services with the largest dollar delta in `ServiceName` +- subscriptions with the largest swing in `SubAccountName` +- region shifts in `RegionName` +- ownership concentration in `x_ResourceGroupName` +- allocation changes in `x_BillingProfileName` and `x_InvoiceSectionName` +- rows present in one group but absent in the other + +### Step 6: Drill into the root cause +After the first comparison, add one more dimension to explain the difference: + +- `ServiceName` by `SubAccountName` +- `ServiceName` by `RegionName` +- `x_ResourceGroupName` within the most expensive service or subscription +- `x_BillingProfileName` → `x_InvoiceSectionName` → `SubAccountName` + +Use `costs-enriched-base.kql` when you need to pivot the same filtered dataset more than once. + +### Step 7: Add optional tag overlays only after the base comparison is clear +If tag quality is usable, add `Tags['team']`, `Tags['product']`, `Tags['application']`, or `Tags['environment']` to explain ownership or workload context. + +If tags are missing or incomplete, use `ServiceName`, `SubAccountName`, `RegionName`, `x_ResourceGroupName`, `x_BillingProfileName`, or `x_InvoiceSectionName` instead so the comparison remains reliable. + +### Step 8: Explain what changed and what to do next +Summarize: + +- what changed +- where the difference is concentrated +- whether the difference is expected or avoidable +- which follow-up analysis or optimization should happen next + +## Output format + +### 1. Executive summary +- what was compared +- overall cost difference in dollars and percent +- one-sentence explanation of the primary driver +- recommended next action + +### 2. High-level comparison + +| Group | Total cost | Difference from baseline | % difference | +|------|------------|--------------------------|--------------| +| Group A | $X,XXX | +$X,XXX | +XX% | +| Group B | $X,XXX | baseline | 0% | + +### 3. Primary driver breakdown + +| Dimension | Group A | Group B | Difference | % difference | Notes | +|-----------|---------|---------|------------|--------------|-------| +| `ServiceName` or other primary field | $X,XXX | $X,XXX | +$XXX | +XX% | Main explanation | + +### 4. Root-cause drill-down +Use one of these structures: + +- `ServiceName` by `SubAccountName` +- `ServiceName` by `RegionName` +- `x_ResourceGroupName` for the most expensive subscription +- `x_BillingProfileName` and `x_InvoiceSectionName` for allocation conversations + +### 5. Unique or shifted costs +- rows only present in one group +- major cost movements between subscriptions, regions, or resource groups +- one-time charges or newly adopted services + +### 6. Optional tag view +If tag quality is usable, summarize what `Tags['team']`, `Tags['product']`, `Tags['application']`, or `Tags['environment']` adds to the analysis. + +If tags are blank or incomplete, explicitly state that the comparison relied on `ServiceName`, `SubAccountName`, `RegionName`, `x_ResourceGroupName`, `x_BillingProfileName`, or `x_InvoiceSectionName` instead. + +### 7. Recommendations +Recommend: +1. which cost deltas need immediate validation +2. which owners or teams should review the biggest differences +3. which resource groups, subscriptions, or regions need deeper investigation +4. whether metadata cleanup is needed before using tags in future comparisons + +## Common comparison scenarios + +### Scenario 1: This month versus last month +Goal: understand month-over-month change. + +Approach: +1. start with `monthly-cost-change-percentage.kql` +2. compare equal monthly windows +3. break the delta down by `ServiceName` +4. isolate new, removed, or sharply changed services +5. normalize for daily average if month lengths differ + +### Scenario 2: Production versus non-production +Goal: verify non-production is scaled appropriately. + +Approach: +1. use `ServiceName`, `SubAccountName`, or `x_ResourceGroupName` as the baseline comparison +2. add `Tags['environment']` only if the tag is present and trustworthy +3. compare service mix and total cost +4. identify oversized non-production resources +5. recommend rightsizing or shutdown opportunities + +### Scenario 3: Subscription versus subscription +Goal: benchmark business or technical ownership scopes. + +Approach: +1. compare totals by `SubAccountName` +2. split major differences by `ServiceName` +3. check whether `RegionName` or `x_ResourceGroupName` explains the variance +4. identify repeatable practices from the lower-cost peer + +### Scenario 4: Region versus region +Goal: understand regional cost differences. + +Approach: +1. start with `cost-by-region-trend.kql` +2. compare the same services across `RegionName` +3. check whether service mix or data movement explains the variance +4. recommend consolidation or placement review if the premium is avoidable + +### Scenario 5: Before versus after an optimization +Goal: measure realized impact. + +Approach: +1. compare equal windows before and after the change +2. quantify savings in dollars and percent +3. validate which `ServiceName`, `SubAccountName`, or `x_ResourceGroupName` changed +4. document repeatable lessons for future optimization work + +## Best practices +1. Compare equal periods whenever possible. +2. Start with a strong non-tag baseline dimension. +3. Use both dollars and percentages so materiality is obvious. +4. Use `monthly-cost-change-percentage.kql` for month-over-month context, then explain the delta with `ServiceName` or another strong grouping. +5. Use `costs-enriched-base.kql` when you need multiple follow-up pivots from the same filtered scope. +6. Add optional tags only when coverage is good enough to trust. +7. If tags are incomplete, say so and fall back to non-tag fields. + +## See also +- `references/queries/INDEX.md` +- `references/queries/finops-hub-database-guide.md` +- `costs-enriched-base.kql` +- `monthly-cost-change-percentage.kql` +- `cost-by-region-trend.kql` +- `cost-by-financial-hierarchy.kql` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-spike-investigation.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-spike-investigation.md new file mode 100644 index 000000000..733ce043c --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-spike-investigation.md @@ -0,0 +1,192 @@ +--- +name: cost-spike-investigation +description: Investigates sudden cost increases in FinOps hubs by comparing spike periods to baseline periods and isolating the services, subscriptions, regions, resource groups, resources, resource types, or usage types responsible for the change +author: FinOps Toolkit Team +version: 1.0.0 +license: Apache-2.0 +--- + +# Cost spike investigation + +## Purpose +Use this reference to explain why cost increased suddenly in a FinOps hub, determine whether the change is a short-lived spike or the start of a new baseline, and identify the drivers that need follow-up. + +## When to use +- “Why did cost jump?” +- “What caused the spike this week or this month?” +- “Which service or subscription explains the increase?” +- “Is this a one-time event or a sustained change?” +- Budget alert, anomaly triage, or executive escalation + +## Grounding +Use these canonical assets first: +- `cost-anomaly-detection.kql` +- `monthly-cost-change-percentage.kql` +- `top-services-by-cost.kql` +- `Costs()` + +Use the FinOps hub database guide and query catalog as the authoritative source for valid columns and query patterns. + +## How this skill works + +### Step 1: Define the spike and baseline periods +- Clarify the exact period where the spike appeared. +- Choose a comparable baseline period of equal length. +- Default to the last 7 days versus the previous 7 days when the user does not specify a window. +- Keep the comparison explicit so absolute and percentage change are easy to explain. + +### Step 2: Confirm the spike exists +Start with `cost-anomaly-detection.kql` to identify unusual daily movement and confirm when the spike started. + +Questions to answer: +- Which dates show the most unusual movement? +- Does the spike revert quickly or persist for multiple days? +- Is the spike isolated or part of a broader pattern? + +### Step 3: Quantify the magnitude +Use `monthly-cost-change-percentage.kql` when you need a simple percentage summary for stakeholders. + +Focus on: +- absolute increase +- percentage increase +- whether the latest monthly movement supports the same story as the daily spike + +### Step 4: Identify the first major driver +Use `top-services-by-cost.kql` to quickly identify whether one or two services explain most of the increase. + +Focus on: +- `ServiceName` values with the largest current spend +- services with the largest increase from baseline +- whether the spike is concentrated or broad-based + +### Step 5: Decompose the spike with `Costs()` +Use `Costs()` to isolate the dimensions responsible for the spike. + +Common fields to test: +- `ServiceName` +- `SubAccountName` +- `RegionName` +- `x_ResourceGroupName` +- `ResourceName` +- `ResourceType` +- `x_UsageType` + +#### Example: compare service cost across spike and baseline periods +```kusto +let spikeStart = ago(7d); +let spikeEnd = now(); +let baselineStart = ago(14d); +let baselineEnd = ago(7d); +let spike = + Costs() + | where ChargePeriodStart between (spikeStart .. spikeEnd) + | summarize SpikeCost = sum(EffectiveCost) by ServiceName; +let baseline = + Costs() + | where ChargePeriodStart between (baselineStart .. baselineEnd) + | summarize BaselineCost = sum(EffectiveCost) by ServiceName; +spike +| join kind=fullouter baseline on ServiceName +| extend SpikeCost = coalesce(SpikeCost, 0.0), BaselineCost = coalesce(BaselineCost, 0.0) +| extend CostIncrease = SpikeCost - BaselineCost +| order by CostIncrease desc +``` + +#### Example: isolate subscription and region drivers +```kusto +let spikeStart = ago(7d); +let spikeEnd = now(); +Costs() +| where ChargePeriodStart between (spikeStart .. spikeEnd) +| summarize EffectiveCost = sum(EffectiveCost) by SubAccountName, RegionName +| order by EffectiveCost desc +``` + +#### Example: isolate workload-specific resources +```kusto +let spikeStart = ago(7d); +let spikeEnd = now(); +Costs() +| where ChargePeriodStart between (spikeStart .. spikeEnd) +| summarize EffectiveCost = sum(EffectiveCost) by x_ResourceGroupName, ResourceName, ResourceType, x_UsageType +| order by EffectiveCost desc +``` + +### Step 6: Determine the spike shape +After reviewing the catalog queries and targeted `Costs()` breakdowns, classify the spike: +- **Transient spike:** abrupt increase followed by reversion +- **Sustained spike:** abrupt increase that remains elevated +- **Concentrated spike:** mostly explained by one `ServiceName`, `SubAccountName`, or `x_ResourceGroupName` +- **Broad spike:** spread across several dimensions +- **Usage-driven spike:** concentrated in one `x_UsageType` or `ResourceType` + +### Step 7: Name the primary cause +State the most important driver explicitly: +- top `ServiceName` contributor +- top `SubAccountName` contributor +- top `RegionName` contributor +- top `x_ResourceGroupName` contributor +- top `ResourceName` or `ResourceType` contributor when the issue is workload-specific + +Then state whether the driver explains most of the increase or only part of it. + +### Step 8: Recommend the next action +Interpret the spike before recommending action: +- expected event such as scale-out, launch, migration, or planned testing +- operational issue such as runaway workload or failed cleanup +- optimization opportunity tied to inefficient `ResourceType` or `x_UsageType` +- data-quality concern if the pattern conflicts with other trend evidence + +## Output format + +### 1. Executive summary +- Spike detected: yes or no +- Spike period analyzed +- Total increase in cost and percentage terms +- Primary driver by `ServiceName`, `SubAccountName`, `RegionName`, `x_ResourceGroupName`, `ResourceName`, or `ResourceType` +- One-sentence conclusion + +### 2. Spike metrics +- Baseline period cost +- Spike period cost +- Absolute increase +- Percentage increase +- Whether the spike is still ongoing + +### 3. Driver breakdown + +| Dimension | Top value | Why it matters | +| --- | --- | --- | +| ServiceName | [value] | Largest service contribution | +| SubAccountName | [value] | Largest subscription contribution | +| RegionName | [value] | Regional concentration | +| x_ResourceGroupName | [value] | Workload grouping with the largest increase | +| ResourceType | [value] | Resource class driving the spike | + +### 4. Interpretation +- When did the spike begin? +- Which dimension explains the largest share of the increase? +- Is the spike transient or sustained? +- Is the increase expected, wasteful, or still unverified? + +### 5. Recommended next step +- Investigate the primary driver if change is concentrated +- Review recent deployment or scaling events around the spike window +- Monitor closely if the spike is understood and expected +- Pursue optimization if the increase is sustained without business justification + +## Best practices +1. Start with `cost-anomaly-detection.kql` before writing custom spike logic. +2. Use `monthly-cost-change-percentage.kql` when stakeholders need a simple summary of magnitude. +3. Use `top-services-by-cost.kql` to identify the fastest path to likely drivers. +4. Use `Costs()` to explain the spike with `ServiceName`, `SubAccountName`, `RegionName`, and `x_ResourceGroupName`. +5. Use `ResourceName`, `ResourceType`, and `x_UsageType` when the spike appears workload-specific. +6. Compare equal-length periods so the increase is defensible. +7. Distinguish a short spike from a sustained baseline reset. + +## See also +- `queries/INDEX.md` +- `queries/finops-hub-database-guide.md` +- `cost-anomaly-detection.kql` +- `monthly-cost-change-percentage.kql` +- `top-services-by-cost.kql` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-trend-analysis.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-trend-analysis.md new file mode 100644 index 000000000..c5715f7e4 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/cost-trend-analysis.md @@ -0,0 +1,186 @@ +--- +name: cost-trend-analysis +description: Analyzes FinOps hubs cost trends over time to identify direction, month-over-month change, service and subscription drivers, regional patterns, and forecast-ready spending signals +author: FinOps Toolkit Team +version: 1.0.0 +license: Apache-2.0 +--- + +# Cost trend analysis + +## Purpose +Use this reference to analyze how cost changes over time in a FinOps hub, explain whether spend is rising or falling, and identify which services, subscriptions, regions, or resource groups are driving the change. + +## When to use +- “How are my costs trending?” +- “Are we increasing or decreasing month over month?” +- “Which services are driving the trend?” +- “Which subscription or resource group changed the most?” +- “Do regions explain the increase?” +- Budget review, forecast preparation, or executive reporting + +## Grounding +Use these canonical assets first: +- `monthly-cost-trend.kql` +- `monthly-cost-change-percentage.kql` +- `cost-by-region-trend.kql` +- `Costs()` + +Use the FinOps hub database guide and query catalog as the authoritative source for valid columns and query patterns. + +## How this skill works + +### Step 1: Define the analysis window +- Default to the last 12 full months for leadership trend analysis. +- Use at least 3 months for short trend checks. +- Use 12 months when you need to describe seasonality, sustained growth, or baseline shifts. + +### Step 2: Establish the overall monthly trend +Start with `monthly-cost-trend.kql` to understand the total billed and effective cost trajectory. + +Questions to answer: +- Is the overall trend increasing, decreasing, or flat? +- Is the latest month above or below the recent baseline? +- Are billed and effective cost moving together? + +### Step 3: Quantify the month-over-month change +Use `monthly-cost-change-percentage.kql` to measure direction and magnitude. + +Focus on: +- Latest month-over-month change +- Consecutive positive or negative months +- Whether change is accelerating, decelerating, or reverting toward baseline + +### Step 4: Check whether region explains the trend +Use `cost-by-region-trend.kql` when geography may explain the change. + +Focus on: +- `RegionName` values with the largest current spend +- Regions with the largest absolute change +- Whether a single region explains most of the overall movement + +### Step 5: Decompose the trend with `Costs()` +Use `Costs()` when you need a tailored breakdown by driver. + +Common dimensions: +- `ServiceName` +- `SubAccountName` +- `RegionName` +- `x_ResourceGroupName` +- `ResourceName` +- `ResourceType` +- `x_UsageType` + +#### Example: service trend +```kusto +let startDate = startofmonth(ago(365d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by Month = startofmonth(ChargePeriodStart), ServiceName +| order by Month asc +``` + +#### Example: subscription trend +```kusto +let startDate = startofmonth(ago(365d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by Month = startofmonth(ChargePeriodStart), SubAccountName +| order by Month asc +``` + +#### Example: resource group trend +```kusto +let startDate = startofmonth(ago(365d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by Month = startofmonth(ChargePeriodStart), x_ResourceGroupName +| order by Month asc +``` + +Use the same pattern to compare `ResourceName`, `ResourceType`, or `x_UsageType` when the trend appears to be concentrated in a narrow workload slice. + +### Step 6: Classify the pattern +After reviewing the catalog queries and custom `Costs()` breakdowns, classify the trend: +- **Growth:** sustained upward movement over multiple months +- **Decline:** sustained downward movement over multiple months +- **Stable:** narrow range with low month-over-month movement +- **Volatile:** frequent swings with no clear baseline +- **Step change:** a permanent shift beginning in a specific month + +### Step 7: Identify the main driver +Name the primary driver explicitly: +- top `ServiceName` contributor +- top `SubAccountName` contributor +- top `RegionName` contributor +- top `x_ResourceGroupName` contributor + +State whether the driver explains most of the change or only part of it. + +### Step 8: Prepare a forecast-ready conclusion +Trend analysis should support planning, not pretend certainty. + +Provide: +- current direction +- latest month-over-month percentage change +- largest driver +- confidence level based on consistency of recent months +- a conservative, expected, and high scenario if forecasting is requested + +## Output format + +### 1. Executive summary +- Overall trend: increasing, decreasing, stable, or volatile +- Latest monthly effective cost +- Latest month-over-month change from `monthly-cost-change-percentage.kql` +- Primary driver by `ServiceName`, `SubAccountName`, `RegionName`, or `x_ResourceGroupName` +- One-sentence takeaway + +### 2. Core metrics +- Trend period analyzed +- Latest billed cost +- Latest effective cost +- Month-over-month billed change +- Month-over-month effective change +- Number of consecutive months in the same direction + +### 3. Driver breakdown +Summarize the top contributors behind the trend: + +| Dimension | Top value | Why it matters | +| --- | --- | --- | +| ServiceName | [value] | Largest service contribution | +| SubAccountName | [value] | Largest subscription contribution | +| RegionName | [value] | Largest regional contribution | +| x_ResourceGroupName | [value] | Largest workload grouping contribution | + +### 4. Pattern interpretation +- What changed first? +- What kept changing afterward? +- Is the pattern broad-based or concentrated? +- Does the trend look durable or temporary? + +### 5. Recommended next step +- Continue monitoring if stable and expected +- Investigate the main driver if change is concentrated +- Prepare budget or forecast adjustments if growth is sustained +- Review optimization opportunities if growth is not tied to expected business activity + +## Best practices +1. Start with `monthly-cost-trend.kql` before writing a custom query. +2. Use `monthly-cost-change-percentage.kql` to quantify the latest movement instead of describing trend direction qualitatively. +3. Use `cost-by-region-trend.kql` when regional deployment, migration, or failover may explain the shift. +4. Use `Costs()` only after the catalog query establishes baseline context. +5. Decompose the trend with `ServiceName`, `SubAccountName`, `RegionName`, and `x_ResourceGroupName` before jumping to conclusions. +6. Explain whether the trend is broad or concentrated. +7. Keep forecast language bounded by recent trend consistency. + +## See also +- `queries/INDEX.md` +- `queries/finops-hub-database-guide.md` +- `monthly-cost-trend.kql` +- `monthly-cost-change-percentage.kql` +- `cost-by-region-trend.kql` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/custom-dimension-analysis.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/custom-dimension-analysis.md new file mode 100644 index 000000000..b64373eb1 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/custom-dimension-analysis.md @@ -0,0 +1,153 @@ +--- +name: custom-dimension-analysis +description: Analyze costs with business allocation fields and tags in FinOps hubs for showback, chargeback, and ownership reporting when those fields are populated. +author: Microsoft +version: 1.0.0 +license: Apache-2.0 +--- + +# Custom dimension analysis + +## Purpose +Use this reference to analyze costs through business-aligned dimensions such as team, product, application, environment, cost center, or project. In FinOps hubs, `Costs()` is the primary surface for this analysis. + +Treat business allocation metadata as observed and optional. Do not assume every hub populates every tag or enrichment column. + +## Validated grounding +Use these repo assets as the approved starting points: +- `Costs()` for primary analysis +- `costs-enriched-base.kql` to inspect enriched cost records and available metadata +- `cost-by-financial-hierarchy.kql` for a ready-made allocation pattern +- `finops-hub-database-guide.md` for schema details +- `INDEX.md` to find the right catalog query for the scenario + +## Business allocation fields to inspect +Inspect which populated fields, tags, and columns are actually present in your hub before choosing a business dimension. + +Common fields worth checking: +- `Tags['team']` +- `Tags['product']` +- `Tags['application']` +- `Tags['environment']` +- `x_CostCenter` +- `x_Project` +- `x_BillingProfileName` +- `x_InvoiceSectionName` + +Some environments have strong tag coverage, some rely more on financial hierarchy columns, and some have both. Use only the fields that are observed and meaningfully populated in the reporting period. + +## Recommended workflow + +### 1. Inspect populated business fields first +Start with `cost-by-financial-hierarchy.kql` when billing hierarchy answers the allocation question. Use `costs-enriched-base.kql` or a small direct query against `Costs()` only to inspect a narrow sample of populated tags and enrichment fields: + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| project x_BillingProfileName, x_InvoiceSectionName, x_CostCenter, x_Project, Tags +| take 50 +``` + +Review which available fields and tags are actually populated. If available, compare how consistently `Tags['team']`, `Tags['product']`, `Tags['application']`, `Tags['environment']`, `x_CostCenter`, and `x_Project` are filled. + +### 2. Choose the business dimension with the best coverage +If `Tags['team']` is populated, start there: + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| extend Team = tostring(Tags['team']) +| summarize EffectiveCost = sum(EffectiveCost) by Team +| order by EffectiveCost desc +``` + +Repeat the same pattern for `Tags['product']`, `Tags['application']`, `Tags['environment']`, `x_CostCenter`, or `x_Project` when populated. + +### 3. Add financial hierarchy context +Use `cost-by-financial-hierarchy.kql` when you need business reporting that rolls up through billing ownership and allocation layers. + +Example pattern: + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| extend Team = tostring(Tags['team']) +| extend Product = tostring(Tags['product']) +| extend Application = tostring(Tags['application']) +| summarize EffectiveCost = sum(EffectiveCost) + by x_BillingProfileName, x_InvoiceSectionName, Team, Product, Application, x_CostCenter, x_Project +| order by EffectiveCost desc +``` + +This is useful for showback and chargeback because it connects business ownership to the financial hierarchy already present in the hub. + +### 4. Measure allocation coverage honestly +Business reporting is only as strong as field coverage. + +```kusto +let base = + Costs() + | where ChargePeriodStart >= startofmonth(ago(30d)) + | extend Team = tostring(Tags['team']); +base +| summarize + TotalCost = sum(EffectiveCost), + AllocatedCost = sumif(EffectiveCost, isnotempty(Team)) +| extend AllocationCoverage = AllocatedCost / TotalCost +``` + +If the selected field is only partially populated, say so clearly. Unallocated cost is an important finding, not a formatting problem. + +### 5. Compare multiple business dimensions only when useful +If populated, compare team, product, application, cost center, or project to answer questions such as: +- Which team owns the most cost? +- Which product has the fastest growth? +- Which application is expensive across multiple invoice sections? +- Which `x_CostCenter` or `x_Project` values have weak allocation coverage? + +## Output guidance +Present results in a way finance and engineering teams can use: + +### Executive summary +- Dimension analyzed +- Reporting window +- Total effective cost +- Allocation coverage percentage +- Largest observed business owner or group +- Biggest data quality gap, if populated fields are inconsistent + +### Business dimension breakdown +| Business dimension | Effective cost | Percent of total | Coverage note | +|---|---:|---:|---| +| Team A | $X | Y% | Well populated | +| Team B | $X | Y% | Partial tags | +| Unallocated | $X | Y% | Missing tag or field | + +### Financial hierarchy context +Where useful, add: +- `x_BillingProfileName` +- `x_InvoiceSectionName` +- `x_CostCenter` +- `x_Project` + +This helps separate business ownership from billing structure. + +## Interpretation guidance +- Prefer the field with the most stable and populated coverage. +- If multiple fields disagree, call that out as a data-quality issue. +- If `Tags['environment']` is populated, use it to separate production from non-production before comparing teams or products. +- If `x_CostCenter` or `x_Project` is populated only for part of the estate, describe that limitation directly. +- Use `finops-hub-database-guide.md` to verify column meaning before making claims about ownership. +- Use `INDEX.md` to decide whether a catalog query is better than a custom query for the scenario. + +## Good analyst behavior +- Tell readers which fields were observed. +- Tell readers which fields were optional or sparsely populated. +- Tell readers to inspect populated tags before standardizing on a showback dimension. +- Keep the analysis centered on `Costs()` and validated query assets. + +## See also +- `queries/finops-hub-database-guide.md` +- `queries/INDEX.md` +- `queries/catalog/costs-enriched-base.kql` +- `queries/catalog/cost-by-financial-hierarchy.kql` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs-deployment.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs-deployment.md new file mode 100644 index 000000000..6ec35855b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs-deployment.md @@ -0,0 +1,323 @@ +--- +name: FinOps Hubs Deployment +description: How to deploy and configure Microsoft FinOps Hubs for cloud cost management and analytics. Covers prerequisites, deployment methods, scope configuration, data backfill, dashboard setup, and troubleshooting. +disable-model-invocation: true +--- + +# FinOps Hubs Deployment + +## Overview + +FinOps hubs provide a scalable platform for cost analytics, insights, and optimization. This skill covers deployment, configuration, and troubleshooting of the FinOps hub infrastructure. + +**Architecture:** +- Storage Account (Data Lake Gen2) - staging area for data ingestion +- Azure Data Factory - data ingestion and cleanup pipelines +- Azure Data Explorer (optional) - scalable datastore for analytics +- Microsoft Fabric RTI (optional) - alternative to Data Explorer +- Key Vault - stores managed identity credentials + +**Estimated Cost:** ~$120/mo + $10/mo per $1M in monitored spend + +--- + +## Prerequisites + +### Required Permissions + +| Task | Required Role | +|------|---------------| +| Deploy template | Contributor + Role Based Access Control Administrator (or Owner) | +| Configure subscription/RG exports | Cost Management Contributor | +| Configure EA billing exports | Enterprise Reader, Department Reader, or Account Owner | +| Configure MCA billing exports | Contributor on billing account/profile/invoice section | +| Configure MPA billing exports | Contributor on billing account/profile/customer | + +### Resource Providers + +Enable these resource providers before deployment: + +**Azure Portal:** +1. Open subscription → Settings → Resource providers +2. Register `Microsoft.EventGrid` +3. Register `Microsoft.CostManagementExports` + +**PowerShell:** +```powershell +Initialize-FinOpsHubDeployment +``` + +--- + +## Deployment Methods + +### Azure Portal + +Deploy using one of these links: +- **Azure Commercial:** https://aka.ms/finops/hubs/deploy +- **Azure Government:** https://aka.ms/finops/hubs/deploy/gov +- **Azure China (MCA only):** https://aka.ms/finops/hubs/deploy/china + +**Key Parameters:** + +| Parameter | Description | Recommendation | +|-----------|-------------|----------------| +| Hub Name | Used for resource naming and Cost Management grouping | Short, descriptive name | +| Data Explorer Name | Cluster name or Fabric eventhouse Query URI | Required for >$100K spend | +| Storage SKU | `Premium_LRS` or `Premium_ZRS` | Default (LRS) for initial deploy | +| Data Explorer SKU | Cluster size | `Dev(No SLA)_Standard_E2a_v4` to start | + +### PowerShell + +```powershell +# Install the module +Install-Module -Name FinOpsToolkit + +# Deploy to Azure Data Explorer +Deploy-FinOpsHub ` + -Name MyHub ` + -ResourceGroupName MyNewResourceGroup ` + -Location westus ` + -DataExplorerName MyFinOpsHubCluster + +# Deploy to Microsoft Fabric +Deploy-FinOpsHub ` + -Name MyHub ` + -ResourceGroupName MyNewResourceGroup ` + -Location westus ` + -DataExplorerName https://abcxyz123789.x0.kusto.fabric.microsoft.com +``` + +### Bicep Module + +```bicep +module finopsHub 'br/public:avm/ptn/finops-toolkit/finops-hub:' = { + params: { + hubName: 'finops-hub' + location: 'westus' + dataExplorerName: 'myhubcluster' + } +} +``` + +--- + +## Configure Scopes (Cost Management Exports) + +### Manual Export Creation + +Create exports for each scope you want to monitor: + +**Required Settings:** +- **Type of data:** `Cost and usage details (FOCUS)` +- **Dataset version:** `1.0` or `1.0r2` +- **Frequency:** `Daily export of month-to-date costs` +- **Container:** `msexports` +- **Format:** `Parquet` with `Snappy` compression +- **File partitioning:** On +- **Overwrite data:** Off (recommended) + +**Directory Path by Scope:** + +| Scope | Directory Path | +|-------|----------------| +| EA Billing Account | `billingAccounts/{enrollment-number}` | +| MCA Billing Profile | `billingProfiles/{billing-profile-id}` | +| Subscription | `subscriptions/{subscription-id}` | +| Resource Group | `subscriptions/{subscription-id}/resourceGroups/{rg-name}` | + +**Supported Datasets:** +- Cost and usage details (FOCUS) - `1.0`, `1.0r2` +- Price sheet - `2023-05-01` (required for missing prices) +- Reservation details - `2023-03-01` +- Reservation recommendations - `2023-05-01` (required for Rate optimization report) +- Reservation transactions - `2023-05-01` + +### Managed Exports + +Allow FinOps hubs to create and maintain exports automatically: + +1. Get Data Factory identity from deployment outputs (`managedIdentityId`) +2. Grant access to each scope: + - EA: Assign enrollment/department reader role + - Subscriptions: Assign Cost Management Contributor +3. Update `settings.json` in storage account `config` container: + +```json +{ + "scopes": [ + { "scope": "/providers/Microsoft.Billing/billingAccounts/1234567" }, + { "scope": "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e" } + ] +} +``` + +### PowerShell Export Commands + +```powershell +# Create FOCUS cost export with 12-month backfill +New-FinOpsCostExport -Name 'ftk-FinOpsHub-costs' ` + -Scope "{scope-id}" ` + -Dataset FocusCost ` + -StorageAccountId "{storage-resource-id}" ` + -StorageContainer msexports ` + -StoragePath 'billingAccounts/###' ` + -Backfill 12 ` + -Execute + +# Create price sheet export +New-FinOpsCostExport -Name 'finops-hub-prices' ` + -Scope '/providers/Microsoft.Billing/billingAccounts/###/billingProfiles/###' ` + -Dataset PriceSheet ` + -StorageAccountId $StorageAccountId ` + -StorageContainer msexports ` + -StoragePath 'billingProfiles/###' ` + -Backfill 13 + +# Create reservation recommendations export +New-FinOpsCostExport -Name 'finops-hub-resrecs' ` + -Scope '/providers/Microsoft.Billing/billingAccounts/###/billingProfiles/###' ` + -Dataset ReservationRecommendations ` + -CommitmentDiscountResourceType VirtualMachines ` + -CommitmentDiscountScope Shared ` + -CommitmentDiscountLookback 30 ` + -StorageAccountId $StorageAccountId ` + -StorageContainer msexports ` + -StoragePath 'billingProfiles/###' +``` + +--- + +## Backfill Historical Data + +### Azure Portal +1. Open Cost Management → Exports +2. Select the export +3. Select **Export selected dates** +4. Specify month (one at a time, up to 12 months) + +### PowerShell +```powershell +# Backfill 13 months +Start-FinOpsCostExport ` + -Scope '/providers/Microsoft.Billing/billingAccounts/###/billingProfiles/###' ` + -Name '{export-name}' ` + -Backfill 13 + +# Or specific date range +Start-FinOpsCostExport ` + -Scope '/providers/Microsoft.Billing/billingAccounts/###' ` + -Name '{export-name}' ` + -StartDate '2024-01-01' -EndDate '2024-12-31' +``` + +### Data Factory Pipeline +Run `config_RunBackfillJob` pipeline after exports complete: + +```powershell +Get-AzDataFactoryV2 -ResourceGroupName "{hub-resource-group}" ` +| ForEach-Object { + Invoke-AzDataFactoryV2Pipeline ` + -ResourceGroupName $_.ResourceGroupName ` + -DataFactoryName $_.DataFactoryName ` + -PipelineName 'config_RunBackfillJob' +} +``` + +--- + +## Microsoft Fabric Setup + +For Fabric as primary data store (instead of Data Explorer): + +### Before Deployment + +1. Create workspace and eventhouse in Fabric +2. Create **Ingestion** database +3. Run setup script from [finops-hub-fabric-setup-Ingestion.kql](https://github.com/microsoft/finops-toolkit/releases/latest/download/finops-hub-fabric-setup-Ingestion.kql) +4. Repeat for **Hub** database using [finops-hub-fabric-setup-Hub.kql](https://github.com/microsoft/finops-toolkit/releases/latest/download/finops-hub-fabric-setup-Hub.kql) +5. Copy the **Query URI** for deployment + +### After Deployment + +Grant Data Factory access to databases: + +```kusto +.add database Ingestion admins ('aadapp=') +.add database Hub admins ('aadapp=') +``` + +--- + +## Dashboard and Report Setup + +### Data Explorer Dashboard + +1. Download [finops-hub-dashboard.json](https://github.com/microsoft/finops-toolkit/releases/latest/download/finops-hub-dashboard.json) +2. Grant users **Viewer** access to Hub and Ingestion databases +3. Go to [dataexplorer.azure.com/dashboards](https://dataexplorer.azure.com/dashboards) +4. Import dashboard from file +5. Edit data source to point to your cluster + +### Power BI Reports + +Download reports based on your backend: +- **KQL (Data Explorer/Fabric):** [PowerBI-kql.zip](https://github.com/microsoft/finops-toolkit/releases/latest/download/PowerBI-kql.zip) +- **Storage:** [PowerBI-storage.zip](https://github.com/microsoft/finops-toolkit/releases/latest/download/PowerBI-storage.zip) +- **Demo (sample data):** [PowerBI-demo.zip](https://github.com/microsoft/finops-toolkit/releases/latest/download/PowerBI-demo.zip) + +**Required Parameters:** +- **Cluster URI:** Data Explorer cluster or Fabric eventhouse query URI +- **Storage URL:** DFS endpoint for the storage account + +--- + +## Template Outputs + +After deployment, retrieve these values from **Deployments → hub → Outputs:** + +| Output | Description | +|--------|-------------| +| `storageAccountId` | Resource ID of storage account | +| `storageAccountName` | Storage account name for Power BI | +| `storageUrlForPowerBI` | URL for custom Power BI reports | +| `clusterUri` | Data Explorer cluster URI | +| `managedIdentityId` | Data Factory managed identity (for managed exports) | +| `managedIdentityTenantId` | Tenant ID for managed exports | + +--- + +## Troubleshooting + +### Common Issues + +| Issue | Cause | Solution | +|-------|-------|----------| +| No data after export | Export takes up to 24 hours | Use "Run now" command | +| Missing prices | Price sheet export not configured | Create price sheet export | +| Power BI timeout | >$1M spend without Data Explorer | Redeploy with Data Explorer or Fabric | +| Export not visible | New subscription | Wait 48 hours for Cost Management activation | + +### Data Processing + +- Files land in `msexports` container +- Data Factory processes into `ingestion` container +- Final data available in Data Explorer **Hub** database + +### Verify Connectivity + +```kusto +Costs() | summarize count(), max(ChargePeriodStart) +``` + +--- + +## References + +- [FinOps Hubs Overview](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) +- [Create and Update FinOps Hubs](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/deploy) +- [Configure Scopes](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/configure-scopes) +- [FinOps Hub Template](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/template) +- [Configure Dashboards](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/configure-dashboards) +- [Troubleshooting Guide](https://learn.microsoft.com/cloud-computing/finops/toolkit/help/troubleshooting) +- [FinOps Toolkit PowerShell](https://learn.microsoft.com/cloud-computing/finops/toolkit/powershell/powershell-commands) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs.md new file mode 100644 index 000000000..5e878afd0 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/finops-hubs.md @@ -0,0 +1,130 @@ +--- +name: FinOps Hubs Analysis +description: Domain knowledge for analyzing cloud financial data in [Microsoft FinOps Hubs](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/finops-hubs-overview). It enables cost analysis, anomaly detection, savings optimization, and FinOps Framework-aligned reporting. **Mission**: Transform cloud cost data into actionable business insights through FinOps best practices. **Capabilities**: KQL analysis | Anomaly detection | Multi-cloud support | FinOps Framework guidance **Temporal**: Data refreshes daily | Default 30-day analysis | UTC timezone +--- + +## Query Access + +All KQL queries are located in `references/queries/`: + +| Resource | Path | Purpose | +|----------|------|---------| +| **Index** | `references/queries/INDEX.md` | Query catalog with descriptions and parameters | +| **Catalog** | `references/queries/catalog/*.kql` | Actual query files to execute | +| **Schema** | `references/queries/finops-hub-database-guide.md` | Database schema and column definitions | + +**To execute a query:** +1. Read the .kql file from `references/queries/catalog/[name].kql` +2. Substitute parameters (startDate, endDate, N, etc.) +3. Get environment config from `.ftk/environments.local.md` (cluster-uri, tenant, subscription, resource-group) +4. Execute via `mcp__azure-mcp-server__kusto` command `kusto_query` + +**Required MCP parameters:** +```json +{ + "cluster-uri": "", + "database": "Hub", + "tenant": "", + "query": "" +} +``` + +> **CRITICAL**: Always include `tenant` parameter. Cross-tenant (B2B) scenarios fail with "Unauthorized" if tenant is omitted. + +--- + +## Critical Constraints + +> **KUSTO (KQL), NOT SQL** +> +> FinOps Hubs uses **Azure Data Explorer (Kusto)**, not SQL Server. Use **KQL syntax only**. +> +> | KQL | SQL | +> |-----|-----| +> | `| where Column == "value"` | `WHERE Column = 'value'` | +> | `| summarize count() by Column` | `SELECT COUNT(*) GROUP BY Column` | +> | `| project Column1, Column2` | `SELECT Column1, Column2` | +> | `| take 10` | `TOP 10` or `LIMIT 10` | +> +> **NEVER use SQL syntax.** Queries will fail. + +**Database Rules:** +- Always use "Hub" database, NEVER "Ingestion" +- Function-based access: `Costs()`, `Prices()`, `Recommendations()`, `Transactions()` + +--- + +## Query Catalog Summary + +> **Tip:** Read `references/queries/INDEX.md` for the full catalog. Prefer a scenario-specific aggregate query first; use `costs-enriched-base.kql` when scoped row-level enrichment is required. + +| FinOps Task | Query File | Key Parameters | +|-------------|------------|----------------| +| Foundation for scoped custom drill-downs | `costs-enriched-base.kql` | `startDate`, `endDate` | +| Monthly cost trends | `monthly-cost-trend.kql` | `startDate`, `endDate` | +| Top resource groups | `top-resource-groups-by-cost.kql` | `N`, `startDate`, `endDate` | +| Top services | `top-services-by-cost.kql` | `N`, `startDate`, `endDate` | +| Anomaly detection | `cost-anomaly-detection.kql` | `numberOfMonths`, `interval` | +| Commitment utilization | `commitment-discount-utilization.kql` | `startDate`, `endDate` | +| Savings summary (ESR) | `savings-summary-report.kql` | `startDate`, `endDate` | +| Cost forecasting | `cost-forecasting-model.kql` | `forecastPeriods`, `interval` | +| AI workload unit economics | `ai-token-usage-breakdown.kql`, `ai-model-cost-comparison.kql`, `ai-daily-trend.kql`, `ai-cost-by-application.kql` | `startDate`, `endDate` | +| Reservation recommendations | `reservation-recommendation-breakdown.kql` | Filter by service/region | + +**Catalog Protocol:** +1. ALWAYS check the catalog FIRST before writing custom queries +2. Read the actual .kql file to get the exact query +3. Adapt only the parameters, never recreate enrichment logic +4. The `x_*` columns are pre-calculated - use them directly + +--- + +## Tool Matrix + +| Scenario | Primary Tool | Fallback | +|----------|--------------|----------| +| Cost queries | Query Catalog → `mcp__azure-mcp-server__kusto` | Manual query | +| Azure docs | `microsoft-docs:microsoft-docs` | Web search | +| Code reference | `microsoft-docs:microsoft-code-reference` | Web search | +| Resources | Azure Resource Graph via `mcp__azure-mcp-server__kusto` | Azure CLI | + +--- + +## Performance Rules + +1. **Default**: 30 days (`ago(30d)`) +2. **Max**: 90 days without approval +3. **Freshness check**: `Costs() | where ChargePeriodStart >= ago(7d) | summarize max(ChargePeriodStart)` + +**Bad**: `Costs() | summarize sum(BilledCost)` +**Good**: `Costs() | where ChargePeriodStart >= ago(30d) | summarize sum(BilledCost)` + +--- + +## FinOps Framework Alignment + +**Understand & Cost**: Allocation (tags) | Anomalies | Ingestion | Analytics +**Optimize**: Reservations | Right-sizing | Scheduling +**Quantify Value**: Unit economics | Budgets | Forecasts +**Manage Practice**: Governance | Onboarding | Education + +--- + +## Quality Checklist + +- [ ] Query Catalog checked FIRST +- [ ] Time filters on ALL queries +- [ ] Query shown to user before execution +- [ ] Results validated for completeness +- [ ] Confidence level stated +- [ ] Recommendations are actionable +- [ ] Impact quantified in dollars + +--- + +## References + +- [FinOps Framework (FinOps Foundation)](https://www.finops.org/framework/) +- [FinOps Hubs Overview](https://learn.microsoft.com/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) +- [KQL Documentation](https://learn.microsoft.com/azure/data-explorer/kusto/query/) +- [FinOps Foundation](https://www.finops.org/framework/) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/queries b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/queries new file mode 120000 index 000000000..34c826fa3 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/queries @@ -0,0 +1 @@ +../../../../../../../../queries \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/service-cost-deep-dive.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/service-cost-deep-dive.md new file mode 100644 index 000000000..b4edc2c24 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/service-cost-deep-dive.md @@ -0,0 +1,374 @@ +--- +name: service-cost-deep-dive +description: Performs a detailed deep dive into a specific service using FinOps hubs cost, price, and recommendation data. +author: FinOps Toolkit Team +version: 1.1.0 +license: Apache-2.0 +--- + +# Service cost deep dive + +## Purpose + +Use this reference to investigate one service in depth, explain what is driving cost, and identify practical optimization actions in a FinOps Toolkit / FinOps hubs environment. + +This deep dive keeps the original intent of service-level analysis, but uses validated FinOps hubs patterns: + +- `Costs()` as the primary analytical surface +- `Prices()` when unit-price validation is relevant +- `Recommendations()` when optimization guidance is relevant +- FinOps hubs fields such as `ServiceName`, `ResourceName`, `ResourceType`, `RegionName`, `SubAccountName`, `x_ResourceGroupName`, `x_UsageType`, and `Tags[...]` + +## Grounding and prerequisites + +Before starting: + +1. Review the schema guidance in [finops-hub-database-guide.md](./queries/finops-hub-database-guide.md). +2. Review the query catalog in [INDEX.md](./queries/INDEX.md). +3. Start from [costs-enriched-base.kql](./queries/catalog/costs-enriched-base.kql) for any custom drilldown that needs enriched fields. +4. Use [top-services-by-cost.kql](./queries/catalog/top-services-by-cost.kql) to confirm the exact `ServiceName` values in scope. +5. Use [service-price-benchmarking.kql](./queries/catalog/service-price-benchmarking.kql) when you need price and realized-savings context. + +Inspect which populated fields, tags, and columns are available in your hub before assuming business context exists. +Treat `x_CostCenter`, `x_Project`, `Tags["environment"]`, and `Tags['team']` as observed or optional fields, not guaranteed schema requirements. +If available, use those fields for attribution. If populated, use them to explain ownership. When populated, use them carefully and call out blanks honestly. + +## When to use + +- “Analyze my Azure SQL costs” +- “Deep dive into Virtual Machines spending” +- “Why is Storage getting more expensive?” +- “Break down this service by subscription, region, and resource group” +- “Show the specific resources behind a service spike” +- “Benchmark the service’s price and savings profile” +- “Find optimization opportunities for one service” + +## Workflow + +### Step 1: Identify the exact service + +Use the catalog query first if the service label is uncertain. + +```kusto +// Start with the catalog pattern from top-services-by-cost.kql +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by ServiceName +| top 20 by EffectiveCost desc +``` + +Pick the exact `ServiceName` that matches the user’s request before drilling deeper. + +### Step 2: Establish the service baseline + +Use `Costs()` as the primary surface for total cost and trend. + +```kusto +let targetService = 'Virtual Machines'; +let startDate = startofmonth(ago(90d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where ServiceName == targetService +| summarize TotalEffectiveCost = sum(EffectiveCost), + TotalBilledCost = sum(BilledCost), + TotalListCost = sum(ListCost), + TotalSavings = sum(x_TotalSavings) +``` + +```kusto +let targetService = 'Virtual Machines'; +let startDate = startofmonth(ago(90d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| where ServiceName == targetService +| summarize EffectiveCost = sum(EffectiveCost) by Day = startofday(ChargePeriodStart) +| order by Day asc +``` + +Calculate: + +- Total service cost +- Daily or monthly trend +- Share of total spend +- Realized savings already present in `x_TotalSavings` + +### Step 3: Break down the service by operational dimensions + +Start with the enriched base pattern from `costs-enriched-base.kql` when you need more context. + +**By subscription/account** + +```kusto +let targetService = 'Virtual Machines'; +Costs() +| where ServiceName == targetService +| summarize EffectiveCost = sum(EffectiveCost) by SubAccountName +| order by EffectiveCost desc +``` + +**By region** + +```kusto +let targetService = 'Virtual Machines'; +Costs() +| where ServiceName == targetService +| summarize EffectiveCost = sum(EffectiveCost) by RegionName +| order by EffectiveCost desc +``` + +**By resource group** + +```kusto +let targetService = 'Virtual Machines'; +Costs() +| where ServiceName == targetService +| summarize EffectiveCost = sum(EffectiveCost) by x_ResourceGroupName +| order by EffectiveCost desc +``` + +**By resource and resource type** + +```kusto +let targetService = 'Virtual Machines'; +Costs() +| where ServiceName == targetService +| summarize EffectiveCost = sum(EffectiveCost) by ResourceName, ResourceType +| top 50 by EffectiveCost desc +``` + +**By usage pattern** + +```kusto +let targetService = 'Virtual Machines'; +Costs() +| where ServiceName == targetService +| summarize EffectiveCost = sum(EffectiveCost) by x_UsageType +| order by EffectiveCost desc +``` + +Use these breakdowns to answer: + +- Which `SubAccountName` owns the cost? +- Which `RegionName` is driving spend? +- Which `x_ResourceGroupName` clusters the spend? +- Which `ResourceName` and `ResourceType` are the biggest contributors? +- Which `x_UsageType` explains the charge pattern? + +### Step 4: Attribute cost with business context + +Business fields are often optional or only partially populated. + +Inspect which populated fields or tags are present before choosing your allocation lens. + +```kusto +let targetService = 'Virtual Machines'; +Costs() +| where ServiceName == targetService +| project x_CostCenter, x_Project, Tags +| take 20 +``` + +If populated, use business context like this: + +```kusto +let targetService = 'Virtual Machines'; +Costs() +| where ServiceName == targetService +| extend Environment = tostring(Tags["environment"]), + Team = tostring(Tags['team']) +| summarize EffectiveCost = sum(EffectiveCost) + by Environment, Team, x_CostCenter, x_Project +| order by EffectiveCost desc +``` + +Call out blank or missing values explicitly. Untagged or unattributed cost is usually a governance finding, not just a reporting inconvenience. + +### Step 5: Investigate the service spike or trend change + +When the service changed recently, compare periods and isolate the dimensions that moved. + +```kusto +let targetService = 'Virtual Machines'; +let recentStart = startofmonth(ago(30d)); +let priorStart = startofmonth(ago(60d)); +let recent = + Costs() + | where ChargePeriodStart >= recentStart and ChargePeriodStart < now() + | where ServiceName == targetService + | summarize RecentCost = sum(EffectiveCost) by RegionName, x_ResourceGroupName, ResourceType; +let prior = + Costs() + | where ChargePeriodStart >= priorStart and ChargePeriodStart < recentStart + | where ServiceName == targetService + | summarize PriorCost = sum(EffectiveCost) by RegionName, x_ResourceGroupName, ResourceType; +recent +| join kind=fullouter prior on RegionName, x_ResourceGroupName, ResourceType +| extend RecentCost = coalesce(RecentCost, 0.0), + PriorCost = coalesce(PriorCost, 0.0), + Delta = RecentCost - PriorCost +| order by Delta desc +``` + +This highlights whether the change is driven by region expansion, new resource groups, or a different `ResourceType` mix. + +### Step 6: Validate unit-price and savings posture + +Use the service-price-benchmarking pattern first. If you need lower-level unit-price validation, use `Prices()` against the SKU identifiers surfaced from `Costs()`. + +```kusto +let targetService = 'Virtual Machines'; +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +let targetPrices = + Costs() + | where ChargePeriodStart >= startDate and ChargePeriodStart < endDate + | where ServiceName == targetService + | summarize by SkuPriceId; +Prices() +| where SkuPriceId in (targetPrices) +| project SkuPriceId, + ListUnitPrice, + ContractedUnitPrice, + x_EffectiveUnitPrice, + PricingUnit, + x_SkuMeterName, + x_SkuRegion, + x_SkuTerm +``` + +Use this to explain: + +- Whether unit prices look reasonable +- Whether negotiated or commitment discounts are already helping +- Whether price changes or SKU mix shifts are contributing to the increase + +### Step 7: Pull optimization recommendations when relevant + +Use `Recommendations()` when the service deep dive should end with a concrete action list. + +```kusto +let targetService = 'Virtual Machines'; +Recommendations() +| where x_SourceProvider == 'Microsoft' +| extend ServiceName = tostring(x_RecommendationDetails.ServiceName), + RegionName = tostring(x_RecommendationDetails.RegionName), + ResourceType = tostring(x_RecommendationDetails.ResourceType), + ResourceName = tostring(x_RecommendationDetails.ResourceName) +| where ServiceName =~ targetService or ResourceType has targetService +| project x_RecommendationDate, + ServiceName, + RegionName, + ResourceType, + ResourceName, + x_EffectiveCostBefore, + x_EffectiveCostAfter, + x_EffectiveCostSavings +| order by x_EffectiveCostSavings desc +``` + +Recommendation payload details can be optional. If available, use them to connect the service-level story to a short list of remediations. + +## Service-specific interpretation guidance + +### Compute services + +Focus on: + +- `ResourceType` mix +- `x_UsageType` patterns +- rightsizing candidates +- commitment discount coverage +- stop/deallocate opportunities + +Useful signals: + +- high spend concentrated in a few `ResourceName` values +- one `RegionName` carrying disproportionate cost +- expensive usage concentrated in one `x_ResourceGroupName` + +### Storage services + +Focus on: + +- growth by `ResourceName` +- region duplication +- hot vs. cooler usage patterns when visible in `x_UsageType` +- price posture using `Prices()` for the affected SKUs + +### Database services + +Focus on: + +- steady-state growth +- non-production cost hiding in the wrong `Tags["environment"]` +- expensive editions or resource families by `ResourceType` +- savings opportunities surfaced in `Recommendations()` + +### Network and transfer-heavy services + +Focus on: + +- `RegionName` concentration +- abrupt period-over-period movement +- resource-group concentration via `x_ResourceGroupName` +- whether the cost is spread broadly or driven by a few `ResourceName` entries + +## Output format + +Use this structure in the final response. + +### 1. Executive summary + +- Service analyzed: exact `ServiceName` +- Total cost for period +- Trend direction and magnitude +- Biggest cost driver +- Biggest optimization opportunity + +### 2. Cost breakdown + +- Top `SubAccountName` values +- Top `RegionName` values +- Top `x_ResourceGroupName` values +- Top `ResourceName` / `ResourceType` pairs +- Top `x_UsageType` values if available + +### 3. Business attribution + +- `x_CostCenter` and `x_Project` if populated +- `Tags["environment"]` and `Tags['team']` if populated +- clear note for unattributed cost + +### 4. Pricing and savings + +- observed list vs. contracted vs. effective posture +- realized savings from the service-price-benchmarking pattern +- whether unit-price review via `Prices()` changed the interpretation + +### 5. Recommendations + +- recommendation-backed actions from `Recommendations()` where available +- service-specific quick wins +- governance follow-ups for blank tags or weak attribution + +## Best practices + +1. Use `Costs()` first; only branch into `Prices()` or `Recommendations()` when the question requires it. +2. Confirm the exact `ServiceName` instead of guessing from a friendly service label. +3. Start broad, then narrow to `RegionName`, `SubAccountName`, `x_ResourceGroupName`, `ResourceType`, and `ResourceName`. +4. Inspect which populated fields and tags are available before promising allocation detail. +5. Treat business context as observed data, not guaranteed schema. +6. Use `costs-enriched-base.kql` when you need a reusable enriched baseline. +7. Use `top-services-by-cost.kql` for service discovery and `service-price-benchmarking.kql` for savings context. + +## See also + +- [finops-hub-database-guide.md](./queries/finops-hub-database-guide.md) +- [INDEX.md](./queries/INDEX.md) +- [costs-enriched-base.kql](./queries/catalog/costs-enriched-base.kql) +- [top-services-by-cost.kql](./queries/catalog/top-services-by-cost.kql) +- [service-price-benchmarking.kql](./queries/catalog/service-price-benchmarking.kql) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/settings-format.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/settings-format.md new file mode 100644 index 000000000..670d80e4b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/settings-format.md @@ -0,0 +1,71 @@ +# FinOps hubs environment settings + +FinOps hubs environment settings are stored in `.ftk/environments.local.md` at the project root. This file is agent-agnostic and supports multiple named environments. + +## File format + +The settings file uses YAML frontmatter with an optional markdown body for notes: + +```markdown +--- +default: dev-hub +environments: + dev-hub: + cluster-uri: https://myhubdev.eastus.kusto.windows.net + tenant: 00000000-0000-0000-0000-000000000000 + subscription: my-dev-subscription + resource-group: rg-finops-dev + prod-hub: + cluster-uri: https://myhubprod.westus2.kusto.windows.net + tenant: 00000000-0000-0000-0000-000000000000 + subscription: my-prod-subscription + resource-group: rg-finops-prod +--- + +# Environment notes + +Optional notes about your FinOps hub environments. +``` + +## Required fields + +| Field | Required | Description | +|-------|----------|-------------| +| `default` | Yes | Name of the default environment to use | +| `environments` | Yes | Map of named environments | +| `cluster-uri` | Yes | Full Azure Data Explorer cluster URI | +| `tenant` | Yes | Azure AD tenant ID (required for B2B/cross-tenant) | +| `subscription` | No | Azure subscription name or ID | +| `resource-group` | No | Resource group containing the hub | + +## Reading settings + +To read settings from `.ftk/environments.local.md`: + +1. Read the file at `.ftk/environments.local.md` relative to the project root +2. Parse the YAML frontmatter between the `---` delimiters +3. Use the `default` field to select the active environment unless the user specifies one +4. Extract `cluster-uri`, `tenant`, and other fields from the selected environment + +## Writing settings + +The `/ftk-hubs-connect` command discovers FinOps hub instances and writes their configuration to this file. When writing: + +1. Read the existing file if it exists to preserve other environments +2. Add or update the environment entry with the discovered values +3. Set `default` to the newly connected environment if no default exists + +## Using settings with MCP Kusto server + +After reading the active environment, pass the values to the MCP Kusto server: + +```json +{ + "cluster-uri": "", + "database": "Hub", + "tenant": "", + "query": "" +} +``` + +Always include the `tenant` parameter. Cross-tenant (B2B) scenarios fail with "Unauthorized" if tenant is omitted. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md new file mode 100644 index 000000000..bb740a7d7 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md @@ -0,0 +1,219 @@ +--- +name: tag-coverage-analysis +description: Analyze tag coverage and unattributed cost in FinOps hubs using validated cost fields, observed tags, and business allocation metadata. +author: Microsoft +version: 1.1.0 +license: Apache-2.0 +--- + +# Tag coverage analysis + +## Purpose + +Use this reference to evaluate how well cost records can be attributed through tags and business fields in FinOps hubs. + +Keep the original tag coverage intent, but ground the analysis in validated FinOps hubs patterns: + +- `Costs()` as the primary analytical surface +- `Tags[...]` for tag inspection and tag-based attribution +- business fields such as `x_CostCenter`, `x_Project`, `ServiceName`, `SubAccountName`, and `x_ResourceGroupName` +- query and schema assets including `costs-enriched-base.kql`, `cost-by-financial-hierarchy.kql`, `finops-hub-database-guide.md`, and `INDEX.md` + +Treat tags and business fields as observed and optional. Do not assume every hub populates every tag, enrichment column, or ownership field. + +## Grounding and prerequisites + +Before starting: + +1. Review [finops-hub-database-guide.md](./queries/finops-hub-database-guide.md) for schema details. +2. Review [INDEX.md](./queries/INDEX.md) to confirm whether a catalog query already fits the scenario. +3. Start from [costs-enriched-base.kql](./queries/catalog/costs-enriched-base.kql) when you need to inspect raw enriched records. +4. Use [cost-by-financial-hierarchy.kql](./queries/catalog/cost-by-financial-hierarchy.kql) when tag coverage needs to be compared with financial hierarchy fields. + +Inspect which populated tags, fields, and columns are actually present in the reporting window before calculating coverage. + +## When to use + +- “What is our tag coverage?” +- “How much cost is unattributed because tags are blank?” +- “Which subscriptions or resource groups have weak tag hygiene?” +- “Which services are missing cost allocation tags?” +- “Can we support showback or chargeback with our current tagging?” +- “Which business fields are populated enough to trust?” + +## Recommended workflow + +### Step 1: Inspect observed tags and business fields + +Start by reviewing a small sample from `Costs()`. + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| project ServiceName, SubAccountName, x_ResourceGroupName, x_CostCenter, x_Project, Tags +| take 50 +``` + +Inspect which populated tags and fields are present. Review which available keys inside `Tags` are actually populated, and note whether `x_CostCenter` or `x_Project` is present often enough to support allocation. + +Useful candidate tags often include: + +- `Tags['environment']` +- `Tags['team']` +- `Tags['application']` +- `Tags['owner']` +- `Tags['costCenter']` +- `Tags['project']` + +If available, compare those tags with `x_CostCenter` and `x_Project`. When populated, those business fields may be more stable than raw tags for financial reporting. + +### Step 2: Establish the total cost baseline + +Measure total effective cost for the reporting period before calculating any coverage percentage. + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| summarize TotalCost = sum(EffectiveCost) +``` + +This gives the denominator for all coverage calculations. + +### Step 3: Measure single-tag coverage honestly + +Choose one observed tag and calculate how much cost has a non-empty value. + +```kusto +let base = + Costs() + | where ChargePeriodStart >= startofmonth(ago(30d)) + | extend Environment = tostring(Tags['environment']); +base +| summarize + TotalCost = sum(EffectiveCost), + TaggedCost = sumif(EffectiveCost, isnotempty(Environment)) +| extend UntaggedCost = TotalCost - TaggedCost, + TagCoverage = TaggedCost / TotalCost +``` + +Repeat the same pattern for any observed tag or field that matters to the business, such as `Tags['team']`, `Tags['application']`, `x_CostCenter`, or `x_Project`. + +If populated coverage is weak, say so directly. Blank values are an important finding. + +### Step 4: Break down weak coverage by business context + +Once you find a weak tag, determine where the unattributed cost lives. + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| extend Environment = tostring(Tags['environment']) +| summarize TotalCost = sum(EffectiveCost), + UntaggedCost = sumif(EffectiveCost, isempty(Environment)) + by SubAccountName, ServiceName, x_ResourceGroupName +| order by UntaggedCost desc +``` + +This highlights which `SubAccountName`, `ServiceName`, or `x_ResourceGroupName` values have the largest unattributed cost. + +### Step 5: Compare tag coverage with financial hierarchy fields + +If available, compare tag-based attribution with business hierarchy fields. + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| extend Team = tostring(Tags['team']), + Application = tostring(Tags['application']) +| summarize EffectiveCost = sum(EffectiveCost) + by x_CostCenter, x_Project, Team, Application, SubAccountName +| order by EffectiveCost desc +``` + +Use `cost-by-financial-hierarchy.kql` as the validated pattern when you need a fuller billing hierarchy view. This is especially useful when tags are only partially populated but financial ownership fields are more reliable. + +### Step 6: Check service-level tag hygiene + +Some services may have weaker tagging than others. + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| extend ProjectTag = tostring(Tags['project']) +| summarize TotalCost = sum(EffectiveCost), + TaggedCost = sumif(EffectiveCost, isnotempty(ProjectTag)) + by ServiceName +| extend Coverage = TaggedCost / TotalCost +| order by Coverage asc, TotalCost desc +``` + +Use this to identify high-cost services with poor tag coverage first. + +### Step 7: Check account and resource-group concentration + +Weak tagging is often concentrated in a few places. + +```kusto +Costs() +| where ChargePeriodStart >= startofmonth(ago(30d)) +| extend CostCenter = coalesce(x_CostCenter, tostring(Tags['costCenter'])) +| summarize TotalCost = sum(EffectiveCost), + UnallocatedCost = sumif(EffectiveCost, isempty(CostCenter)) + by SubAccountName, x_ResourceGroupName +| order by UnallocatedCost desc +``` + +This helps prioritize cleanup by subscription and resource group instead of treating tag coverage as one flat percentage. + +## Output guidance + +### 1. Executive summary + +- Reporting window +- Total effective cost analyzed +- Best observed attribution field or tag +- Weakest important tag or field +- Total unattributed cost +- Highest-priority cleanup target + +### 2. Coverage scorecard + +| Field or tag | Coverage % | Tagged cost | Untagged cost | Notes | +|---|---:|---:|---:|---| +| `Tags['environment']` | XX% | $X | $Y | Observed, partially populated | +| `Tags['team']` | XX% | $X | $Y | Optional in some subscriptions | +| `x_CostCenter` | XX% | $X | $Y | Better for finance if populated | +| `x_Project` | XX% | $X | $Y | Sparse in shared platforms | + +### 3. Untagged or unattributed cost breakdown + +Report where blank values concentrate: + +- by `SubAccountName` +- by `ServiceName` +- by `x_ResourceGroupName` +- by `x_CostCenter` or `x_Project` when populated + +### 4. Interpretation notes + +- Call out which tags were observed. +- Call out which fields were optional. +- State whether business conclusions rely on tags, enrichment fields, or both. +- Tell readers to inspect populated tags and fields before standardizing on one allocation key. + +## Analyst guidance + +1. Use `Costs()` first; this is the primary surface for coverage analysis. +2. Inspect populated tags and available fields before choosing the dimensions to report. +3. Treat blank tags as governance evidence, not just missing formatting. +4. Prefer the most consistently populated field, even if it is `x_CostCenter` or `x_Project` instead of a tag. +5. Use `costs-enriched-base.kql` when you need to validate what the hub actually contains. +6. Use `cost-by-financial-hierarchy.kql` when you need to compare tags with billing ownership structure. +7. Use `finops-hub-database-guide.md` and `INDEX.md` before inventing custom assumptions about schema. + +## See also + +- [finops-hub-database-guide.md](./queries/finops-hub-database-guide.md) +- [INDEX.md](./queries/INDEX.md) +- [costs-enriched-base.kql](./queries/catalog/costs-enriched-base.kql) +- [cost-by-financial-hierarchy.kql](./queries/catalog/cost-by-financial-hierarchy.kql) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/top-cost-drivers.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/top-cost-drivers.md new file mode 100644 index 000000000..eef93808d --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/top-cost-drivers.md @@ -0,0 +1,183 @@ +--- +name: top-cost-drivers +description: Identifies and ranks the biggest contributors to FinOps hubs cost across services, subscriptions, regions, resource groups, billing hierarchy, and optional tags to help prioritize optimization work +author: FinOps Toolkit Team +version: 1.0.0 +license: Apache-2.0 +--- + +# Top cost drivers + +## Purpose +Use FinOps hubs data to identify the largest contributors to cost, measure how concentrated spend is, and prioritize the next optimization or allocation investigation. + +## When to use +- "What are my biggest costs?" +- "Where is most of my spend going?" +- "What should I optimize first?" +- "Show me top spending by service, subscription, region, or resource group" +- Monthly business reviews, budget planning, and allocation reviews +- Keywords: top, biggest, largest, highest, cost drivers, most expensive, concentration, ranking + +## Prerequisites +- Confirm the hub connection and reporting window before starting. +- Use `references/queries/finops-hub-database-guide.md` to verify available FinOps hubs fields and enrichment columns. +- Use `references/queries/INDEX.md` to select the closest aggregate ranking query. Use `costs-enriched-base.kql` only for a scoped row-level drill-down after the aggregate ranking is known. + +## Recommended ranking dimensions +Choose the first grouping that best matches the question: + +- `ServiceName` for top Azure service cost drivers +- `SubAccountName` for top subscriptions or sub-accounts +- `RegionName` for regional rollups +- `x_ResourceGroupName` for resource-group ranking +- `x_BillingProfileName` and `x_InvoiceSectionName` for billing hierarchy and allocation views + +## Analysis workflow + +### Step 1: Scope the request +Confirm: +- analysis period +- filters already in scope +- whether the user wants technical drivers, billing hierarchy drivers, or both +- whether optional business tags are trustworthy enough to use + +### Step 2: Start with the highest-signal primary dimension + +**Top services** +- Use `top-services-by-cost.kql` when the question is service-led. +- This is the fastest way to rank cost by `ServiceName`. + +```kusto +let N = 10; +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by ServiceName +| top N by EffectiveCost desc +``` + +**Top regions** +- Use `cost-by-region-trend.kql` for regional rollup and trend context. +- This groups cost by `RegionName` and helps surface regional concentration. + +```kusto +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by RegionName +| order by EffectiveCost desc +``` + +**Top resource groups** +- Use `top-resource-groups-by-cost.kql` when ranking by `x_ResourceGroupName`. +- If the catalog query is close but not exact, adapt the aggregate pattern before falling back to row-level samples. + +```kusto +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) by x_ResourceGroupName +| top 20 by EffectiveCost desc +``` + +**Top billing hierarchy nodes** +- Use `cost-by-financial-hierarchy.kql` when you need allocation or showback context. +- Focus on `x_BillingProfileName`, `x_InvoiceSectionName`, and `SubAccountName` before adding any lower-level dimensions. + +```kusto +let startDate = startofmonth(ago(30d)); +let endDate = startofmonth(now()); +Costs() +| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate +| summarize EffectiveCost = sum(EffectiveCost) + by x_BillingProfileName, x_InvoiceSectionName, SubAccountName +| top 20 by EffectiveCost desc +``` + +### Step 3: Add a multidimensional breakdown +After the primary ranking, add one more dimension to explain the driver: + +- `ServiceName` by `SubAccountName` +- `ServiceName` by `RegionName` +- `x_ResourceGroupName` within a top `ServiceName` +- `x_BillingProfileName` → `x_InvoiceSectionName` → `SubAccountName` + +Use `costs-enriched-base.kql` when you need to pivot the same filtered dataset multiple ways. + +### Step 4: Add optional tag-based grouping only when it helps +Tag-based grouping is optional. If your organization uses tags and coverage is good enough, add `Tags['team']`, `Tags['product']`, `Tags['application']`, or `Tags['environment']` as an overlay after the non-tag ranking is understood. + +If tags are missing, blank, or tag coverage is incomplete, fall back to `ServiceName`, `SubAccountName`, `RegionName`, `x_ResourceGroupName`, `x_BillingProfileName`, or `x_InvoiceSectionName` instead. + +Treat blank tag values as incomplete metadata, not as a reliable business grouping. + +### Step 5: Quantify concentration +For every ranked output: +1. calculate total spend for the filtered scope +2. calculate each row's percentage of total +3. calculate cumulative percentage +4. identify the smallest set of rows that explains roughly 80 percent of spend + +### Step 6: Add trend context when needed +- Re-run the top driver view over daily or monthly grain when the user asks what changed. +- `cost-by-region-trend.kql` is useful when regional growth or migration is part of the story. +- For custom trend work, start from `costs-enriched-base.kql` and keep the same driver dimensions so comparisons stay consistent. + +## Output format + +### 1. Executive summary +- total spend for the period +- scope analyzed +- top 3 drivers in one sentence +- immediate optimization or allocation takeaway + +### 2. Ranked cost drivers + +| Rank | Dimension | Cost | % of total | Cumulative % | +|------|-----------|------|------------|--------------| +| 1 | Value 1 | $X,XXX | XX% | XX% | +| 2 | Value 2 | $X,XXX | XX% | XX% | +| 3 | Value 3 | $X,XXX | XX% | XX% | + +### 3. Drill-down explanation +For each top driver, explain the most useful secondary split, such as: +- `ServiceName` by `SubAccountName` +- `ServiceName` by `RegionName` +- `x_ResourceGroupName` for the most expensive subscription +- `x_BillingProfileName` and `x_InvoiceSectionName` for chargeback conversations + +### 4. Concentration summary +- Top N rows represent X percent of spend +- Remaining long tail represents Y percent +- Recommendation on where to focus first + +### 5. Optional tag view +If tag quality is usable, summarize what `Tags['team']`, `Tags['product']`, `Tags['application']`, or `Tags['environment']` adds to the analysis. + +If tags are missing or incomplete, explicitly say the fallback ranking used `ServiceName`, `SubAccountName`, `RegionName`, `x_ResourceGroupName`, `x_BillingProfileName`, or `x_InvoiceSectionName` instead. + +### 6. Optimization priorities +Recommend: +1. highest-cost services or regions for immediate review +2. subscriptions or resource groups that need deeper investigation +3. billing hierarchy areas that need ownership clarification +4. metadata cleanup when optional tags are incomplete + +## Best practices +1. Start with one strong non-tag dimension before adding more detail. +2. Prefer `ServiceName`, `RegionName`, `SubAccountName`, and `x_ResourceGroupName` when tags are unreliable. +3. Use `x_BillingProfileName` and `x_InvoiceSectionName` for finance-facing allocation views. +4. Keep the ranking dimension stable when adding trend context. +5. Always report both dollars and percentages so concentration is obvious. + +## See also +- `references/queries/INDEX.md` +- `references/queries/finops-hub-database-guide.md` +- `costs-enriched-base.kql` +- `top-services-by-cost.kql` +- `cost-by-region-trend.kql` +- `cost-by-financial-hierarchy.kql` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/understand-finops-hub-context.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/understand-finops-hub-context.md new file mode 100644 index 000000000..ad08b9e3f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/understand-finops-hub-context.md @@ -0,0 +1,138 @@ +--- +name: understand-finops-hub-context +description: Mandatory foundational reference for establishing FinOps hub context before analysis +author: Microsoft +version: 1.0.0 +license: Apache-2.0 +--- + +# Understand FinOps hub context + +## Purpose + +This is the mandatory foundational step before any cost analysis. Start by confirming the active FinOps hub, validating the cluster URI, and establishing the available hub context before moving into deeper analysis. + +Use this reference once at the beginning of an analysis session, then reuse that context for the rest of the conversation instead of repeating the same setup work. + +## Required grounding references + +- `references/workflows/ftk-hubs-connect.md` +- `references/workflows/ftk-hubs-healthCheck.md` +- `references/queries/finops-hub-database-guide.md` +- `references/queries/INDEX.md` + +## When to use + +- **Mandatory** at the start of any FinOps analysis conversation or workflow +- Before using deeper query-catalog analysis patterns +- When switching to a different hub or cluster URI +- When the current session does not yet have confirmed hub context + +## What this step establishes + +This step confirms the Hub is reachable and identifies what context is actually observable from the FinOps hubs dataset. Ground your work in Azure Data Explorer, KQL, and the query catalog rather than assumptions. + +### Core data surfaces + +Use the documented functions from `references/queries/finops-hub-database-guide.md`: + +- `Costs()` +- `Prices()` +- `Recommendations()` +- `Transactions()` + +### Minimum validation query + +Use a simple KQL summary to understand data coverage before analysis: + +```kusto +Costs() +| summarize Rows=count(), MinCharge=min(ChargePeriodStart), MaxCharge=max(ChargePeriodStart), Services=dcount(ServiceName), ResourceGroups=dcount(x_ResourceGroupName) +``` + +This gives a quick view of row volume, date range, service diversity, and resource-group coverage. + +### Tag-key discovery + +Discover which tags are present instead of assuming a business taxonomy: + +```kusto +Costs() +| mv-expand TagKey = bag_keys(Tags) +| summarize by TagKey +| order by TagKey asc +``` + +Observed keys may include values such as `org`, `env`, `Project`, or `CostCenter`, but business tags are not guaranteed to exist consistently. + +## How to use this reference + +### Step 1: Connect to the correct Hub + +Follow `references/workflows/ftk-hubs-connect.md` to identify or confirm the active FinOps hub and cluster URI. + +If a cluster URI is already established for the session, reuse it. If not, connect first before running analysis queries. + +### Step 2: Validate the Hub and data freshness + +Use `references/workflows/ftk-hubs-healthCheck.md` after connection if you need to confirm version guidance or investigate stale data. + +### Step 3: Establish baseline analytical context + +Use the schema guide in `references/queries/finops-hub-database-guide.md` and the query catalog in `references/queries/INDEX.md` to choose the right starting point. + +For most custom exploration, begin with a small validation query, then expand into a catalog query or a focused KQL investigation. + +### Step 4: Record only observed business context + +Summarize what the Hub actually shows. Keep the summary factual and bounded to observable cost, pricing, recommendation, transaction, enrichment, and tag evidence. + +## Honest interpretation rules + +- Optional team tags may be missing, so treat them as observed only when present. +- Optional product tags may be missing or blank in many datasets. +- Optional application tags may be missing; if present, validate the actual tag key and coverage before using them. +- Optional environment tags are not guaranteed and may appear as `env` instead of a full `environment` key. + +Validation shorthand: `\bteam\b` is optional, `\bproduct\b` is optional, `\bapplication\b` is optional, and `\benvironment\b` is not guaranteed. + +Do not treat business tags as universal requirements across all records. + +Do not infer budget ownership, stakeholder mappings, recharge policy details, or future business milestones from Hub data alone. Those require separate business or governance inputs outside this foundational step. + +## Suggested output format + +After this step, provide a concise summary like: + +### Hub context summary + +- **FinOps hub**: [hub name or cluster short URI] +- **Cluster URI**: [active cluster URI] +- **Data coverage**: [min/max charge period, row count, major service count] +- **Available functions used for follow-up**: `Costs()`, `Prices()`, `Recommendations()`, `Transactions()` +- **Observed tag keys**: [examples discovered with `bag_keys(Tags)`] +- **Known gaps or cautions**: [missing tags, sparse coverage, stale data, or incomplete enrichment] + +### Recommended next move + +- Use `references/queries/INDEX.md` to choose a scenario-specific query. +- Use `references/queries/finops-hub-database-guide.md` to verify columns and enrichment fields. + +## Integration guidance for other references + +Other analysis references should assume this foundational step happened first. They should reuse the established hub context, cluster URI, freshness status, and observed tag evidence instead of re-establishing them from scratch. + +## Best practices + +1. Connect once, then reuse the confirmed hub context. +2. Prefer observed tag keys over assumed business dimensions. +3. Start with lightweight KQL validation before large analysis queries. +4. Use the query catalog for scenario-specific analysis instead of inventing unsupported patterns. +5. Keep conclusions limited to what the Hub data actually shows. + +## See also + +- `references/workflows/ftk-hubs-connect.md` +- `references/workflows/ftk-hubs-healthCheck.md` +- `references/queries/finops-hub-database-guide.md` +- `references/queries/INDEX.md` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-connect.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-connect.md new file mode 100644 index 000000000..6b49e1a21 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-connect.md @@ -0,0 +1,98 @@ +# Connect to a FinOps hub cluster + +## Step 1: Use the cluster identifier, if specified + +If the user specified a cluster, check `.ftk/environments.local.md` for a matching environment by hub name, cluster name, cluster short URI (name and location), or cluster URI. + +If the cluster has already been added to `.ftk/environments.local.md`, announce that you'll use that FinOps hub instance for the session and skip to step 4. + +If the cluster was not found in `.ftk/environments.local.md`, go to step 2 to find FinOps hub instances that you can connect to. + +## Step 2: Find FinOps hub instances, if not specified + +If a cluster was identified and found in the previous step, skip this step. + +If a cluster was not identified or was not found in the previous step, use this Azure Resource Graph query to find FinOps hub instances that you can connect to: + +```kusto +resources +| where type =~ "microsoft.kusto/clusters" +| where tags['ftk-tool'] == 'FinOps hubs' +| extend hubResourceId = tolower(tags["cm-resource-parent"]) +| extend hubName = split(hubResourceId, '/microsoft.cloud/hubs/')[1] +| extend hubVersion = tostring(tags["ftk-version"]) +| project hubResourceId, hubName, hubVersion, location, clusterResourceId = id, clusterName = name, clusterShortUri = strcat(name, '.', location), clusterUri = properties.uri, resourceGroup, subscriptionId +``` + +Filter this list based on the user's input, if provided. + +Notes about the columns: + +- Use the `clusterShortUri` to refer to the FinOps hub instance. +- Also accept the `hubName`, `clusterName`, or `resourceGroup` to refer to the FinOps hub instance as long as they are unique. If there are multiple FinOps hub instances with the same identifier, list them and ask which the user should use. +- Use the `clusterUri` to connect to the cluster using `#azmcp-kusto-query`. +- The `hubVersion` is the version of the FinOps hub instance. Format this value is a string using Semantic Versioning (SemVer) format (e.g., `major.minor` or `major.minor.patch` or `major.minor-prerelease`). + +Tell the user how many FinOps hub instances you found that matched their inputs, if provided. If there is only one FinOps hub instance, announce that you will use that FinOps hub instance for this session and skip to step 4. If there are multiple FinOps hub instances, list them with the following details: + +- `hubName` +- `hubVersion` +- `clusterShortUri` +- Subscription name + +If you don't find any FinOps hub instances, inform the user that you couldn't find any FinOps hubs and ask them to provide a subscription or cluster URI to connect. If they provide a subscription, repeat step 2 with that subscription name or ID. If they provide a cluster URI, use that for the session and skip to step 4. + +## Step 3: Ask which FinOps hub instance to use + +If a FinOps hub instance was identified in the previous steps, skip this step. + +If multiple FinOps hub instances were found and shared with the user, ask the user to select one of them by providing the `hubName`, `clusterShortUri`, or another cluster URI of the FinOps hub instance they want to use. + +## Step 4: Validate the FinOps hub instance + +If a FinOps hub instance was identified in a previous step, run the following query against the `Hub` database with the #azmcp-kusto-query command to validate the FinOps hub instance. Use the `tenant` from the selected environment. The query reads the version from `Ingestion.HubSettings`, but the primary analytical surface is still `Costs()` in the `Hub` database: + +```kusto +let version = toscalar(database('Ingestion').HubSettings | project version); +Costs() +| summarize + Cost = format_number(sum(EffectiveCost), 'N2'), + Months = dcount(startofmonth(ChargePeriodStart)), + DataLastUpdated = format_datetime(max(ChargePeriodStart), 'yyyy-MM-dd') + by + HubVersion = version, + BillingCurrency +``` + +Announce the name and version of the FinOps hub instance you are connecting to, when data was last updated, and how much cost is covered over how many months. Format the cost using the billing currency. If there are multiple billing currencies, list each in a bulleted list of formatted cost and number of months. + +If the query fails, inform the user that you couldn't connect to the FinOps hub instance and ask them to provide a different cluster URI or subscription name. If they provide a cluster URI, repeat step 4 with that URI. If they provide a subscription name, repeat step 2 with that subscription name. + +## Step 5: Save the environment + +After validating the FinOps hub instance, save the connection details to `.ftk/environments.local.md`: + +1. Read the existing file if it exists to preserve other environments +2. Add or update the environment entry using the `clusterShortUri` as the environment name +3. Include `cluster-uri`, `tenant`, `subscription`, and `resource-group` values +4. Set `default` to this environment if no default exists or if this is the only environment + +Example format: + +```markdown +--- +default: myhub.eastus +environments: + myhub.eastus: + cluster-uri: https://myhub.eastus.kusto.windows.net + tenant: 00000000-0000-0000-0000-000000000000 + subscription: my-subscription + resource-group: rg-finops +--- +``` + +See `references/settings-format.md` for the complete file format documentation. + +## Step 6: Run a health check + +After connecting to the FinOps hub instance, inform the user they can use the `/ftk-hubs-healthCheck` prompt to run a health check. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-healthCheck.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-healthCheck.md new file mode 100644 index 000000000..fe5470d2a --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/workflows/ftk-hubs-healthCheck.md @@ -0,0 +1,31 @@ +# Health check for FinOps hubs + +## Step 1: Check the latest released FinOps hub version + +Get the content from this file to determine the latest stable version of FinOps hubs: `https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/heads/main/src/templates/finops-hub/modules/ftkver.txt`. + +Get the content from this file to determine the latest development version of FinOps hubs: `https://raw.githubusercontent.com/microsoft/finops-toolkit/refs/heads/dev/src/templates/finops-hub/modules/ftkver.txt`. + +FinOps hubs use semantic versioning (SemVer) format for version numbers, which is `major.minor`, `major.minor.patch`, or `major.minor-prerelease`. If the version number has `-dev` at the end of it, that means it's a development version. + +Compare the version of the current FinOps hub instance with the latest stable version of FinOps hubs. If it's the same version as stable, tell the user they are using the latest released version and skip to the next step. + +If the FinOps hub version is the same as the development version, tell the user they are using the development version and they should monitor the repository to ensure it's updated with the latest changes, then skip to the next step. + +If the FinOps hub version is older than the development version and matches or is older than the latest stable version, tell the user they are using an older development version and should update to the latest stable release or development version. Mention their version number and the latest stable and development version numbers. Give them this link to deploy the latest stable version depending on their Azure cloud environment: + +- For the Azure public, commercial cloud, use https://aka.ms/finops/hubs/deploy +- For the Azure Government cloud, use https://aka.ms/finops/hubs/deploy/gov +- For the Azure China cloud, use https://aka.ms/finops/hubs/deploy/china + +## Step 2: Check the latest data refresh/update date + +If the last data refresh/update date is less than 24 hours ago, skip this step. + +If the last data refresh/update date is more than 24 hours ago, inform the user that the data may be stale and they should check the Microsoft Cost Management exports and Azure Data Factory data ingestion pipelines to ensure they are running without errors. + +Give them a link to Microsoft Cost Management to check the exports: https://portal.azure.com/#view/Microsoft_Azure_CostManagement/Menu/~/exports + +Give them a link to the Azure Data Factory portal to check data ingestion pipelines: https://adf.azure.com/monitoring/pipelineruns + +Tell the user you can help them troubleshoot any issues with [common errors](https://learn.microsoft.com/cloud-computing/finops/toolkit/help/errors) and the [troubleshooting guide](https://learn.microsoft.com/cloud-computing/finops/toolkit/help/troubleshooting). diff --git a/src/templates/sre-agent/recipes/finops-hub/config/subagents/azure-capacity-manager.yaml b/src/templates/sre-agent/recipes/finops-hub/config/subagents/azure-capacity-manager.yaml new file mode 100644 index 000000000..aa4ad764f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/subagents/azure-capacity-manager.yaml @@ -0,0 +1,122 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgent +metadata: + name: azure-capacity-manager +spec: + instructions: 'You are azure-capacity-manager, an Azure capacity-management specialist for SaaS ISVs operating workloads in ISV-owned Azure subscriptions under EA or MCA billing. + + + Load the azure-capacity-management skill when it''s available before handling capacity work. + + + Scope: + + - Handle Azure capacity management as part of the canonical FinOps Framework: Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization, Governance, Policy & Risk, and Automation, Tools, & Services. + + - Cover quota analysis and increases, quota groups and transfers, capacity reservation groups, sharing and overallocation, region access, zonal enablement, AKS capacity readiness, non-compute quota + constraints, and monitoring or governance alerts. + + - Use assigned Python capacity tools, knowledge files, and uploaded references to inspect current state, compare scenarios, and recommend next actions. + + - Do not call Kusto, Azure Resource Graph, Azure CLI, deployment, data freshness, or handoff tools. Use Teams, Outlook, and visualization tools only when the practitioner asks you to render or deliver the final evidence package. If Kusto-backed cost evidence is needed, return a precise evidence request for the practitioner to send to `ftk-database-query`. If Resource Graph, Hub health, or infrastructure remediation evidence is needed, return a precise evidence request for the practitioner to send to `ftk-hubs-agent`. + + + Grounding rules: + + - Don''t rely on unstated internal knowledge for Azure behavior. + + - Ground claims in uploaded knowledge, Microsoft Learn, or live command output gathered in the session. + + - Cite the source path, URL, or command evidence you used. + + - If a claim can''t be grounded, say so instead of guessing. + + + Key distinctions: + + - Capacity reservations guarantee compute supply. Azure Reservations and savings plans reduce cost. They aren''t substitutes. + + - Quota groups aggregate compute quota under management group scope, but they aren''t management groups and don''t inherit management group RBAC or policy. + + - Region access, quota increases, and zonal enablement are separate controls with separate approval paths. + + - Logical availability-zone mappings are subscription-specific, so verify physical zone alignment before cross-subscription sharing decisions. + + - Azure Data Explorer / Kusto SKU eligibility is service-specific and can differ from Microsoft.Compute SKU availability. Use `sku-availability` with `resource_provider: kusto` before advising on FinOps Hub analytics backend SKUs. + + + Python tool inventory: + + + - Use the database service quota tool for SQL DB, SQL MI, Cosmos DB, PostgreSQL Flex, and MySQL Flex quota, region access, and AZ-access risk checks. + + + Decision framework: + + 1. Gather state for quota usage, reservation coverage, access constraints, billing scope, and workload demand. + + 2. Identify the limiting constraint before recommending action. + + 3. Compare options with numbers whenever you can. + + 4. Make a clear recommendation, document assumptions, and list exact next steps. + + + Safety rules: + + - Stay review-oriented and propose write actions before executing them. + + - Don''t delete capacity reservations, reservation groups, or quota-group configuration without explicit confirmation. + + - Run what-if analysis before recommending reservation sizing, sharing, or reduction changes. + + - Call out zone-mismatch and cost risks before recommending zonal reservations or unused reserved capacity.' + handoffDescription: 'Route Azure capacity-management work here: quota analysis or increases, quota groups and transfers, capacity reservation group planning or sharing, region access, zonal enablement, + AKS capacity readiness, and monitoring or governance recommendations for Azure SaaS estates.' + handoffs: [] + tools: + - SearchMemory + - execute_python + - ExecutePythonCode + - PlotBarChart + - PlotPieChart + - PlotAreaChartWithCorrelation + - benefit-recommendations + - sku-availability + - vm-quota-usage + - non-compute-quotas + - db-service-quotas + - capacity-reservation-groups + - PostTeamsMessage + - SendOutlookEmail + - ReplyToTeamsMessage + - GetTeamsMessages + hooks: + PostToolUse: + - type: command + matcher: Bash|ExecuteShellCommand|Terminal|RunAzCliReadCommands|RunAzCliWriteCommands|execute_python|ExecutePythonCode + timeout: 30 + failMode: block + script: | + #!/usr/bin/env python3 + import json + import re + import sys + + context = json.load(sys.stdin) + tool_payload = json.dumps({ + "tool_input": context.get("tool_input", {}), + "tool_result": context.get("tool_result", ""), + }) + blocked = [ + (r"https://[^\s\"']+@github\.com", "Do not use authenticated GitHub remote URLs in shell commands. Use the configured credential provider or GitHub connector."), + (r"gh[pousr]_[A-Za-z0-9_]{20,}", "Do not pass GitHub tokens to shell tools or transcripts."), + (r"github_pat_[A-Za-z0-9_]{20,}", "GitHub PATs are forbidden. Do not pass personal access tokens to shell tools or transcripts."), + ] + + for pattern, reason in blocked: + if re.search(pattern, tool_payload): + print(json.dumps({"decision": "block", "reason": reason})) + sys.exit(0) + + print(json.dumps({"decision": "allow"})) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/subagents/chief-financial-officer.yaml b/src/templates/sre-agent/recipes/finops-hub/config/subagents/chief-financial-officer.yaml new file mode 100644 index 000000000..5dec69675 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/subagents/chief-financial-officer.yaml @@ -0,0 +1,45 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgent +metadata: + name: chief-financial-officer +spec: + instructions: 'You are the chief-financial-officer agent for FinOps and executive financial leadership scenarios. + + + Focus areas: + + - Lead strategic financial analysis tied to business outcomes, capital allocation, liquidity, and value creation. + + - Guide budgeting, rolling forecasts, scenario planning, variance analysis, and KPI-driven performance management. + + - Assess financial risk, controls, compliance exposure, and trade-offs across short-term execution and long-term sustainability. + + - Evaluate cloud and technology spending through a FinOps lens, including cost optimization, unit economics, commitment decisions, and investment prioritization. + + - Produce executive-ready recommendations for boards, CEOs, finance leaders, and FinOps stakeholders. + + + Response expectations: + + - Start with an executive summary. + + - Provide structured analysis with explicit assumptions, key drivers, and quantified reasoning when data is available. + + - Recommend prioritized actions, expected impact, risks, and mitigations. + + - Call out missing data, uncertainty, and follow-up steps needed for a decision. + + - For month-level, fiscal-period, or scheduled financial reports, consume evidence packages from the FinOps practitioner, FinOps Hub database specialist, and capacity specialist. You have only the Knowledge Base search tool (`SearchMemory`) so you can read uploaded recipe knowledge and prior memory. You have no operational tools; do not run raw data collection, delivery, or visualization yourself. + + - Keep the analysis strategic, financially rigorous, and actionable. + - Do not own autonomous scheduled tasks. Act as a consulted Finance and Leadership persona for budgeting, forecasting, unit economics, investment tradeoffs, commitment risk, and executive packaging.' + handoffDescription: Executive financial strategy and FinOps leadership for budgeting, forecasting, risk, capital allocation, and cost optimization. + handoffs: [] + tools: + - SearchMemory + systemTools: [] + mcpTools: [] + maxReflectionCount: 0 + customReflectionNote: '' + commonPrompts: [] + enableVanillaMode: true diff --git a/src/templates/sre-agent/recipes/finops-hub/config/subagents/finops-practitioner.yaml b/src/templates/sre-agent/recipes/finops-hub/config/subagents/finops-practitioner.yaml new file mode 100644 index 000000000..29642280e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/subagents/finops-practitioner.yaml @@ -0,0 +1,86 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgent +metadata: + name: finops-practitioner +spec: + instructions: 'You are a FinOps practitioner specializing in Azure cloud financial management and FinOps Toolkit adoption. + + + Mission: + + - Guide teams on implementing FinOps practices using the six FinOps principles. + + - Help with cost allocation, shared-cost management, showback and chargeback, commitment optimization, budgeting, forecasting, governance, anomaly management, and FinOps operating-model design. + + - Translate FinOps concepts into practical implementation guidance using Azure Cost Management and FinOps Toolkit capabilities where they materially help. + + + Working approach: + + 1. Assess context first: business objectives, stakeholders, cloud footprint, current pain points, and the organization''s Crawl-Walk-Run maturity. + + 2. Align recommendations to the FinOps principles: collaboration, business value, ownership, timely and accurate data, central enablement, and effective use of the cloud variable-cost model. + + 3. Evaluate trade-offs clearly: expected value, implementation effort, risk, and organizational impact. + + 4. Deliver an action plan: prioritized next steps, owners, metrics, and sequencing appropriate to the team''s maturity. + + 5. State assumptions explicitly when required data is missing. + + + Focus areas: + + - Understand Usage & Cost: data quality, FOCUS-aligned reporting, tagging, allocation models, and shared-cost transparency. + + - Quantify Business Value: budgeting, forecasting, benchmarking, and unit economics. + + - Optimize Usage & Cost: rightsizing, commitment strategy, workload efficiency, pricing optimization, and automation opportunities. + + - Manage the FinOps Practice: enablement, governance, accountability, alerts, anomalies, and sustainable operating rhythms. + + + Guardrails: + + - Never recommend blind cost cutting without explaining business impact, trade-offs, and risk. + + - Never centralize all cloud decisions away from engineering teams. + + - Never hide cost data from the stakeholders who need visibility and ownership. + + - Never recommend commitments without considering utilization risk, flexibility, and long-term business plans. + + - Always provide maturity-appropriate guidance. Keep Crawl-stage recommendations focused on foundational visibility and governance, Walk-stage guidance on process and optimization, and Run-stage guidance + on automation, policy, and advanced financial analytics. + - When `ftk-database-query` reports that top-other-transactions returned the literal string ZERO_ROWS_RETURNED, treat the tool call itself as completed, then ask `ftk-hubs-agent` to run data-freshness-check before stating that no transactions matched. If data-freshness-check reports TRANSACTIONS_ZERO_ROWS, surface the export / ingestion / stored-function diagnostic as a report limitation instead of a successful empty result. + + + Collaboration guidance: + + - Use FinOps Toolkit and Azure Cost Management concepts when they improve implementation speed, data quality, or governance rigor. + + - Own every scheduled task run and the FinOps operating rhythm. You have only the Knowledge Base search tool (`SearchMemory`) so you can read uploaded recipe knowledge, prior memory, and `ftk-output-style.md`. You have no operational tools. Orchestrate the four delegated subagents for specialist evidence, visualization, delivery, and decision framing. Do not gather data or deliver reports yourself. + + - Hand off every FinOps Hub database, KQL, FOCUS, Costs(), Prices(), Recommendations(), and Transactions() request to `ftk-database-query`. Never call Kusto tools directly. + + - Hand off quota, capacity reservation group, regional SKU, zonal availability, AI/GPU capacity, database service quota, and benefit recommendation questions to `azure-capacity-manager`. + + - Hand off FinOps Hub platform health, data freshness, Azure Resource Graph inventory, deployment validation, alert or budget deployment, Advisor suppression management, and infrastructure remediation questions to `ftk-hubs-agent`. + + - Hand off executive finance narratives, portfolio prioritization, and board-level recommendations to `chief-financial-officer`. The CFO consumes evidence and pontificates on results; it does not gather data or own schedules. + + - Subagent handoffs preserve main-agent context. Pass the exact task scope, evidence already collected, open questions, and requested output shape with each handoff.' + handoffDescription: 'Use this agent for FinOps practice guidance: cost allocation, shared-cost strategy, showback or chargeback, commitment optimization, budgeting, forecasting, governance, anomaly response, + maturity assessment, and operating-model implementation aligned to FinOps principles and the Crawl-Walk-Run maturity model.' + handoffs: + - chief-financial-officer + - ftk-database-query + - azure-capacity-manager + - ftk-hubs-agent + tools: + - SearchMemory + systemTools: [] + mcpTools: [] + maxReflectionCount: 0 + customReflectionNote: '' + commonPrompts: [] + enableVanillaMode: true diff --git a/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-database-query.yaml b/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-database-query.yaml new file mode 100644 index 000000000..b6a46bc93 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-database-query.yaml @@ -0,0 +1,146 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgent +metadata: + name: ftk-database-query +spec: + instructions: 'You are the FinOps Hub database and KQL specialist for the FinOps Toolkit. + + + Scope: + + - Query, explain, and analyze FinOps Hub cost, pricing, recommendation, and transaction data. + + - Use KQL for all database work. Never use SQL syntax. + + - Always use the Hub database for analytics. Never use Ingestion for end-user analysis. + + - Use attached FinOps Hub Kusto query tooling for live execution when it is available; otherwise provide the exact KQL and required execution parameters. + + - Never use RunAzCliReadCommands, Azure CLI, `az rest`, Python, data-freshness-check, Resource Graph, deployment, or handoff tools. Use Teams, Outlook, and visualization tools only when the practitioner asks you to render or deliver the final evidence package. Use the attached Kusto tools for catalog analytics. If Hub data freshness, Resource Graph inventory, platform health, or infrastructure remediation evidence is needed, return a precise evidence request for the practitioner to send to `ftk-hubs-agent`. + + + Required workflow: + + 1. Check the query catalog first before writing custom KQL. + + 2. Reuse or adapt the closest catalog query when it fits the user''s scenario. + + 3. If no catalog query fits, start custom analysis from costs-enriched-base for scoped row-level drill-down only and extend it instead of rebuilding enrichment logic from scratch. Do not run costs-enriched-base for full-month, fiscal-period, scheduled report, dashboard export, or broad tag-coverage requests. Use aggregation tools first, then drill into a one-day or narrower slice only when raw details are required. + + 4. Filter early with the correct date column for the function and keep the query scoped to the user''s question. Use ChargePeriodStart for Costs() and Transactions(); use x_EffectivePeriodStart for Prices(); do not assume every function has ChargePeriodStart. + + 5. Prefer EffectiveCost unless the user explicitly asks for billed, contracted, or list cost. + + + Database functions to use: + + - Costs() for FOCUS-aligned cost and usage analysis. + + - Prices() for list, contracted, and effective pricing analysis. + + - Recommendations() for reservation and savings plan recommendation analysis. + + - Transactions() for commitment purchases, refunds, exchanges, and other non-usage financial transactions. + + + Query and response rules: + + - Use exact schema column names, including x_ enrichment columns when needed. + + - Treat Tags as dynamic and extract values with tostring(Tags[''key'']). + + - Always include tenant when preparing live query parameters for the customer''s FinOps Hub cluster and Hub database. + + - Explain which function, filters, and metrics you used, then summarize the result clearly. + + - If a requested query is too broad, require tighter time, subscription, region, or resource scope before execution. + - When top-other-transactions returns the literal string ZERO_ROWS_RETURNED, treat the tool call itself as completed, then tell the practitioner to ask `ftk-hubs-agent` to run data-freshness-check before stating that no transactions matched. If data-freshness-check reports TRANSACTIONS_ZERO_ROWS, surface the export / ingestion / stored-function diagnostic as a report limitation instead of a successful empty result. + + + Grounding rules: + + - Check uploaded FinOps Toolkit references and schema guidance before making claims about functions or columns. + + - Do not duplicate long reference docs in your answers; summarize only the parts needed for the current analysis. + + - If data is missing, stale, or inconsistent, say so and suggest the next diagnostic step. + + - When `Transactions()` or transaction tools return zero rows, do not state that no transactions occurred. Tell the practitioner that `ftk-hubs-agent` must run `data-freshness-check` to confirm row counts and diagnostics. If `TRANSACTIONS_ZERO_ROWS` appears, explain that reservation transaction analysis is unavailable until the `reservationtransactions` export, Data Factory Transactions ingestion, and `Transactions()` / `Transactions_v1_2()` stored functions are verified.' + handoffDescription: 'Use this agent for FinOps Hub database and KQL work: query design, schema-aware cost analysis, pricing lookups, recommendation analysis, transaction analysis, and interpretation of + FinOps Hub data in the Hub database.' + handoffs: [] + tools: + - SearchMemory + - PlotBarChart + - PlotPieChart + - PlotAreaChartWithCorrelation + - ai-cost-by-application + - ai-daily-trend + - ai-model-cost-comparison + - ai-token-usage-breakdown + - allocation-accuracy-index + - anomaly-detection-rate + - anomaly-variance-total + - commitment-discount-waste + - commitment-discount-utilization + - commitment-utilization-score + - cost-anomaly-detection + - cost-by-financial-hierarchy + - cost-by-region-trend + - cost-forecasting-model + - cost-optimization-index + - cost-per-gb-stored + - cost-visibility-delay + - costs-enriched-base + - compute-cost-per-core + - compute-spend-commitment-coverage + - data-update-frequency + - macc-consumption-vs-commitment + - monthly-cost-change-percentage + - monthly-cost-trend + - percentage-unallocated-costs + - percentage-untagged-costs + - quarterly-cost-by-resource-group + - reservation-recommendation-breakdown + - savings-summary-report + - service-price-benchmarking + - storage-tier-distribution + - tagging-policy-compliance + - top-commitment-transactions + - top-other-transactions + - top-resource-groups-by-cost + - top-resource-types-by-cost + - top-services-by-cost + - PostTeamsMessage + - SendOutlookEmail + - ReplyToTeamsMessage + - GetTeamsMessages + hooks: + PostToolUse: + - type: command + matcher: Bash|ExecuteShellCommand|Terminal|RunAzCliReadCommands|RunAzCliWriteCommands|execute_python|ExecutePythonCode + timeout: 30 + failMode: block + script: | + #!/usr/bin/env python3 + import json + import re + import sys + + context = json.load(sys.stdin) + tool_payload = json.dumps({ + "tool_input": context.get("tool_input", {}), + "tool_result": context.get("tool_result", ""), + }) + blocked = [ + (r"https://[^\s\"']+@github\.com", "Do not use authenticated GitHub remote URLs in shell commands. Use the configured credential provider or GitHub connector."), + (r"gh[pousr]_[A-Za-z0-9_]{20,}", "Do not pass GitHub tokens to shell tools or transcripts."), + (r"github_pat_[A-Za-z0-9_]{20,}", "GitHub PATs are forbidden. Do not pass personal access tokens to shell tools or transcripts."), + ] + + for pattern, reason in blocked: + if re.search(pattern, tool_payload): + print(json.dumps({"decision": "block", "reason": reason})) + sys.exit(0) + + print(json.dumps({"decision": "allow"})) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml b/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml new file mode 100644 index 000000000..01959c356 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml @@ -0,0 +1,110 @@ +# T-5: RTM FR-1.1 +api_version: azuresre.ai/v2 +kind: ExtendedAgent +metadata: + name: ftk-hubs-agent +spec: + instructions: |- + You are the FinOps Hubs deployment and operations specialist for the FinOps Toolkit. + + Scope: + - Deploy new FinOps Hubs environments. + - Upgrade existing hub deployments. + - Maintain hub configuration, exports, dashboards, and connectivity. + - Troubleshoot failed deployments and unhealthy hub environments. + - Manage FinOps Hub infrastructure health, Resource Graph inventory, data freshness, deployment validation, alert and budget deployment, and Advisor suppression operations. + + Operating rules: + - Start by checking uploaded knowledge for FinOps Hubs deployment, hub architecture, compatibility, and troubleshooting guidance before taking action. + - Prefer Azure CLI workflows and use Azure CLI help when command syntax or parameters need verification. + - Use read commands for discovery and validation first; use write commands only after the change has been validated. + - For FinOps Hub database freshness, run `data-freshness-check`. Do not use Azure CLI or `az rest` against Azure Data Explorer query or management endpoints. + - Do not run FinOps Hub analytical Kusto tools such as cost, savings, pricing, recommendation, or transaction queries. Those belong to `ftk-database-query`; use `data-freshness-check` only for Hub freshness and function diagnostics. + - Do not duplicate long-form documentation in your responses; summarize only the guidance needed for the current task. + + Deployment and upgrade workflow: + 1. Verify prerequisites before proposing or running changes: + - Confirm subscription, resource group, region, hub name, backend choice, and required parameters. + - Confirm Azure authentication and the required RBAC for deployment and Cost Management export configuration. + - Confirm Bicep is available for template validation. + - Validate required resource providers, especially Microsoft.EventGrid and Microsoft.CostManagementExports. + - Check for naming conflicts, unsupported regions, quota limits, and existing resources that might block the deployment. + - For Data Explorer / Kusto analytics backend deployments or upgrades, run `sku-availability` with `resource_provider: kusto`, `subscription_id`, `location`, and the planned Data Explorer SKU as `sku_filter`. Treat `is_available: false` as a deployment blocker; do not infer Kusto SKU eligibility from Microsoft.Compute SKU availability. + 2. Validate templates before deployment: + - Inspect the template and parameter set. + - Run template validation such as `bicep build --stdout` before deployment. + - Review version compatibility and breaking changes before upgrades. + 3. Required safety gate for every deploy or upgrade: + - Run `az deployment group what-if` or `az deployment sub what-if` before applying changes. + - Show or summarize the expected changes before proceeding. + - If what-if or template validation fails, stop and explain the blocking issue before any write action. + 4. Execute the deployment or upgrade only after prerequisites, template validation, and what-if complete successfully. + 5. Perform post-deployment validation: + - Confirm the deployment succeeded and the expected resources exist. + - Verify storage, Data Factory, Key Vault, and analytics backend connectivity as applicable. + - Validate Hub database readiness, Cost Management export configuration, and any required follow-up setup. + - Use `data-freshness-check` as the source of truth for Hub data freshness. Treat `Costs()` from that direct REST tool as authoritative over stale memory, raw KQL rollups, or ingestion timestamp conclusions. + - Capture important outputs such as cluster URI, storage details, and managed identity IDs for downstream configuration. + + Maintenance and troubleshooting workflow: + - Gather the exact operation, error text, resource IDs, deployment logs, and recent changes. + - Check common root causes first: RBAC, missing providers, region support, quota limits, naming conflicts, missing exports, version incompatibility, and broken connectivity. + - For errors such as "The sku is not supported in " in nested Microsoft.FinOpsHubs.Analytics deployments, preflight the target region with `sku-availability` using `resource_provider: kusto` and recommend a returned SKU or a region where the requested SKU is returned. + - Use deployment operations and current resource state to isolate the fault before recommending fixes. + - Provide concrete remediation steps, validate the result, and summarize next steps. + - Warn before destructive changes and recommend backup or rollback planning for upgrades and major configuration changes. + handoffDescription: Deploys, upgrades, maintains, and troubleshoots FinOps Hubs with validation-first Azure workflows. + handoffs: [] + tools: + - SearchMemory + - RunAzCliReadCommands + - RunAzCliWriteCommands + - GetAzCliHelp + - PlotBarChart + - PlotPieChart + - PlotAreaChartWithCorrelation + - data-freshness-check + - resource-graph-query + - sku-availability + - deploy-anomaly-alert + - deploy-budget + - deploy-bulk-anomaly-alerts + - deploy-bulk-budgets + - suppress-advisor-recommendations + - PostTeamsMessage + - SendOutlookEmail + - ReplyToTeamsMessage + - GetTeamsMessages + hooks: + PostToolUse: + - type: command + matcher: Bash|ExecuteShellCommand|Terminal|RunAzCliReadCommands|RunAzCliWriteCommands|execute_python|ExecutePythonCode + timeout: 30 + failMode: block + script: | + #!/usr/bin/env python3 + import json + import re + import sys + + context = json.load(sys.stdin) + tool_payload = json.dumps({ + "tool_input": context.get("tool_input", {}), + "tool_result": context.get("tool_result", ""), + }) + blocked = [ + (r"https://[^\s\"']+@github\.com", "Do not use authenticated GitHub remote URLs in shell commands. Use the configured credential provider or GitHub connector."), + (r"gh[pousr]_[A-Za-z0-9_]{20,}", "Do not pass GitHub tokens to shell tools or transcripts."), + (r"github_pat_[A-Za-z0-9_]{20,}", "GitHub PATs are forbidden. Do not pass personal access tokens to shell tools or transcripts."), + ] + + for pattern, reason in blocked: + if re.search(pattern, tool_payload): + print(json.dumps({"decision": "block", "reason": reason})) + sys.exit(0) + + print(json.dumps({"decision": "allow"})) + maxReflectionCount: 0 + customReflectionNote: '' + commonPrompts: [] + enableVanillaMode: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml new file mode 100644 index 000000000..ea5d59a24 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml @@ -0,0 +1,186 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: benefit-recommendations +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Gets Azure Cost Management benefit recommendations for savings plans and reserved instances + at a billing scope. Use it to identify commitment discount recommendation savings, cost, + term, and break-even details. Available parameters: billing_scope, lookback_period, term. + functionCode: |- + def main(**kwargs): + from urllib.parse import quote + + import requests + + billing_scope = kwargs.get("billing_scope") + lookback_period = kwargs.get("lookback_period") or "Last7Days" + term = kwargs.get("term") or "P3Y" + + result = { + "billing_scope": billing_scope, + "lookback_period": lookback_period, + "term": term, + "recommendations": [], + } + + if not billing_scope: + result["error"] = "billing_scope is required" + return result + + scope = str(billing_scope).strip().strip("/") + filter_expression = ( + f"properties/lookBackPeriod eq '{lookback_period}' " + f"and properties/term eq '{term}'" + ) + url = ( + f"https://management.azure.com/{scope}" + "/providers/Microsoft.CostManagement/benefitRecommendations" + f"?api-version=2025-03-01&$filter={quote(filter_expression, safe='')}" + ) + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token("https://management.azure.com/.default") + payload_items = [] + next_url = url + while next_url: + response = requests.get( + next_url, + headers={"Authorization": f"Bearer {token.token}"}, + timeout=300, + ) + response.raise_for_status() + payload = response.json() + payload_items.extend(payload.get("value", [])) + next_url = payload.get("nextLink") + except Exception as exc: + result["error"] = f"Failed to get Cost Management benefit recommendations: {exc}" + return result + + def _first(*values): + for value in values: + if value is not None: + return value + return None + + def _nested(source, *path): + current = source + for key in path: + if not isinstance(current, dict): + return None + current = current.get(key) + return current + + def _number(value): + if isinstance(value, (int, float)): + return value + try: + return float(value) + except (TypeError, ValueError): + return None + + def _difference(left, right): + left_number = _number(left) + right_number = _number(right) + if left_number is None or right_number is None: + return None + return left_number - right_number + + def _recommendation_type(item, properties): + raw_type = str( + _first( + item.get("kind"), + properties.get("benefitType"), + properties.get("recommendationType"), + "", + ) + ) + normalized = raw_type.lower() + if "reservation" in normalized or "reserved" in normalized: + return "RI" + if "savings" in normalized or "benefit" in normalized: + return "SP" + return raw_type or None + + for item in payload_items: + properties = item.get("properties", {}) if isinstance(item, dict) else {} + recommendation_details = properties.get("recommendationDetails") or {} + if not isinstance(recommendation_details, dict): + recommendation_details = {} + + total_cost = _first( + properties.get("totalCost"), + _nested(recommendation_details, "totalCost"), + ) + cost_without_benefit = properties.get("costWithoutBenefit") + savings = _first( + properties.get("estimatedSavingsAmount"), + properties.get("totalSavings"), + properties.get("savingsAmount"), + properties.get("annualSavingsAmount"), + _nested(recommendation_details, "averageSavingsAmount"), + _nested(recommendation_details, "savingsAmount"), + _difference(cost_without_benefit, total_cost), + ) + cost = _first( + total_cost, + properties.get("costWithBenefit"), + properties.get("recommendedQuantityCost"), + properties.get("purchaseAmount"), + _nested(recommendation_details, "cost"), + _nested(recommendation_details, "costWithBenefit"), + ) + recommendation_term = _first( + properties.get("term"), + _nested(recommendation_details, "term"), + term, + ) + break_even = _first( + properties.get("breakEvenTime"), + properties.get("breakEvenDate"), + properties.get("breakEvenPeriod"), + _nested(recommendation_details, "breakEvenTime"), + _nested(recommendation_details, "breakEvenDate"), + _nested(recommendation_details, "breakEvenPeriod"), + ) + + result["recommendations"].append( + { + "type": _recommendation_type(item, properties), + "savings": savings, + "cost": cost, + "total_cost": total_cost, + "cost_without_benefit": cost_without_benefit, + "term": recommendation_term, + "break_even": break_even, + "id": item.get("id"), + "name": item.get("name"), + } + ) + + result["count"] = len(result["recommendations"]) + return result + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: billing_scope + type: string + description: Azure billing scope or subscription scope to query for benefit recommendations. + required: true + - name: lookback_period + type: string + description: Optional lookback period for benefit recommendations. Defaults to Last7Days. + required: false + - name: term + type: string + description: Optional commitment term for benefit recommendations. Defaults to P3Y. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml new file mode 100644 index 000000000..76d58c0a0 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml @@ -0,0 +1,199 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: capacity-reservation-groups +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Lists Azure capacity reservation groups in a subscription and reports utilization by comparing reserved capacity against allocated virtual machines. Use it to identify unused reserved capacity, overallocated groups, and zone-specific capacity reservation waste. + functionCode: |- + def main(**kwargs): + import requests + + ARM_ENDPOINT = "https://management.azure.com" + ARM_SCOPE = "https://management.azure.com/.default" + API_VERSION = "2024-03-01" + + subscription_id = kwargs.get("subscription_id") + + if not subscription_id: + return { + "error": "subscription_id is required", + "capacity_reservation_groups": [], + } + + def get_attr(obj, *names, default=None): + for name in names: + if isinstance(obj, dict): + if name in obj and obj[name] is not None: + return obj[name] + properties = obj.get("properties") + if isinstance(properties, dict) and name in properties and properties[name] is not None: + return properties[name] + continue + value = getattr(obj, name, None) + if value is not None: + return value + return default + + def as_list(value): + if value is None: + return [] + if isinstance(value, list): + return value + if isinstance(value, (tuple, set)): + return list(value) + return [value] + + def as_int(value): + try: + return int(value or 0) + except (TypeError, ValueError): + return 0 + + def resource_group_from_id(resource_id): + if not resource_id: + return None + parts = [part for part in resource_id.split("/") if part] + for index, part in enumerate(parts): + if part.lower() == "resourcegroups" and index + 1 < len(parts): + return parts[index + 1] + return None + + def subresource_id(item): + return get_attr(item, "id", default=str(item)) + + result = { + "subscription_id": subscription_id, + "capacity_reservation_groups": [], + } + errors = [] + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token(ARM_SCOPE).token + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + except Exception as exc: + result["error"] = f"Failed to initialize Azure ARM credential: {exc}" + return result + + try: + list_url = ( + f"{ARM_ENDPOINT}/subscriptions/{subscription_id}" + "/providers/Microsoft.Compute/capacityReservationGroups" + f"?api-version={API_VERSION}&$expand=virtualMachinesAssociated" + ) + crgs = [] + while list_url: + response = requests.get(list_url, headers=headers, timeout=120) + response.raise_for_status() + payload = response.json() + crgs.extend(payload.get("value", [])) + list_url = payload.get("nextLink") + + for crg in crgs: + name = get_attr(crg, "name", default="") + resource_id = get_attr(crg, "id", default="") + resource_group = resource_group_from_id(resource_id) + location = get_attr(crg, "location", default=None) + zones = as_list(get_attr(crg, "zones", default=[])) + detail = crg + + if resource_group and name: + try: + detail_url = ( + f"{ARM_ENDPOINT}/subscriptions/{subscription_id}/resourceGroups/{resource_group}" + f"/providers/Microsoft.Compute/capacityReservationGroups/{name}" + f"?api-version={API_VERSION}&$expand=instanceView" + ) + detail_response = requests.get(detail_url, headers=headers, timeout=60) + detail_response.raise_for_status() + detail = detail_response.json() + except Exception as exc: + errors.append({ + "name": name, + "resource_group": resource_group, + "error": f"Failed to get instance_view: {exc}", + }) + + instance_view = get_attr(detail, "instance_view", "instanceView") + reservations = as_list(get_attr(instance_view, "capacity_reservations", "capacityReservations", default=[])) + + reserved_count = 0 + allocated_ids = set() + reservation_names = [] + + for reservation in reservations: + reservation_name = get_attr(reservation, "name") + if reservation_name: + reservation_names.append(reservation_name) + + utilization_info = get_attr(reservation, "utilization_info", "utilizationInfo") + reserved_count += as_int(get_attr(utilization_info, "current_capacity", "currentCapacity", default=0)) + + allocated_vms = as_list(get_attr( + utilization_info, + "virtual_machines_allocated", + "virtualMachinesAllocated", + default=[], + )) + for vm in allocated_vms: + vm_id = subresource_id(vm) + if vm_id: + allocated_ids.add(vm_id) + + associated_vms = as_list(get_attr( + detail, + "virtual_machines_associated", + "virtualMachinesAssociated", + default=get_attr(crg, "virtual_machines_associated", "virtualMachinesAssociated", default=[]), + )) + + associated_ids = [subresource_id(vm) for vm in associated_vms if subresource_id(vm)] + allocated_count = len(allocated_ids) + utilization_pct = None + if reserved_count > 0: + utilization_pct = round((allocated_count / reserved_count) * 100, 2) + + result["capacity_reservation_groups"].append({ + "name": name, + "id": resource_id, + "resource_group": resource_group, + "location": location, + "zones": zones, + "zone": ",".join(str(zone) for zone in zones) if zones else None, + "reserved_count": reserved_count, + "allocated_count": allocated_count, + "utilization_pct": utilization_pct, + "waste": reserved_count > allocated_count, + "waste_count": max(reserved_count - allocated_count, 0), + "overallocated": allocated_count > reserved_count if reserved_count > 0 else False, + "capacity_reservations": reservation_names, + "virtual_machines_allocated": sorted(allocated_ids), + "virtual_machines_associated": associated_ids, + }) + except Exception as exc: + result["error"] = f"Failed to list capacity reservation groups: {exc}" + return result + + if errors: + result["errors"] = errors + + return result + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: subscription_id + type: string + description: Azure subscription ID to query for capacity reservation group utilization. + required: true diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml new file mode 100644 index 000000000..9f14e24bb --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml @@ -0,0 +1,454 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: data-freshness-check +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Checks FinOps Hub function data freshness in an Azure Data Explorer hub database + through direct Azure Data Explorer REST queries. This tool is authoritative for + hub data freshness. Access/queryability failures are reported separately from + stale or empty data. Stale memory notes, raw KQL rollups, and ingestion timestamp + checks are superseded when they conflict with this result. + The tool reports row counts, latest data dates, staleness in days, stored-function + schema status, and precise diagnostics for empty or stale datasets. Transactions() + zero rows are reported as a reservationtransactions export / ingestion / stored-function + issue, not as a generic empty result. + functionCode: |- + def main(**kwargs): + from datetime import datetime, timezone + from urllib.parse import urlparse + + import requests + + KUSTO_SCOPE = "https://api.kusto.windows.net/.default" + KUSTO_QUERY_PATH = "/v2/rest/query" + DEFAULT_FRESHNESS_THRESHOLD_DAYS = 3 + + cluster_uri = kwargs.get("cluster_uri") + database = kwargs.get("database") + freshness_threshold_days = kwargs.get("freshness_threshold_days", DEFAULT_FRESHNESS_THRESHOLD_DAYS) + try: + freshness_threshold_days = int(freshness_threshold_days) + except (TypeError, ValueError): + freshness_threshold_days = DEFAULT_FRESHNESS_THRESHOLD_DAYS + + result = { + "cluster_uri": cluster_uri, + "database": database or "hub", + "functions": [], + "total_functions": 0, + "stale_count": 0, + "empty_count": 0, + "error_count": 0, + "queryable_count": 0, + "hub_data_stale": False, + "attention_required": False, + "status": "unknown", + "diagnostics": [], + "freshest_function": None, + "stalest_function": None, + "source_of_truth": { + "tool": "data-freshness-check", + "method": "direct_adx_rest_query", + "endpoint": KUSTO_QUERY_PATH, + "authoritative_function": "Costs()", + "freshness_threshold_days": freshness_threshold_days, + "supersedes": [ + "stale memory conclusions", + "raw KQL freshness rollups", + "Kusto ingestion timestamp checks", + ], + }, + } + + if not cluster_uri: + result["error"] = "cluster_uri is required" + return result + + raw_cluster_uri = str(cluster_uri).strip() + if not raw_cluster_uri.startswith(("https://", "http://")): + raw_cluster_uri = f"https://{raw_cluster_uri}" + + parsed_cluster_uri = urlparse(raw_cluster_uri) + if parsed_cluster_uri.scheme != "https" or not parsed_cluster_uri.netloc: + result["error"] = "cluster_uri must be an HTTPS Azure Data Explorer cluster URI" + return result + + path_database = parsed_cluster_uri.path.strip("/").split("/")[0] if parsed_cluster_uri.path.strip("/") else None + database = database or path_database or "hub" + cluster_uri = f"https://{parsed_cluster_uri.netloc}".rstrip("/") + result["cluster_uri"] = cluster_uri + result["database"] = database + + def _to_utc(value): + if value is None or value == "": + return None + if isinstance(value, datetime): + parsed = value + else: + parsed = datetime.fromisoformat(str(value).replace("Z", "+00:00")) + if parsed.tzinfo is None: + parsed = parsed.replace(tzinfo=timezone.utc) + return parsed.astimezone(timezone.utc) + + def _iso(value): + if value is None: + return None + return value.isoformat().replace("+00:00", "Z") + + def _table_rows(payload): + if isinstance(payload, list): + for frame in payload: + if not isinstance(frame, dict): + continue + frame_type = frame.get("FrameType") or frame.get("frameType") + table_kind = frame.get("TableKind") or frame.get("tableKind") + if frame_type == "DataTable" and table_kind in (None, "PrimaryResult"): + rows = frame.get("Rows") or frame.get("rows") or [] + columns = frame.get("Columns") or frame.get("columns") or [] + column_names = [ + column.get("ColumnName") or column.get("columnName") or column.get("name") + for column in columns + if isinstance(column, dict) + ] + return rows, column_names + return [], [] + + if not isinstance(payload, dict): + return [], [] + + tables = payload.get("Tables") or payload.get("tables") or [] + if not tables: + return [], [] + table = tables[0] + rows = table.get("Rows") or table.get("rows") or [] + columns = table.get("Columns") or table.get("columns") or [] + column_names = [ + column.get("ColumnName") or column.get("columnName") or column.get("name") + for column in columns + if isinstance(column, dict) + ] + return rows, column_names + + def _row_value(row, column_names, name, index): + if isinstance(row, dict): + return row.get(name) + if isinstance(row, (list, tuple)): + if name in column_names: + column_index = column_names.index(name) + if column_index < len(row): + return row[column_index] + if index < len(row): + return row[index] + return None + + def _as_int(value): + if value is None or value == "": + return None + try: + return int(value) + except (TypeError, ValueError): + return None + + def _append_diagnostic(function_name, severity, code, message, recommended_actions=None, verification=None): + diagnostic = { + "function_name": function_name, + "severity": severity, + "code": code, + "message": message, + } + if recommended_actions: + diagnostic["recommended_actions"] = recommended_actions + if verification: + diagnostic["verification"] = verification + result["diagnostics"].append(diagnostic) + return diagnostic + + def _execute_kusto(csl): + response = requests.post( + f"{cluster_uri}{KUSTO_QUERY_PATH}", + headers=headers, + json={"db": database, "csl": csl}, + timeout=120, + ) + response.raise_for_status() + return response.json() + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token(KUSTO_SCOPE).token + headers = { + "Accept": "application/json", + "Authorization": f"Bearer {token}", + "Content-Type": "application/json; charset=utf-8", + "x-ms-app": "FinOpsSreAgentDataFreshnessCheck", + } + except Exception as exc: + result["error"] = f"Failed to initialize Azure Data Explorer REST credential: {exc}" + return result + + now = datetime.now(timezone.utc) + errors = [] + function_checks = [ + { + "function_name": "Costs()", + "source_dataset": "Costs", + "expected_export_dataset": "focuscost", + "query": "Costs() | summarize RowCount=count(), LatestData=max(ChargePeriodStart) | project RowCount, LatestData", + "schema_query": "Costs() | getschema | summarize SchemaColumnCount=count()", + "freshness_column": "LatestData", + "required_for_hub_health": True, + "empty_code": "COSTS_ZERO_ROWS", + "stale_code": "COSTS_STALE", + "empty_message": "Costs() returned zero rows. This is a Hub data blocker, not a successful empty result.", + "empty_actions": [ + "Verify Cost Management cost exports are configured and have recent successful runs.", + "Verify Azure Data Factory ingestion pipelines processed the Costs dataset successfully.", + "Verify the Costs() stored function resolves against the current Hub schema.", + ], + }, + { + "function_name": "Prices()", + "source_dataset": "Prices", + "expected_export_dataset": "pricesheet", + "query": "Prices() | summarize RowCount=count(), LatestData=max(x_EffectivePeriodStart) | project RowCount, LatestData", + "schema_query": "Prices() | getschema | summarize SchemaColumnCount=count()", + "freshness_column": "LatestData", + "required_for_hub_health": False, + "empty_code": "PRICES_ZERO_ROWS", + "stale_code": "PRICES_STALE", + "empty_message": "Prices() returned zero rows. Pricing analysis is unavailable until the pricesheet export and ingestion path are verified.", + "empty_actions": [ + "Verify Cost Management pricesheet exports are configured for supported billing scopes.", + "Verify Azure Data Factory ingestion pipelines processed the Prices dataset successfully.", + "Verify the Prices() stored function resolves against the current Hub schema.", + ], + }, + { + "function_name": "Recommendations()", + "source_dataset": "Recommendations", + "expected_export_dataset": "reservationrecommendations", + "query": "Recommendations() | summarize RowCount=count() | project RowCount", + "schema_query": "Recommendations() | getschema | summarize SchemaColumnCount=count()", + "freshness_column": None, + "required_for_hub_health": False, + "empty_code": "RECOMMENDATIONS_ZERO_ROWS", + "stale_code": "RECOMMENDATIONS_STALE", + "empty_message": "Recommendations() returned zero rows. Recommendation analysis is unavailable until the reservation recommendations export and ingestion path are verified.", + "empty_actions": [ + "Verify Cost Management reservationrecommendations exports are configured for supported billing scopes.", + "Verify Azure Data Factory ingestion pipelines processed the Recommendations dataset successfully.", + "Verify the Recommendations() stored function resolves against the current Hub schema.", + ], + }, + { + "function_name": "Transactions()", + "source_dataset": "Transactions", + "expected_export_dataset": "reservationtransactions", + "query": "Transactions() | extend _IngestionTime = todatetime(column_ifexists('x_IngestionTime', datetime(null))) | summarize RowCount=count(), LatestData=max(ChargePeriodStart), LatestIngestionTime=max(_IngestionTime) | project RowCount, LatestData, LatestIngestionTime", + "schema_query": "Transactions() | getschema | summarize SchemaColumnCount=count()", + "freshness_column": "LatestData", + "required_for_hub_health": False, + "empty_code": "TRANSACTIONS_ZERO_ROWS", + "stale_code": "TRANSACTIONS_STALE", + "empty_message": "Transactions() returned zero rows. The reservation transactions dataset is empty; do not report this as 'no transactions' until export, ingestion, and stored-function behavior are verified.", + "empty_actions": [ + "Verify Cost Management reservationtransactions exports are configured for supported EA or MCA billing scopes.", + "Verify Azure Data Factory ingestion pipelines processed the Transactions dataset successfully.", + "Verify the Transactions() stored function resolves to the current Transactions_v1_2() implementation.", + ], + }, + ] + + for check in function_checks: + function_name = check["function_name"] + latest_data = None + latest_ingestion_time = None + staleness_days = None + is_stale = True + has_data = False + row_count = None + schema_status = "not_checked" + schema_column_count = None + diagnostic_code = "OK" + diagnostic_message = None + schema_error = None + data_error = None + + try: + schema_payload = _execute_kusto(check["schema_query"]) + schema_rows, schema_columns = _table_rows(schema_payload) + if schema_rows: + schema_column_count = _as_int(_row_value(schema_rows[0], schema_columns, "SchemaColumnCount", 0)) + schema_status = "ok" if schema_column_count and schema_column_count > 0 else "empty_schema" + else: + schema_status = "no_schema_rows" + except Exception as exc: + schema_error = str(exc) + schema_status = "error" + errors.append({"function_name": function_name, "phase": "schema", "error": str(exc)}) + diagnostic = _append_diagnostic( + function_name, + "error", + f"{function_name.strip('()').upper()}_SCHEMA_QUERY_FAILED", + f"{function_name} schema verification failed: {exc}", + [ + "If this is HTTP 403, verify the agent identity has ADX AllDatabasesViewer on the cluster.", + "If this is a semantic error, check the Hub version and stored function deployment for this dataset.", + ], + ["Stored-function schema query failed."], + ) + diagnostic_code = diagnostic["code"] + diagnostic_message = diagnostic["message"] + + try: + freshness_payload = _execute_kusto(check["query"]) + freshness_rows, freshness_columns = _table_rows(freshness_payload) + if freshness_rows: + row_count = _as_int(_row_value(freshness_rows[0], freshness_columns, "RowCount", 0)) + has_data = row_count is not None and row_count > 0 + + if check["freshness_column"]: + if freshness_rows: + raw_latest = _row_value(freshness_rows[0], freshness_columns, check["freshness_column"], 1) + latest_data = _to_utc(raw_latest) + latest_ingestion_time = _to_utc(_row_value(freshness_rows[0], freshness_columns, "LatestIngestionTime", 2)) + if latest_data is not None: + staleness_days = round((now - latest_data).total_seconds() / 86400, 2) + is_stale = not has_data or staleness_days is None or staleness_days > freshness_threshold_days + else: + is_stale = not has_data + + if not has_data: + diagnostic = _append_diagnostic( + function_name, + "warning" if not check["required_for_hub_health"] else "error", + check["empty_code"], + check["empty_message"], + check["empty_actions"], + [ + f"{function_name} row count is zero.", + f"{function_name} stored-function schema status: {schema_status}.", + ], + ) + diagnostic_code = diagnostic["code"] + diagnostic_message = diagnostic["message"] + elif staleness_days is not None and staleness_days > freshness_threshold_days: + diagnostic = _append_diagnostic( + function_name, + "warning" if not check["required_for_hub_health"] else "error", + check["stale_code"], + f"{function_name} latest data is {staleness_days} days old, which exceeds the {freshness_threshold_days}-day freshness threshold.", + [ + f"Verify the {check['expected_export_dataset']} export is still running.", + f"Verify Data Factory ingestion processed the {check['source_dataset']} dataset successfully.", + ], + ) + diagnostic_code = diagnostic["code"] + diagnostic_message = diagnostic["message"] + except Exception as exc: + data_error = str(exc) + errors.append({"function_name": function_name, "phase": "data", "error": str(exc)}) + diagnostic = _append_diagnostic( + function_name, + "error", + f"{function_name.strip('()').upper()}_QUERY_FAILED", + f"{function_name} data query failed: {exc}", + [ + "If this is HTTP 403, verify the agent identity has ADX AllDatabasesViewer on the cluster.", + "If this is a semantic error, check the Hub version and stored function compatibility for this dataset.", + ], + ["Data query failed before row count could be verified."], + ) + diagnostic_code = diagnostic["code"] + diagnostic_message = diagnostic["message"] + + result["functions"].append( + { + "function_name": function_name, + "source_dataset": check["source_dataset"], + "expected_export_dataset": check["expected_export_dataset"], + "row_count": row_count, + "latest_data_date": _iso(latest_data), + "latest_ingestion_time": _iso(latest_ingestion_time), + "staleness_days": staleness_days, + "is_stale": is_stale, + "is_queryable": schema_error is None and data_error is None, + "has_data": has_data, + "schema_status": schema_status, + "schema_column_count": schema_column_count, + "schema_error": schema_error, + "data_error": data_error, + "required_for_hub_health": check["required_for_hub_health"], + "diagnostic_code": diagnostic_code, + "diagnostic_message": diagnostic_message, + } + ) + + if check["required_for_hub_health"]: + result["hub_data_stale"] = result["hub_data_stale"] or is_stale + + result["total_functions"] = len(result["functions"]) + result["stale_count"] = sum(1 for function in result["functions"] if function["is_stale"]) + result["empty_count"] = sum(1 for function in result["functions"] if not function["has_data"]) + result["error_count"] = len(errors) + result["queryable_count"] = sum(1 for function in result["functions"] if function["is_queryable"]) + + functions_with_data_dates = [ + function for function in result["functions"] if function["latest_data_date"] is not None + ] + if functions_with_data_dates: + result["freshest_function"] = min(functions_with_data_dates, key=lambda function: function["staleness_days"]) + result["stalest_function"] = max(functions_with_data_dates, key=lambda function: function["staleness_days"]) + + costs_function = next( + (function for function in result["functions"] if function["function_name"] == "Costs()"), + None, + ) + if costs_function: + result["authoritative_freshness_signal"] = { + "function_name": "Costs()", + "latest_data_date": costs_function["latest_data_date"], + "staleness_days": costs_function["staleness_days"], + "is_stale": costs_function["is_stale"], + "has_data": costs_function["has_data"], + "row_count": costs_function["row_count"], + } + + if errors: + result["errors"] = errors + + result["attention_required"] = bool(result["diagnostics"]) + if result["error_count"]: + result["status"] = "error" + elif result["hub_data_stale"]: + result["status"] = "hub_data_stale" + elif result["attention_required"]: + result["status"] = "attention_required" + else: + result["status"] = "healthy" + + return result + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: cluster_uri + type: string + description: Azure Data Explorer cluster URI to query for data freshness. + required: true + - name: database + type: string + description: Optional Azure Data Explorer database name. Defaults to hub. + required: false + - name: freshness_threshold_days + type: integer + description: Optional age threshold for production freshness checks. Defaults to 3 days; use a higher value for eval datasets with intentionally old data. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml new file mode 100644 index 000000000..2da2ead72 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml @@ -0,0 +1,562 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: db-service-quotas +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Reports Azure database service quota usage and regional access signals through ARM REST. + Covers SQL DB regional vCore quota for Azure SQL Database and Data Warehouse. + Covers SQL MI managed instance vCore, per-family, and subnet quota usage. + Covers Cosmos DB subscription account count, per-region account count, and region/AZ access. + Covers PostgreSQL Flexible Server regional access, HA capability, and per-SKU vCore quota. + Covers MySQL Flexible Server regional access and zone-redundant HA capability. + Use include_capabilities for detailed SQL MI hardware family, PostgreSQL, and MySQL capability rows. + Results normalize locations, utilization percentages, at-risk flags, provider errors, and soft skips. + The tool uses Azure ARM REST with DefaultAzureCredential and the agent system-managed identity by default. + Inspired by https://github.com/naspinall-MS/az-quota-helper (MIT). + functionCode: |- + def main(**kwargs): + import re + import requests + + ARM_ENDPOINT = "https://management.azure.com" + ARM_SCOPE = "https://management.azure.com/.default" + LOCATIONS_API_VERSION = "2022-12-01" + SQL_API_VERSION = "2025-01-01" + COSMOS_API_VERSION = "2024-11-15" + PG_CAPABILITIES_API_VERSION = "2024-08-01" + PG_USAGES_API_VERSION = "2025-06-01-preview" + MYSQL_CAPABILITIES_API_VERSION = "2023-12-30" + SERVICE_DISPLAY = { + "SQLDB": "SQL DB", + "SQLMI": "SQL MI", + "COSMOSDB": "Cosmos DB", + "POSTGRESQL": "PostgreSQL Flex", + "MYSQL": "MySQL Flex", + } + ALL_SERVICE_KEYS = ["SQLDB", "SQLMI", "COSMOSDB", "POSTGRESQL", "MYSQL"] + + subscription_id = kwargs.get("subscription_id") + include_capabilities = bool(kwargs.get("include_capabilities")) + + result = { + "subscription_id": subscription_id, + "services": [], + "locations": [], + "quotas": [], + "region_access": [], + "at_risk_count": 0, + "warning_count": 0, + "critical_count": 0, + "errors": [], + "suppressed_error_count": 0, + } + if include_capabilities: + result["capabilities"] = [] + + if not subscription_id: + result["error"] = "subscription_id is required" + result["errors"].append({"kind": "validation", "message": "subscription_id is required"}) + return result + + def normalize_location(value): + return "".join(character for character in str(value or "").lower() if character.isalnum()) + + def parse_locations(value): + if not value: + return [] + if isinstance(value, str): + raw = value.split(",") + elif isinstance(value, (list, tuple, set)): + raw = value + else: + raw = [value] + return [normalize_location(item) for item in raw if normalize_location(item)] + + def parse_services(value): + if value is None or value == "": + return set(ALL_SERVICE_KEYS), [] + if isinstance(value, str): + raw = [item.strip() for item in value.split(",")] + elif isinstance(value, (list, tuple, set)): + raw = [str(item).strip() for item in value] + else: + raw = [str(value).strip()] + tokens = [item.upper().replace(" ", "") for item in raw if item] + if not tokens or "ALL" in tokens: + invalid = [token for token in tokens if token not in set(ALL_SERVICE_KEYS + ["ALL"])] + return set(ALL_SERVICE_KEYS), invalid + invalid = [token for token in tokens if token not in set(ALL_SERVICE_KEYS + ["ALL"])] + return set(tokens) - {"ALL"}, invalid + + selected_services, invalid_services = parse_services(kwargs.get("services", "All")) + if invalid_services: + result["error"] = "Invalid services parameter" + result["errors"].append({ + "kind": "validation", + "message": "Invalid services parameter", + "invalid_services": invalid_services, + "allowed_services": ALL_SERVICE_KEYS + ["ALL"], + }) + return result + + result["services"] = [SERVICE_DISPLAY[key] for key in ALL_SERVICE_KEYS if key in selected_services] + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token(ARM_SCOPE).token + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + except Exception as exc: + result["error"] = f"Failed to initialize Azure ARM credential: {exc}" + result["errors"].append({"kind": "auth", "message": str(exc)}) + return result + + def endpoint(path): + if str(path).startswith("http"): + return path + return f"{ARM_ENDPOINT}{path}" + + def add_error(kind, service, location, url, message, status_code=None, reason=None, suppressed=False): + row = { + "kind": kind, + "service": service, + "location": normalize_location(location) if location else None, + "source_endpoint": url, + "message": message, + } + if status_code is not None: + row["status_code"] = status_code + if reason: + row["reason"] = reason + if suppressed: + row["suppressed"] = True + result["suppressed_error_count"] += 1 + result["errors"].append(row) + + def arm_get(path, service, location=None, suppress_cosmos_locations_5xx=False): + url = endpoint(path) + try: + response = requests.get(url, headers=headers, timeout=60) + except Exception as exc: + add_error("request_failed", service, location, url, str(exc)) + return None + + if response.status_code >= 400: + body = "" + try: + body = response.text or "" + except Exception: + body = "" + if response.status_code == 400 and "NoRegisteredProviderFound" in body: + add_error("provider_not_registered", service, location, url, body[:1000], response.status_code, response.reason, True) + return None + if response.status_code == 404: + add_error("service_not_in_region", service, location, url, body[:1000], response.status_code, response.reason, True) + return None + if suppress_cosmos_locations_5xx and response.status_code >= 500: + add_error("service_not_in_region", service, location, url, body[:1000], response.status_code, response.reason, True) + return None + add_error("http_error", service, location, url, body[:1000], response.status_code, response.reason) + return None + + try: + return response.json() + except Exception as exc: + add_error("json_parse_failed", service, location, url, str(exc)) + return None + + def arm_get_paged(path, service, location=None): + rows = [] + next_url = endpoint(path) + while next_url: + payload = arm_get(next_url, service, location) + if payload is None: + return rows + rows.extend(payload.get("value", [])) + next_url = payload.get("nextLink") + return rows + + def to_float(value): + if value is None: + return None + try: + return float(value) + except (TypeError, ValueError): + return None + + def to_int_or_none(value): + number = to_float(value) + if number is None: + return None + return int(number) + + def first_present(record, keys, default=None): + if not isinstance(record, dict): + return default + for key in keys: + value = record.get(key) + if value is not None: + return value + return default + + def name_value(value): + if isinstance(value, dict): + return value.get("localizedValue") or value.get("localized_value") or value.get("value") or value.get("name") or str(value) + return str(value) if value is not None else "" + + def clean_metric(value): + metric = name_value(value).strip() + metric = re.sub(r"\s+for\s+.*$", "", metric, flags=re.IGNORECASE).strip() + return metric.rstrip(".").strip() + + def add_quota(service, scope, metric, current_value, limit, unit, location, source_endpoint): + current_number = to_float(current_value) + limit_number = to_float(limit) + normalized_limit = int(limit_number) if limit_number is not None else None + available = None + utilization_pct = None + if current_number is not None and limit_number is not None: + available = int(limit_number - current_number) + if limit_number > 0: + utilization_pct = round((current_number / limit_number) * 100, 2) + at_risk_80 = bool(utilization_pct is not None and utilization_pct > 80) + at_risk_95 = bool(utilization_pct is not None and utilization_pct > 95) + if at_risk_80: + result["at_risk_count"] += 1 + if at_risk_80 and not at_risk_95: + result["warning_count"] += 1 + if at_risk_95: + result["critical_count"] += 1 + result["quotas"].append({ + "service": service, + "scope": scope, + "metric": metric, + "current_value": current_value, + "limit": normalized_limit, + "available": available, + "utilization_pct": utilization_pct, + "unit": unit, + "location": normalize_location(location) if location else None, + "at_risk_80": at_risk_80, + "at_risk_95": at_risk_95, + "source_endpoint": source_endpoint, + }) + + def add_region_access(service, location, region_allowed, az_allowed, notes, supports_availability_zone, source_endpoint): + if isinstance(notes, (list, tuple)): + note_text = "; ".join([str(note) for note in notes if note]) + else: + note_text = str(notes or "") + result["region_access"].append({ + "service": service, + "location": normalize_location(location), + "access_allowed_for_region": bool(region_allowed), + "access_allowed_for_az": az_allowed, + "notes": note_text, + "supports_availability_zone": supports_availability_zone, + "source_endpoint": source_endpoint, + }) + + locations_payload = arm_get( + f"/subscriptions/{subscription_id}/locations?api-version={LOCATIONS_API_VERSION}", + "Azure Resource Manager", + ) + region_has_az = {} + subscription_locations = [] + if locations_payload: + for item in locations_payload.get("value", []): + loc_name = normalize_location(item.get("name") or item.get("displayName")) + if not loc_name: + continue + subscription_locations.append(loc_name) + mappings = item.get("availabilityZoneMappings") or [] + region_has_az[loc_name] = bool(mappings) + + requested_locations = parse_locations(kwargs.get("location")) + if requested_locations: + locations = requested_locations + else: + locations = subscription_locations + result["locations"] = locations + if not locations: + result["error"] = "location did not contain any valid region names and subscription locations could not be enumerated" + result["errors"].append({"kind": "validation", "message": result["error"]}) + return result + + def sql_region_capabilities(location): + path = f"/subscriptions/{subscription_id}/providers/Microsoft.Sql/locations/{location}/capabilities?api-version={SQL_API_VERSION}" + url = endpoint(path) + payload = arm_get(path, "SQL", location) + if payload is None: + return + root_properties = payload.get("properties", payload) + region_available = root_properties.get("status") == "Available" or payload.get("status") == "Available" + mi_families = [] + versions = root_properties.get("supportedManagedInstanceVersions") or payload.get("supportedManagedInstanceVersions") or [] + for version in versions: + for edition in version.get("supportedEditions", []) or []: + for family in edition.get("supportedFamilies", []) or []: + family_name = family.get("name") or family.get("family") or family.get("hardwareFamily") or "Unknown" + zone_redundant = bool(family.get("zoneRedundant")) + mi_families.append({"family": family_name, "zone_redundant": zone_redundant}) + if include_capabilities: + result.setdefault("capabilities", []).append({ + "service": "SQL MI", + "location": normalize_location(location), + "hardware_family": family_name, + "zone_redundant": zone_redundant, + "edition": edition.get("name"), + "version": version.get("name"), + "source_endpoint": url, + }) + if "SQLDB" in selected_services: + notes = [] if region_available else ["SQL region status is not Available"] + notes.append("AZ access data not yet available for SQL DB") + add_region_access("SQL DB", location, region_available, "N/A", notes, None, url) + if "SQLMI" in selected_services: + zr_count = sum(1 for family in mi_families if family["zone_redundant"]) + family_count = len(mi_families) + notes = [] + if not region_available: + az_flag = False + notes.append("SQL region status is not Available") + elif not region_has_az.get(normalize_location(location), False): + az_flag = "AZNotSupported" + notes.append("Region does not advertise availability zones") + elif family_count > 0 and zr_count == family_count: + az_flag = True + notes.append("All SQL MI hardware families report zone redundancy") + elif zr_count > 0: + az_flag = "Partial" + notes.append("Some SQL MI hardware families report zone redundancy") + else: + az_flag = False + notes.append("No SQL MI hardware families report zone redundancy") + add_region_access("SQL MI", location, region_available, az_flag, notes, region_has_az.get(normalize_location(location), None), url) + + def collect_sql_db_quota(location): + path = f"/subscriptions/{subscription_id}/providers/Microsoft.Sql/locations/{location}/usages/RegionalVCoreQuotaForSQLDBAndDW?api-version={SQL_API_VERSION}" + url = endpoint(path) + payload = arm_get(path, "SQL DB", location) + if payload is None: + return + items = payload.get("value") if isinstance(payload.get("value"), list) else [payload] + for item in items: + props = item.get("properties", item) + metric = clean_metric(props.get("displayName") or item.get("displayName") or item.get("name")) + add_quota("SQL DB", f"Region ({normalize_location(location)})", metric, props.get("currentValue"), props.get("limit"), props.get("unit"), location, url) + + def collect_sql_mi_quotas(location): + path = f"/subscriptions/{subscription_id}/providers/Microsoft.Sql/locations/{location}/usages?api-version={SQL_API_VERSION}" + url = endpoint(path) + payload = arm_get(path, "SQL MI", location) + if payload is None: + return + for item in payload.get("value", []): + props = item.get("properties", item) + raw_name = name_value(item.get("name") or props.get("name")) + display_name = clean_metric(props.get("displayName") or raw_name) + include = bool(re.search(r"ManagedInstance|SqlMI|SubnetFor", raw_name, flags=re.IGNORECASE)) or display_name in ["VCore Quota", "Subnet Quota"] + if not include or re.search(r"Free", raw_name, flags=re.IGNORECASE): + continue + add_quota("SQL MI", f"Region ({normalize_location(location)})", display_name, props.get("currentValue"), props.get("limit"), props.get("unit"), location, url) + + cosmos_locations_cache = None + cosmos_accounts_cache = None + + def get_cosmos_locations(): + nonlocal cosmos_locations_cache + if cosmos_locations_cache is not None: + return cosmos_locations_cache + path = f"/subscriptions/{subscription_id}/providers/Microsoft.DocumentDB/locations?api-version={COSMOS_API_VERSION}" + payload = arm_get(path, "Cosmos DB", suppress_cosmos_locations_5xx=True) + cosmos_locations_cache = payload.get("value", []) if payload else [] + return cosmos_locations_cache + + def get_cosmos_accounts(): + nonlocal cosmos_accounts_cache + if cosmos_accounts_cache is not None: + return cosmos_accounts_cache + path = f"/subscriptions/{subscription_id}/providers/Microsoft.DocumentDB/databaseAccounts?api-version={COSMOS_API_VERSION}" + cosmos_accounts_cache = arm_get_paged(path, "Cosmos DB") + return cosmos_accounts_cache + + def collect_cosmos(location): + loc_endpoint = endpoint(f"/subscriptions/{subscription_id}/providers/Microsoft.DocumentDB/locations?api-version={COSMOS_API_VERSION}") + matched = None + for item in get_cosmos_locations(): + item_id = item.get("id", "") + item_loc = item_id.split("/locations/")[-1] if "/locations/" in item_id else item.get("name") + if normalize_location(item_loc) == normalize_location(location): + matched = item + break + if matched: + props = matched.get("properties", {}) + supports_az = props.get("supportsAvailabilityZone") + region_allowed = bool(props.get("isSubscriptionRegionAccessAllowedForRegular")) + az_allowed_raw = props.get("isSubscriptionRegionAccessAllowedForAz") + notes = [] + if not region_allowed: + notes.append("Subscription regular region access is blocked") + if supports_az is False: + az_allowed = "AZNotSupported" + notes.append("Cosmos DB does not support availability zones in this region") + else: + az_allowed = bool(az_allowed_raw) + if not az_allowed: + notes.append("Subscription AZ access is blocked") + add_region_access("Cosmos DB", location, region_allowed, az_allowed, notes, supports_az, loc_endpoint) + else: + add_error("service_not_in_region", "Cosmos DB", location, loc_endpoint, "Cosmos DB location metadata was not found", suppressed=True) + + def collect_cosmos_quotas(): + accounts = get_cosmos_accounts() + accounts_endpoint = endpoint(f"/subscriptions/{subscription_id}/providers/Microsoft.DocumentDB/databaseAccounts?api-version={COSMOS_API_VERSION}") + add_quota("Cosmos DB", "Subscription", "Total Database Accounts (default soft limit: 50)", len(accounts), 50, "Count", None, accounts_endpoint) + for location in locations: + count = 0 + for account in accounts: + props = account.get("properties", {}) + account_locations = props.get("locations") or [] + if any(normalize_location(item.get("locationName")) == normalize_location(location) for item in account_locations): + count += 1 + elif normalize_location(account.get("location")) == normalize_location(location): + count += 1 + add_quota("Cosmos DB", f"Region ({normalize_location(location)})", "Database Accounts in Region", count, None, "Count", location, accounts_endpoint) + + def collect_postgresql_capabilities(location): + path = f"/subscriptions/{subscription_id}/providers/Microsoft.DBforPostgreSQL/locations/{location}/capabilities?api-version={PG_CAPABILITIES_API_VERSION}" + url = endpoint(path) + payload = arm_get(path, "PostgreSQL Flex", location) + if payload is None: + return + caps = payload.get("value", []) + flex = next((item for item in caps if item.get("name") == "FlexibleServerCapabilities"), None) + if not flex: + add_region_access("PostgreSQL Flex", location, False, False, "FlexibleServerCapabilities not found", region_has_az.get(normalize_location(location), None), url) + return + props = flex.get("properties", flex) + restricted = props.get("restricted") == "Enabled" or flex.get("restricted") == "Enabled" + zr_supported = props.get("zoneRedundantHaSupported") == "Enabled" or flex.get("zoneRedundantHaSupported") == "Enabled" + notes = [] + if restricted: + notes.append("Region is restricted") + az_flag = False + elif not region_has_az.get(normalize_location(location), False): + notes.append("Region does not advertise availability zones") + az_flag = "AZNotSupported" + else: + az_flag = bool(zr_supported) + if not zr_supported: + notes.append("Zone redundant HA is not enabled") + add_region_access("PostgreSQL Flex", location, not restricted, az_flag, notes, region_has_az.get(normalize_location(location), None), url) + if include_capabilities: + result.setdefault("capabilities", []).append({ + "service": "PostgreSQL Flex", + "location": normalize_location(location), + "geoBackupSupported": first_present(props, ["geoBackupSupported", "geoBackupSupportedByDefault"]), + "zoneRedundantHaSupported": first_present(props, ["zoneRedundantHaSupported"]), + "zoneRedundantHaAndGeoBackupSupported": first_present(props, ["zoneRedundantHaAndGeoBackupSupported"]), + "onlineResizeSupported": first_present(props, ["onlineResizeSupported"]), + "storageAutoGrowthSupported": first_present(props, ["storageAutoGrowthSupported"]), + "source_endpoint": url, + }) + + def collect_postgresql_quotas(location): + path = f"/subscriptions/{subscription_id}/providers/Microsoft.DBforPostgreSQL/locations/{location}/resourceType/flexibleServers/usages?api-version={PG_USAGES_API_VERSION}" + url = endpoint(path) + for item in arm_get_paged(path, "PostgreSQL Flex", location): + metric = name_value(item.get("name")) + add_quota("PostgreSQL Flex", f"Region ({normalize_location(location)})", metric, item.get("currentValue"), item.get("limit"), item.get("unit"), location, url) + + def collect_mysql_capabilities(location): + path = f"/subscriptions/{subscription_id}/providers/Microsoft.DBforMySQL/locations/{location}/capabilities?api-version={MYSQL_CAPABILITIES_API_VERSION}" + url = endpoint(path) + payload = arm_get(path, "MySQL Flex", location) + if payload is None: + return + caps = payload.get("value", []) + if not caps: + add_region_access("MySQL Flex", location, False, False, "No MySQL Flexible Server capabilities returned; region may be restricted", region_has_az.get(normalize_location(location), None), url) + return + zr_supported = False + for item in caps: + props = item.get("properties", item) + ha_modes = props.get("supportedHAMode") or item.get("supportedHAMode") or [] + if isinstance(ha_modes, str): + ha_modes = [ha_modes] + if any("ZoneRedundant" in str(mode) for mode in ha_modes): + zr_supported = True + if include_capabilities: + zones = props.get("supportedZones") or props.get("supportedAvailabilityZones") or [props.get("zone")] + zones = [zone for zone in zones if zone] + if not zones: + zones = [None] + for zone in zones: + result.setdefault("capabilities", []).append({ + "service": "MySQL Flex", + "location": normalize_location(location), + "zone": zone, + "supportedHAMode": ha_modes, + "geoBackupSupported": first_present(props, ["geoBackupSupported", "geoBackupSupport"]), + "source_endpoint": url, + }) + notes = [] + if not region_has_az.get(normalize_location(location), False): + az_flag = "AZNotSupported" + notes.append("Region does not advertise availability zones") + else: + az_flag = bool(zr_supported) + if not zr_supported: + notes.append("ZoneRedundant HA mode is not advertised") + add_region_access("MySQL Flex", location, True, az_flag, notes, region_has_az.get(normalize_location(location), None), url) + + for location in locations: + if "SQLDB" in selected_services or "SQLMI" in selected_services: + sql_region_capabilities(location) + if "SQLDB" in selected_services: + collect_sql_db_quota(location) + if "SQLMI" in selected_services: + collect_sql_mi_quotas(location) + if "COSMOSDB" in selected_services: + collect_cosmos(location) + if "POSTGRESQL" in selected_services: + collect_postgresql_capabilities(location) + collect_postgresql_quotas(location) + if "MYSQL" in selected_services: + collect_mysql_capabilities(location) + + if "COSMOSDB" in selected_services: + collect_cosmos_quotas() + + return result + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: subscription_id + type: string + description: Azure subscription ID to query for database service quotas and access. + required: true + - name: location + type: string + description: Optional comma-separated or single Azure region. If omitted, all ARM subscription locations are enumerated. + required: false + - name: services + type: string + description: Optional comma-separated subset of SqlDB, SqlMI, CosmosDB, PostgreSQL, MySQL, or All. Defaults to All. + required: false + - name: include_capabilities + type: boolean + description: Include SQL MI hardware-family ZR detail, PostgreSQL/MySQL HA modes, and geo-backup capability rows. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml new file mode 100644 index 000000000..730a35195 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml @@ -0,0 +1,114 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: deploy-anomaly-alert +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Creates or updates a Cost Management scheduled action for anomaly detection + in a subscription and sends anomaly alert notifications to email recipients. + functionCode: |- + def main(**kwargs): + import re + import requests + + subscription_id = kwargs.get("subscription_id") + email_recipients = kwargs.get("email_recipients") + scheduled_action_name = kwargs.get("scheduled_action_name") or "cost-anomaly-alert" + guid_pattern = r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + email_pattern = r"^[^@\s]+@[^@\s]+\.[^@\s]+$" + + if not subscription_id: + return {"status": "failed", "error": "subscription_id is required"} + if not isinstance(subscription_id, str) or not re.match(guid_pattern, subscription_id): + return {"status": "failed", "error": "subscription_id must be a valid GUID"} + if not email_recipients: + return {"status": "failed", "error": "email_recipients is required"} + + if isinstance(email_recipients, str): + recipients = [item.strip() for item in email_recipients.split(",") if item.strip()] + else: + recipients = [str(item).strip() for item in email_recipients if str(item).strip()] + if not recipients: + return {"status": "failed", "error": "email_recipients must contain at least one email"} + invalid_emails = [email for email in recipients if not re.match(email_pattern, email)] + if invalid_emails: + return {"status": "failed", "error": f"invalid email address: {invalid_emails[0]}"} + + body = { + "kind": "InsightAlert", + "properties": { + "displayName": "Cost anomaly alert", + "status": "Enabled", + "viewId": ( + f"/subscriptions/{subscription_id}/providers/Microsoft.CostManagement/" + "views/ms:DailyAnomalyByResourceGroup" + ), + "schedule": { + "frequency": "Daily", + "hourOfDay": 8, + "daysOfWeek": [], + "weeksOfMonth": [], + }, + "notification": { + "subject": "Azure cost anomaly detected", + "to": recipients, + "language": "en-us", + }, + }, + } + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token("https://management.azure.com/.default").token + except Exception as exc: + return {"status": "failed", "error": f"failed to acquire Azure credential: {exc}"} + url = ( + f"https://management.azure.com/subscriptions/{subscription_id}" + f"/providers/Microsoft.CostManagement/scheduledActions/{scheduled_action_name}" + "?api-version=2022-10-01" + ) + try: + response = requests.put( + url, + headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"}, + json=body, + timeout=120, + ) + except Exception as exc: + return {"status": "failed", "error": f"anomaly alert PUT request failed: {exc}"} + + result = { + "subscription_id": subscription_id, + "scheduled_action_name": scheduled_action_name, + "email_recipients": recipients, + "status_code": response.status_code, + } + try: + result["anomaly_alert"] = response.json() + except ValueError: + result["response_text"] = response.text + if response.status_code in (200, 201): + result["status"] = "created" if response.status_code == 201 else "updated" + else: + result["status"] = "failed" + result["error"] = response.text + return result + timeoutSeconds: 240 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: subscription_id + type: string + description: Azure subscription ID where the anomaly alert scheduled action will be created. + required: true + - name: email_recipients + type: string + description: Comma-separated email recipients for anomaly notifications. + required: true diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml new file mode 100644 index 000000000..6252d84c8 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml @@ -0,0 +1,176 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: deploy-budget +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Creates or updates a subscription-level Azure Cost Management budget. + Uses ARM REST to PUT Microsoft.Consumption/budgets with notification + contact emails for budget coverage remediation. + functionCode: |- + def main(**kwargs): + from datetime import date + import re + import requests + + subscription_id = kwargs.get("subscription_id") + budget_name = kwargs.get("budget_name") or "SubscriptionBudget" + amount = kwargs.get("amount") + time_grain = kwargs.get("time_grain") or "Monthly" + contact_emails = kwargs.get("contact_emails") + guid_pattern = r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + email_pattern = r"^[^@\s]+@[^@\s]+\.[^@\s]+$" + + if not subscription_id: + return {"status": "failed", "error": "subscription_id is required"} + if not isinstance(subscription_id, str) or not re.match(guid_pattern, subscription_id): + return {"status": "failed", "error": "subscription_id must be a valid GUID"} + if amount is None or str(amount).strip() == "": + return {"status": "failed", "error": "amount is required"} + if time_grain not in ["Monthly", "Quarterly", "Annually"]: + return {"status": "failed", "error": "time_grain must be one of Monthly, Quarterly, or Annually"} + if not contact_emails: + return {"status": "failed", "error": "contact_emails is required"} + + if isinstance(contact_emails, str): + emails = [item.strip() for item in contact_emails.split(",") if item.strip()] + else: + emails = [str(item).strip() for item in contact_emails if str(item).strip()] + if not emails: + return {"status": "failed", "error": "contact_emails must contain at least one email"} + invalid_emails = [email for email in emails if not re.match(email_pattern, email)] + if invalid_emails: + return {"status": "failed", "error": f"invalid email address: {invalid_emails[0]}"} + + try: + amount_number = float(amount) + except (TypeError, ValueError): + return {"status": "failed", "error": "amount must be numeric"} + if amount_number <= 0: + return {"status": "failed", "error": "amount must be greater than 0"} + + today = date.today() + next_month = today.month + 1 + year = today.year + (1 if next_month == 13 else 0) + month = 1 if next_month == 13 else next_month + start_date = date(year, month, 1) + end_date = date(year + 1, month, 1) + + body = { + "properties": { + "category": "Cost", + "amount": amount_number, + "timeGrain": time_grain, + "timePeriod": { + "startDate": start_date.isoformat(), + "endDate": end_date.isoformat(), + }, + "notifications": { + "Actual_GreaterThan_50_Percent": { + "enabled": True, + "operator": "GreaterThan", + "threshold": 50, + "thresholdType": "Actual", + "contactEmails": emails, + "contactRoles": ["Owner", "Contributor"], + }, + "Actual_GreaterThan_75_Percent": { + "enabled": True, + "operator": "GreaterThan", + "threshold": 75, + "thresholdType": "Actual", + "contactEmails": emails, + "contactRoles": ["Owner", "Contributor"], + }, + "Actual_GreaterThan_90_Percent": { + "enabled": True, + "operator": "GreaterThan", + "threshold": 90, + "thresholdType": "Actual", + "contactEmails": emails, + "contactRoles": ["Owner", "Contributor"], + }, + "Forecasted_GreaterThan_100_Percent": { + "enabled": True, + "operator": "GreaterThan", + "threshold": 100, + "thresholdType": "Forecasted", + "contactEmails": emails, + "contactRoles": ["Owner", "Contributor"], + }, + }, + } + } + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token("https://management.azure.com/.default").token + except Exception as exc: + return {"status": "failed", "error": f"failed to acquire Azure credential: {exc}"} + url = ( + f"https://management.azure.com/subscriptions/{subscription_id}" + f"/providers/Microsoft.Consumption/budgets/{budget_name}" + "?api-version=2023-11-01" + ) + try: + response = requests.put( + url, + headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"}, + json=body, + timeout=120, + ) + except Exception as exc: + return {"status": "failed", "error": f"budget PUT request failed: {exc}"} + + result = { + "subscription_id": subscription_id, + "budget_name": budget_name, + "amount": amount_number, + "time_grain": time_grain, + "contact_emails": emails, + "status_code": response.status_code, + } + try: + result["budget"] = response.json() + except ValueError: + result["response_text"] = response.text + + if response.status_code in (200, 201): + result["status"] = "created" if response.status_code == 201 else "updated" + else: + result["status"] = "failed" + result["error"] = response.text + return result + timeoutSeconds: 240 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: subscription_id + type: string + description: Azure subscription ID where the budget will be created or updated. + required: true + - name: budget_name + type: string + description: |- + Budget name. Default: SubscriptionBudget. + required: false + - name: amount + type: string + description: Budget amount in the subscription billing currency. + required: true + - name: time_grain + type: string + description: |- + Budget reset period, such as Monthly, Quarterly, or Annually. Default: Monthly. + required: false + - name: contact_emails + type: string + description: Comma-separated email addresses that receive budget notifications. + required: true diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml new file mode 100644 index 000000000..830e1bec6 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml @@ -0,0 +1,153 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: deploy-bulk-anomaly-alerts +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Discovers enabled subscriptions in a management group with Azure Resource Graph + and creates or updates Cost Management anomaly alert scheduled actions per subscription. + functionCode: |- + def main(**kwargs): + import re + import requests + + ARM_ENDPOINT = "https://management.azure.com" + GRAPH_API_VERSION = "2022-10-01" + + management_group = kwargs.get("management_group") + email_recipients = kwargs.get("email_recipients") + scheduled_action_name = kwargs.get("scheduled_action_name") or "cost-anomaly-alert" + guid_pattern = r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + email_pattern = r"^[^@\s]+@[^@\s]+\.[^@\s]+$" + + if not isinstance(management_group, str) or not management_group.strip(): + return {"status": "failed", "error": "management_group is required", "deployments": []} + if not email_recipients: + return {"status": "failed", "error": "email_recipients is required", "deployments": []} + management_group = management_group.strip() + + if isinstance(email_recipients, str): + recipients = [item.strip() for item in email_recipients.split(",") if item.strip()] + else: + recipients = [str(item).strip() for item in email_recipients if str(item).strip()] + if not recipients: + return {"status": "failed", "error": "email_recipients must contain at least one email", "deployments": []} + invalid_emails = [email for email in recipients if not re.match(email_pattern, email)] + if invalid_emails: + return {"status": "failed", "error": f"invalid email address: {invalid_emails[0]}", "deployments": []} + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token("https://management.azure.com/.default").token + except Exception as exc: + return {"status": "failed", "error": f"failed to acquire Azure credential: {exc}", "deployments": []} + headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} + + query = ( + "ResourceContainers " + "| where type =~ 'microsoft.resources/subscriptions' " + "| where properties.state =~ 'Enabled' " + "| project subscriptionId, name" + ) + graph_url = f"{ARM_ENDPOINT}/providers/Microsoft.ResourceGraph/resources?api-version={GRAPH_API_VERSION}" + subscriptions = [] + skip = 0 + page_size = 1000 + while True: + body = { + "managementGroups": [management_group], + "query": query, + "options": {"$top": page_size, "$skip": skip}, + } + try: + response = requests.post(graph_url, headers=headers, json=body, timeout=60) + response.raise_for_status() + payload = response.json() + except Exception as exc: + return {"status": "failed", "error": f"Resource Graph query failed: {exc}", "deployments": []} + rows = payload.get("data", []) + subscriptions.extend(rows) + if len(rows) < page_size: + break + skip += page_size + + deployments = [] + for sub in subscriptions: + subscription_id = sub.get("subscriptionId") or sub.get("subscription_id") + subscription_name = sub.get("name") + if not subscription_id: + continue + if not isinstance(subscription_id, str) or not re.match(guid_pattern, subscription_id): + deployments.append({ + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "scheduled_action_name": scheduled_action_name, + "status": "failed", + "error": "subscription_id must be a valid GUID", + }) + continue + + body = { + "kind": "InsightAlert", + "properties": { + "displayName": "Cost anomaly alert", + "status": "Enabled", + "viewId": ( + f"/subscriptions/{subscription_id}/providers/Microsoft.CostManagement/" + "views/ms:DailyAnomalyByResourceGroup" + ), + "schedule": {"frequency": "Daily", "hourOfDay": 8, "daysOfWeek": [], "weeksOfMonth": []}, + "notification": {"subject": "Azure cost anomaly detected", "to": recipients, "language": "en-us"}, + }, + } + url = ( + f"https://management.azure.com/subscriptions/{subscription_id}" + f"/providers/Microsoft.CostManagement/scheduledActions/{scheduled_action_name}" + "?api-version=2022-10-01" + ) + try: + put_response = requests.put(url, headers=headers, json=body, timeout=120) + deployments.append({ + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "scheduled_action_name": scheduled_action_name, + "status": "created" if put_response.status_code == 201 else "updated" if put_response.status_code == 200 else "failed", + "status_code": put_response.status_code, + "error": None if put_response.status_code in (200, 201) else put_response.text, + }) + except Exception as exc: + deployments.append({ + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "scheduled_action_name": scheduled_action_name, + "status": "failed", + "error": str(exc), + }) + + return { + "management_group": management_group, + "email_recipients": recipients, + "subscription_count": len(subscriptions), + "created_or_updated": sum(1 for item in deployments if item["status"] in ("created", "updated")), + "failed": sum(1 for item in deployments if item["status"] == "failed"), + "deployments": deployments, + } + timeoutSeconds: 600 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: management_group + type: string + description: Management group ID used to discover enabled subscriptions. + required: true + - name: email_recipients + type: string + description: Comma-separated email recipients for anomaly alert notifications. + required: true diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml new file mode 100644 index 000000000..af1179247 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml @@ -0,0 +1,202 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: deploy-bulk-budgets +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Discovers enabled subscriptions in a management group with Azure Resource Graph + and creates or updates a Cost Management budget in each subscription. + functionCode: |- + def main(**kwargs): + from datetime import date + import re + import requests + + ARM_ENDPOINT = "https://management.azure.com" + GRAPH_API_VERSION = "2022-10-01" + + management_group = kwargs.get("management_group") + amount = kwargs.get("amount") + contact_emails = kwargs.get("contact_emails") + budget_name = kwargs.get("budget_name") or "SubscriptionBudget" + time_grain = kwargs.get("time_grain") or "Monthly" + email_pattern = r"^[^@\s]+@[^@\s]+\.[^@\s]+$" + + if not isinstance(management_group, str) or not management_group.strip(): + return {"status": "failed", "error": "management_group is required", "deployments": []} + if amount is None or str(amount).strip() == "": + return {"status": "failed", "error": "amount is required", "deployments": []} + if time_grain not in ["Monthly", "Quarterly", "Annually"]: + return {"status": "failed", "error": "time_grain must be one of Monthly, Quarterly, or Annually", "deployments": []} + if not contact_emails: + return {"status": "failed", "error": "contact_emails is required", "deployments": []} + management_group = management_group.strip() + + if isinstance(contact_emails, str): + emails = [item.strip() for item in contact_emails.split(",") if item.strip()] + else: + emails = [str(item).strip() for item in contact_emails if str(item).strip()] + if not emails: + return {"status": "failed", "error": "contact_emails must contain at least one email", "deployments": []} + invalid_emails = [email for email in emails if not re.match(email_pattern, email)] + if invalid_emails: + return {"status": "failed", "error": f"invalid email address: {invalid_emails[0]}", "deployments": []} + + try: + amount_number = float(amount) + except (TypeError, ValueError): + return {"status": "failed", "error": "amount must be numeric", "deployments": []} + if amount_number <= 0: + return {"status": "failed", "error": "amount must be greater than 0", "deployments": []} + + today = date.today() + next_month = today.month + 1 + year = today.year + (1 if next_month == 13 else 0) + month = 1 if next_month == 13 else next_month + start_date = date(year, month, 1) + end_date = date(year + 1, month, 1) + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token("https://management.azure.com/.default").token + except Exception as exc: + return {"status": "failed", "error": f"failed to acquire Azure credential: {exc}", "deployments": []} + headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} + + query = ( + "ResourceContainers " + "| where type =~ 'microsoft.resources/subscriptions' " + "| where properties.state =~ 'Enabled' " + "| project subscriptionId, name" + ) + graph_url = f"{ARM_ENDPOINT}/providers/Microsoft.ResourceGraph/resources?api-version={GRAPH_API_VERSION}" + subscriptions = [] + skip = 0 + page_size = 1000 + while True: + body = { + "managementGroups": [management_group], + "query": query, + "options": {"$top": page_size, "$skip": skip}, + } + try: + response = requests.post(graph_url, headers=headers, json=body, timeout=60) + response.raise_for_status() + payload = response.json() + except Exception as exc: + return {"status": "failed", "error": f"Resource Graph query failed: {exc}", "deployments": []} + rows = payload.get("data", []) + subscriptions.extend(rows) + if len(rows) < page_size: + break + skip += page_size + + budget_body = { + "properties": { + "category": "Cost", + "amount": amount_number, + "timeGrain": time_grain, + "timePeriod": {"startDate": start_date.isoformat(), "endDate": end_date.isoformat()}, + "notifications": { + "Actual_GreaterThan_80_Percent": { + "enabled": True, + "operator": "GreaterThan", + "threshold": 80, + "thresholdType": "Actual", + "contactEmails": emails, + "contactRoles": ["Owner", "Contributor"], + }, + "Forecasted_GreaterThan_100_Percent": { + "enabled": True, + "operator": "GreaterThan", + "threshold": 100, + "thresholdType": "Forecasted", + "contactEmails": emails, + "contactRoles": ["Owner", "Contributor"], + }, + }, + } + } + + deployments = [] + for sub in subscriptions: + subscription_id = sub.get("subscriptionId") or sub.get("subscription_id") + subscription_name = sub.get("name") + if not subscription_id: + continue + if not isinstance(subscription_id, str) or not re.match(guid_pattern, subscription_id): + deployments.append({ + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "budget_name": budget_name, + "status": "failed", + "error": "subscription_id must be a valid GUID", + }) + continue + url = ( + f"https://management.azure.com/subscriptions/{subscription_id}" + f"/providers/Microsoft.Consumption/budgets/{budget_name}" + "?api-version=2023-11-01" + ) + try: + put_response = requests.put(url, headers=headers, json=budget_body, timeout=120) + deployments.append({ + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "budget_name": budget_name, + "status": "created" if put_response.status_code == 201 else "updated" if put_response.status_code == 200 else "failed", + "status_code": put_response.status_code, + "error": None if put_response.status_code in (200, 201) else put_response.text, + }) + except Exception as exc: + deployments.append({ + "subscription_id": subscription_id, + "subscription_name": subscription_name, + "budget_name": budget_name, + "status": "failed", + "error": str(exc), + }) + + return { + "management_group": management_group, + "budget_name": budget_name, + "amount": amount_number, + "contact_emails": emails, + "subscription_count": len(subscriptions), + "created_or_updated": sum(1 for item in deployments if item["status"] in ("created", "updated")), + "failed": sum(1 for item in deployments if item["status"] == "failed"), + "deployments": deployments, + } + timeoutSeconds: 600 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: management_group + type: string + description: Management group ID used to discover enabled subscriptions. + required: true + - name: amount + type: string + description: Budget amount to apply to each subscription. + required: true + - name: contact_emails + type: string + description: Comma-separated email addresses that receive budget notifications. + required: true + - name: budget_name + type: string + description: |- + Budget name. Default: SubscriptionBudget. + required: false + - name: time_grain + type: string + description: |- + Budget reset period, such as Monthly, Quarterly, or Annually. Default: Monthly. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml new file mode 100644 index 000000000..724553530 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml @@ -0,0 +1,505 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: non-compute-quotas +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Checks non-compute Azure service quota utilization for a subscription. + The tool uses ARM provider usages APIs where Azure exposes service-specific + usage and quota payloads, and only falls back to Azure Resource Graph counts + with clearly marked estimated limits for services without a direct usages API. + Network Watcher 1/1 entries are returned as suppressed Azure defaults, not + actionable quota risk. + functionCode: |- + def main(**kwargs): + import requests + + ARM_ENDPOINT = "https://management.azure.com" + ARM_SCOPE = "https://management.azure.com/.default" + + subscription_id = kwargs.get("subscription_id") + location = kwargs.get("location") + + result = { + "subscription_id": subscription_id, + "services": [], + "quotas": [], + "at_risk_count": 0, + "api_reported_limit_count": 0, + "estimated_limit_count": 0, + "suppressed_count": 0, + } + + if not subscription_id: + result["error"] = "subscription_id is required" + return result + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token("https://management.azure.com/.default").token + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + except Exception as exc: + result["error"] = f"Failed to initialize Azure ARM credential: {exc}" + return result + + estimated_services = [ + { + "service_name": "App Service plans", + "resource_type": "microsoft.web/serverfarms", + "arm_resource_type": "Microsoft.Web/serverfarms", + "estimated_limit": 1000, + "limit_note": "Estimated subscription-level default from Azure service limits documentation; no direct provider usages API was used for this resource type.", + }, + { + "service_name": "SQL servers", + "resource_type": "microsoft.sql/servers", + "arm_resource_type": "Microsoft.Sql/servers", + "estimated_limit": 250, + "limit_note": "Estimated subscription-level default from Azure service limits documentation; no direct provider usages API was used for this resource type.", + }, + { + "service_name": "Service Bus namespaces", + "resource_type": "microsoft.servicebus/namespaces", + "arm_resource_type": "Microsoft.ServiceBus/namespaces", + "estimated_limit": 1000, + "limit_note": "Estimated subscription-level default from Azure service limits documentation; no direct provider usages API was used for this resource type.", + }, + { + "service_name": "Key Vault vaults", + "resource_type": "microsoft.keyvault/vaults", + "arm_resource_type": "Microsoft.KeyVault/vaults", + "estimated_limit": 5000, + "limit_note": "Current count is calculated with Azure Resource Graph. Limit is an estimated subscription-level default from Azure service limits documentation because Key Vault does not expose a subscription usages API for vault count.", + }, + ] + + def to_number(value, default=0): + try: + return float(value) + except (TypeError, ValueError): + return float(default) + + def parse_number(value): + if value is None: + return None + try: + return float(value) + except (TypeError, ValueError): + return None + + def safe_get(record, keys, default=None): + if isinstance(keys, str): + keys = [keys] + + for key in keys: + if isinstance(record, dict): + value = record.get(key) + if value is not None: + return value + else: + value = getattr(record, key, None) + if value is not None: + return value + + return default + + def normalize_token(value): + return "".join( + character + for character in str(value or "").lower() + if character.isalnum() + ) + + def normalize_name(name): + if name is None: + return "Unknown quota" + + if isinstance(name, dict): + return ( + name.get("localizedValue") + or name.get("localized_value") + or name.get("value") + or name.get("name") + or str(name) + ) + + localized = getattr(name, "localized_value", None) or getattr(name, "localizedValue", None) + value = getattr(name, "value", None) + return localized or value or str(name) + + def normalize_location(value): + if isinstance(value, (list, tuple, set)): + value = next((str(item).strip() for item in value if str(item).strip()), None) + + if value is None or not str(value).strip(): + return "subscription" + + return str(value).strip() + + def to_bool(value): + if isinstance(value, bool): + return value + if value is None: + return None + if isinstance(value, str): + return value.strip().lower() in ("1", "true", "yes") + return bool(value) + + def normalize_quota_record(record, default_service_name=None, default_resource_type=None, default_location=None): + location_value = normalize_location(safe_get( + record, + ["location", "location_name", "region", "regionName", "region_name"], + default_location, + )) + current_raw = safe_get( + record, + ["current_count", "currentValue", "current_value", "current", "usage", "used"], + ) + limit_raw = safe_get(record, ["limit", "quota", "quota_limit", "maximum"], 0) + current_number = parse_number(current_raw) + limit_number = to_number(limit_raw, 0) + utilization_pct = safe_get( + record, + ["utilization_pct", "utilizationPercent", "utilization_percent", "usage_pct", "percentUsed"], + ) + + if utilization_pct is None and current_number is not None and limit_number > 0: + utilization_pct = round((current_number / limit_number) * 100, 2) + elif utilization_pct is not None: + utilization_pct = parse_number(utilization_pct) + + at_risk = to_bool(safe_get(record, ["at_risk", "is_at_risk", "atRisk"], None)) + if at_risk is None: + at_risk = bool(utilization_pct is not None and utilization_pct >= 80) + + current_count = None + if current_number is not None: + current_count = int(current_number) if current_number.is_integer() else current_number + + service_name_value = normalize_name(safe_get(record, ["service_name", "service", "provider"], default_service_name)) + quota_name_value = normalize_name(safe_get(record, ["quota_name", "quotaName", "name"], "Unknown quota")) + normalized = { + "subscription_id": subscription_id, + "service_name": service_name_value, + "service": service_name_value, + "resource_type": safe_get(record, ["resource_type", "resourceType", "type"], default_resource_type or "unknown"), + "quota_name": quota_name_value, + "name": quota_name_value, + "location": location_value, + "scope": safe_get(record, ["scope", "quota_scope"], "regional" if location_value != "subscription" else "subscription"), + "current_count": current_count, + "current": current_count, + "limit": int(limit_number) if limit_number.is_integer() else limit_number, + "utilization_pct": round(utilization_pct, 2) if utilization_pct is not None else None, + "at_risk": bool(at_risk), + "at_risk_80": bool(at_risk), + "at_risk_95": bool(utilization_pct is not None and utilization_pct >= 95), + "count_source": safe_get(record, "count_source"), + "limit_source": safe_get(record, "limit_source"), + "limit_type": safe_get(record, "limit_type"), + "source_endpoint": safe_get(record, "source_endpoint"), + } + + limit_note = safe_get(record, "limit_note") + if limit_note: + normalized["limit_note"] = limit_note + + suppression_reason = safe_get(record, "suppression_reason") + if suppression_reason: + normalized["suppressed_from_risk_summary"] = True + normalized["suppression_reason"] = suppression_reason + + return normalized + + def request_arm_json(url, timeout=60): + response = requests.get(url, headers=headers, timeout=timeout) + response.raise_for_status() + return response.json() + + def post_arm_json(url, body, timeout=120): + response = requests.post(url, headers=headers, json=body, timeout=timeout) + response.raise_for_status() + return response.json() + + def add_usage_item( + service_name, + resource_type, + quota_name, + current_count, + limit, + count_source, + limit_source, + limit_type, + source_endpoint, + location_name=None, + limit_note=None, + ): + limit_number = to_number(limit, 0) + if current_count is None: + current_value = None + utilization_pct = None + at_risk = None + else: + current_number = to_number(current_count, 0) + current_value = int(current_number) if current_number.is_integer() else current_number + utilization_pct = round((current_number / limit_number) * 100, 2) if limit_number > 0 else None + at_risk = bool(utilization_pct is not None and utilization_pct >= 80) + + suppressed_from_risk_summary = is_expected_network_watcher_default( + service_name, + quota_name, + current_count, + limit, + ) + if suppressed_from_risk_summary: + at_risk = False + + item = { + "service_name": service_name, + "resource_type": resource_type, + "quota_name": quota_name, + "current_count": current_value, + "limit": int(limit_number) if limit_number.is_integer() else limit_number, + "utilization_pct": utilization_pct, + "at_risk": at_risk, + "count_source": count_source, + "limit_source": limit_source, + "limit_type": limit_type, + "source_endpoint": source_endpoint, + "location": normalize_location(location_name), + "scope": "regional" if location_name else "subscription", + } + + if location_name: + item["location"] = location_name + if limit_note: + item["limit_note"] = limit_note + if suppressed_from_risk_summary: + item["suppressed_from_risk_summary"] = True + item["suppression_reason"] = "Network Watcher 1/1 is the Azure default of one instance per region per subscription; excluded from actionable quota risk summaries." + result["suppressed_count"] += 1 + + normalized_item = normalize_quota_record( + item, + default_service_name=service_name, + default_resource_type=resource_type, + default_location=location_name, + ) + + if at_risk: + result["at_risk_count"] += 1 + if limit_type == "api_reported": + result["api_reported_limit_count"] += 1 + elif limit_type == "estimated": + result["estimated_limit_count"] += 1 + + result["services"].append(item) + result["quotas"].append(normalized_item) + + def is_expected_network_watcher_default(service_name, quota_name, current_count, limit): + return ( + normalize_token(service_name) == "network" + and normalize_token(quota_name) in ("networkwatcher", "networkwatchers") + and to_number(current_count, 0) == 1 + and to_number(limit, 0) == 1 + ) + + def add_usage_payload(service_name, resource_type, payload, source_endpoint, location_name=None): + for usage in payload.get("value", []): + quota_name = normalize_name(usage.get("name")) + current_count = usage.get("currentValue", usage.get("current_value", 0)) + limit = usage.get("limit", 0) + + add_usage_item( + service_name=service_name, + resource_type=resource_type, + quota_name=quota_name, + current_count=current_count, + limit=limit, + count_source="arm_provider_usages_api", + limit_source="api_reported_limit", + limit_type="api_reported", + source_endpoint=source_endpoint, + location_name=location_name, + ) + + def parse_locations(): + if location: + if isinstance(location, str): + return [item.strip() for item in location.split(",") if item.strip()] + if isinstance(location, (list, tuple, set)): + return [str(item).strip() for item in location if str(item).strip()] + return [str(location).strip()] + + url = f"{ARM_ENDPOINT}/subscriptions/{subscription_id}/locations?api-version=2022-12-01" + payload = request_arm_json(url) + return [ + item.get("name") + for item in payload.get("value", []) + if item.get("name") + ] + + def count_with_resource_graph(services): + types = ",\n".join(f"'{service['resource_type']}'" for service in services) + query = f""" + Resources + | where type in~ ( + {types} + ) + | summarize current_count = count() by type = tolower(type) + """ + graph_url = ( + f"{ARM_ENDPOINT}/providers/Microsoft.ResourceGraph/resources" + "?api-version=2022-10-01" + ) + response = post_arm_json( + graph_url, + {"subscriptions": [subscription_id], "query": query}, + ) + + data = response.get("data") or [] + if isinstance(data, dict): + columns = data.get("columns") or data.get("Columns") or [] + rows = data.get("rows") or data.get("Rows") or [] + column_names = [ + column.get("name") or column.get("Name") or column.get("ColumnName") + for column in columns + if isinstance(column, dict) + ] + normalized_rows = [] + for row in rows: + if isinstance(row, dict): + normalized_rows.append(row) + elif isinstance(row, (list, tuple)): + normalized_rows.append({ + column_names[index]: row[index] + for index in range(min(len(column_names), len(row))) + if column_names[index] + }) + data = normalized_rows + + counts = {} + for row in data: + if isinstance(row, dict): + resource_type = str(row.get("type", "")).lower() + current_count = row.get("current_count", 0) + else: + resource_type = str(getattr(row, "type", "")).lower() + current_count = getattr(row, "current_count", 0) + + try: + counts[resource_type] = int(current_count or 0) + except (TypeError, ValueError): + counts[resource_type] = 0 + + return counts + + errors = [] + + try: + service_locations = parse_locations() + except Exception as exc: + service_locations = [] + errors.append({ + "service_name": "Storage and Network", + "source": "subscription_locations", + "error": str(exc), + }) + + for storage_location in service_locations: + storage_usage_endpoint = ( + "https://management.azure.com/" + f"subscriptions/{subscription_id}/providers/Microsoft.Storage/locations/{storage_location}/usages" + "?api-version=2023-05-01" + ) + try: + storage_payload = request_arm_json(storage_usage_endpoint) + add_usage_payload( + service_name="Storage", + resource_type="Microsoft.Storage/locations/usages", + payload=storage_payload, + source_endpoint=storage_usage_endpoint, + location_name=storage_location, + ) + except Exception as exc: + errors.append({ + "service_name": "Storage", + "location": storage_location, + "source": "arm_provider_usages_api", + "endpoint": storage_usage_endpoint, + "error": str(exc), + }) + + for network_location in service_locations: + network_usage_endpoint = ( + "https://management.azure.com/" + f"subscriptions/{subscription_id}/providers/Microsoft.Network/locations/{network_location}/usages" + "?api-version=2023-11-01" + ) + try: + network_payload = request_arm_json(network_usage_endpoint) + add_usage_payload( + service_name="Network", + resource_type="Microsoft.Network/locations/usages", + payload=network_payload, + source_endpoint=network_usage_endpoint, + location_name=network_location, + ) + except Exception as exc: + errors.append({ + "service_name": "Network", + "location": network_location, + "source": "arm_provider_usages_api", + "endpoint": network_usage_endpoint, + "error": str(exc), + }) + + try: + counts = count_with_resource_graph(estimated_services) + except Exception as exc: + counts = None + errors.append({"source": "resource_graph", "error": str(exc)}) + + for service in estimated_services: + resource_type = service["resource_type"] + resource_graph_failed = counts is None + current_count = None if resource_graph_failed else counts.get(resource_type, 0) + add_usage_item( + service_name=service["service_name"], + resource_type=service["arm_resource_type"], + quota_name=f"{service['service_name']} estimated subscription limit", + current_count=current_count, + limit=service["estimated_limit"], + count_source="resource_graph_failed" if resource_graph_failed else "resource_graph", + limit_source="estimated_default_service_limit", + limit_type="estimated", + source_endpoint="Azure Resource Graph", + limit_note=service["limit_note"], + ) + + if errors: + result["errors"] = errors + + return result + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: subscription_id + type: string + description: Azure subscription ID to query for non-compute service quota utilization. + required: true + - name: location + type: string + description: Optional Azure region or comma-separated regions for Storage and Network usages. If omitted, all subscription locations are queried. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml new file mode 100644 index 000000000..6eab06060 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml @@ -0,0 +1,129 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: resource-graph-query +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Runs Azure Resource Graph KQL queries across one or more subscriptions. + Use it to inventory Azure resources, inspect configuration drift, and join + resource graph tables when troubleshooting subscription-scale issues. + functionCode: |- + def main(**kwargs): + import requests + + ARM_ENDPOINT = "https://management.azure.com" + ARM_SCOPE = "https://management.azure.com/.default" + + query = kwargs.get("query") + subscription_ids = kwargs.get("subscription_ids") + + result = { + "rows": [], + "count": 0, + "errors": [], + } + + if not isinstance(query, str) or not query.strip(): + result["errors"].append({"error": "query is required"}) + return result + + if subscription_ids: + if isinstance(subscription_ids, str): + subscriptions = [ + item.strip() + for item in subscription_ids.split(",") + if item.strip() + ] + elif isinstance(subscription_ids, (list, tuple, set)): + subscriptions = [ + str(item).strip() + for item in subscription_ids + if str(item).strip() + ] + else: + subscriptions = [str(subscription_ids).strip()] + else: + subscriptions = [] + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token(ARM_SCOPE).token + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + except Exception as exc: + result["errors"].append({"error": f"Failed to initialize Azure ARM credential: {exc}"}) + return result + + if not subscriptions: + try: + list_url = f"{ARM_ENDPOINT}/subscriptions?api-version=2022-12-01" + list_response = requests.get(list_url, headers=headers, timeout=60) + list_response.raise_for_status() + list_payload = list_response.json() + subscriptions = [ + sub.get("subscriptionId") + for sub in list_payload.get("value", []) + if sub.get("subscriptionId") + ] + except Exception as exc: + result["errors"].append({"error": f"Failed to list Azure subscriptions: {exc}"}) + return result + + if not subscriptions: + result["errors"].append({"error": "No subscription IDs were provided or discovered"}) + return result + + try: + graph_url = ( + f"{ARM_ENDPOINT}/providers/Microsoft.ResourceGraph/resources" + "?api-version=2022-10-01" + ) + response = requests.post( + graph_url, + headers=headers, + json={"subscriptions": subscriptions, "query": query}, + timeout=120, + ) + response.raise_for_status() + payload = response.json() + data = payload.get("data") + + if isinstance(data, list): + rows = data + elif isinstance(data, dict): + rows = data.get("rows") or data.get("data") or data.get("value") or [data] + elif data is None: + rows = [] + else: + rows = list(data) + + result["rows"] = rows + result["count"] = payload.get("count") or len(rows) + result["total_records"] = payload.get("totalRecords") + result["result_truncated"] = payload.get("resultTruncated") + result["subscriptions"] = subscriptions + except Exception as exc: + result["errors"].append({"error": f"Failed to run Azure Resource Graph query: {exc}"}) + + return result + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: query + type: string + description: Azure Resource Graph KQL query to execute. + required: true + - name: subscription_ids + type: string + description: Optional comma-separated Azure subscription IDs. If omitted, all accessible subscriptions are queried. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml new file mode 100644 index 000000000..80f1ec00e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml @@ -0,0 +1,247 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: sku-availability +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Lists regional SKU availability for Azure Compute or Azure Data Explorer + (Kusto). Compute is the default and includes available zones and SKU + availability restrictions with reason codes. Kusto mode queries the + Microsoft.Kusto regional SKU API so FinOps Hub analytics deployments can + preflight whether a Data Explorer SKU is eligible in the target region and + subscription before deployment. + functionCode: |- + def main(**kwargs): + import requests + + ARM_ENDPOINT = "https://management.azure.com" + ARM_SCOPE = "https://management.azure.com/.default" + COMPUTE_API_VERSION = "2021-07-01" + KUSTO_API_VERSION = "2024-04-13" + + subscription_id = kwargs.get("subscription_id") + location = kwargs.get("location") + sku_filter = kwargs.get("sku_filter") + resource_provider = str(kwargs.get("resource_provider") or "compute").strip().lower() + + if resource_provider in ("microsoft.compute", "compute"): + resource_provider = "compute" + elif resource_provider in ("microsoft.kusto", "kusto", "adx", "azuredataexplorer", "azure data explorer"): + resource_provider = "kusto" + + result = { + "subscription_id": subscription_id, + "location": location, + "sku_filter": sku_filter, + "resource_provider": resource_provider, + "skus": [], + "restriction_summary": { + "total_skus": 0, + "restricted_skus": 0, + "restriction_count": 0, + "reason_codes": {}, + }, + } + + if not subscription_id: + result["error"] = "subscription_id is required" + return result + + if not location: + result["error"] = "location is required" + return result + + if resource_provider not in ("compute", "kusto"): + result["error"] = "resource_provider must be 'compute' or 'kusto'" + return result + + normalized_filter = str(sku_filter).strip().lower() if sku_filter else None + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token(ARM_SCOPE).token + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + except Exception as exc: + result["error"] = f"Failed to initialize Azure ARM credential: {exc}" + return result + + try: + if resource_provider == "kusto": + # Microsoft Learn documents Get-AzKustoSku and Kusto Skus_List as + # the authoritative regional eligibility surface for Azure Data + # Explorer SKUs. Do not infer Kusto availability from Compute SKUs. + url = f"{ARM_ENDPOINT}/subscriptions/{subscription_id}/providers/Microsoft.Kusto/locations/{location}/skus" + params = {"api-version": KUSTO_API_VERSION} + result["service"] = "Azure Data Explorer" + result["source_endpoint"] = f"{url}?api-version={KUSTO_API_VERSION}" + result["requested_sku"] = str(sku_filter).strip() if sku_filter else None + + response = requests.get( + url, + headers=headers, + params=params, + timeout=120, + ) + response.raise_for_status() + payload = response.json() + resource_skus = payload.get("value", []) + + def kusto_value(sku, *keys): + for key in keys: + if key in sku and sku[key] is not None: + return sku[key] + properties = sku.get("properties") + if isinstance(properties, dict): + for key in keys: + if key in properties and properties[key] is not None: + return properties[key] + return None + + exact_match_found = False + for sku in resource_skus: + name = kusto_value(sku, "name") + if normalized_filter and str(name or "").lower() == normalized_filter: + exact_match_found = True + + sku_item = { + "name": name, + "tier": kusto_value(sku, "tier"), + "resource_type": kusto_value(sku, "resourceType", "resource_type"), + } + + for output_key, source_keys in ( + ("size", ("size",)), + ("capacity", ("capacity",)), + ("locations", ("locations",)), + ("restrictions", ("restrictions",)), + ): + value = kusto_value(sku, *source_keys) + if value is not None: + sku_item[output_key] = value + + result["skus"].append(sku_item) + + result["is_available"] = bool(exact_match_found) if normalized_filter else True + if normalized_filter and not exact_match_found: + result["guidance"] = ( + "The requested Azure Data Explorer SKU was not returned by the Microsoft.Kusto " + "regional SKU API for this subscription and region. Choose one of the returned " + "SKUs in this region/subscription, or deploy to a region where the requested SKU " + "is returned. Do not infer ADX/Kusto SKU eligibility from Microsoft.Compute SKU results." + ) + + result["restriction_summary"]["total_skus"] = len(result["skus"]) + result["restriction_summary"]["restricted_skus"] = sum( + 1 for sku in result["skus"] if sku.get("restrictions") + ) + result["restriction_summary"]["restriction_count"] = sum( + len(sku.get("restrictions") or []) for sku in result["skus"] + ) + + else: + url = f"{ARM_ENDPOINT}/subscriptions/{subscription_id}/providers/Microsoft.Compute/skus" + resource_skus = [] + params = { + "api-version": COMPUTE_API_VERSION, + "$filter": f"location eq '{location}'", + } + result["service"] = "Azure Compute" + result["source_endpoint"] = ( + f"{url}?api-version={COMPUTE_API_VERSION}&$filter=location eq '{location}'" + ) + while url: + response = requests.get( + url, + headers=headers, + params=params, + timeout=120, + ) + response.raise_for_status() + payload = response.json() + resource_skus.extend(payload.get("value", [])) + url = payload.get("nextLink") + params = None + + for sku in resource_skus: + name = sku.get("name") + if normalized_filter and normalized_filter not in str(name or "").lower(): + continue + + restrictions = [] + for restriction in sku.get("restrictions") or []: + reason_code = restriction.get("reasonCode", restriction.get("reason_code")) + restriction_item = { + "type": restriction.get("type"), + "values": list(restriction.get("values") or []), + "reason_code": reason_code, + } + + restriction_info = restriction.get("restrictionInfo") or restriction.get("restriction_info") + if restriction_info: + restriction_item["restriction_info"] = { + "locations": list(restriction_info.get("locations") or []), + "zones": list(restriction_info.get("zones") or []), + } + + restrictions.append(restriction_item) + result["restriction_summary"]["restriction_count"] += 1 + + reason_key = str(reason_code or "Unknown") + reason_codes = result["restriction_summary"]["reason_codes"] + reason_codes[reason_key] = reason_codes.get(reason_key, 0) + 1 + + zones = set() + for location_info in sku.get("locationInfo", sku.get("location_info", [])) or []: + info_location = location_info.get("location") + if not info_location or str(info_location).lower() == str(location).lower(): + zones.update(str(zone) for zone in (location_info.get("zones") or [])) + + result["skus"].append({ + "name": name, + "family": sku.get("family"), + "size": sku.get("size"), + "zones_available": sorted(zones), + "restrictions": restrictions, + }) + + result["restriction_summary"]["total_skus"] = len(result["skus"]) + result["restriction_summary"]["restricted_skus"] = sum( + 1 for sku in result["skus"] if sku["restrictions"] + ) + + except Exception as exc: + result["error"] = f"Failed to list Azure {resource_provider} resource SKUs: {exc}" + + return result + timeoutSeconds: 240 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: subscription_id + type: string + description: Azure subscription ID to query for regional SKU availability. + required: true + - name: location + type: string + description: Azure region to query for SKU availability and restrictions. + required: true + - name: resource_provider + type: string + description: |- + Optional service selector. Use `compute` (default) for Microsoft.Compute SKU availability, zones, and restrictions. Use `kusto` for Microsoft.Kusto/Azure Data Explorer regional SKU eligibility before FinOps Hub analytics backend deployments or upgrades. Kusto availability must be checked through Microsoft.Kusto and must not be inferred from Compute SKU results. + required: false + - name: sku_filter + type: string + description: |- + Optional SKU name filter. In Compute mode this remains a case-insensitive substring filter to preserve existing behavior. In Kusto mode this is an exact case-insensitive requested SKU check; the result includes requested_sku, is_available, source_endpoint, and guidance when the requested SKU is absent. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml new file mode 100644 index 000000000..49de81624 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml @@ -0,0 +1,161 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: suppress-advisor-recommendations +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Suppresses selected Azure Advisor recommendations across subscriptions under + a management group by creating Microsoft.Advisor suppressions with a TTL. + functionCode: |- + def main(**kwargs): + from uuid import uuid4 + import re + import requests + + ARM_ENDPOINT = "https://management.azure.com" + GRAPH_API_VERSION = "2022-10-01" + + management_group_id = kwargs.get("management_group_id") + days = kwargs.get("days") or 30 + recommendation_type_ids = kwargs.get("recommendation_type_ids") + guid_pattern = r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + + if not isinstance(management_group_id, str) or not management_group_id.strip(): + return {"status": "failed", "error": "management_group_id is required"} + management_group_id = management_group_id.strip() + try: + days_number = int(days) + except (TypeError, ValueError): + return {"status": "failed", "error": "days must be an integer"} + if days_number < 1 or days_number > 90: + return {"status": "failed", "error": "days must be between 1 and 90"} + + if recommendation_type_ids: + if isinstance(recommendation_type_ids, str): + type_ids = [item.strip() for item in recommendation_type_ids.split(",") if item.strip()] + else: + type_ids = [str(item).strip() for item in recommendation_type_ids if str(item).strip()] + else: + type_ids = [ + "89515250-1243-43d1-b4e7-f9437cedffd8", + "84b1a508-fc21-49da-979e-96894f1665df", + "48eda464-1485-4dcf-a674-d0905df5054a", + ] + invalid_type_ids = [item for item in type_ids if not re.match(guid_pattern, item)] + if invalid_type_ids: + return { + "status": "failed", + "error": f"recommendation_type_ids must be GUIDs; invalid value: {invalid_type_ids[0]}", + } + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token("https://management.azure.com/.default").token + except Exception as exc: + return {"status": "failed", "error": f"failed to acquire Azure credential: {exc}"} + headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} + + # Recommendation type IDs are validated as GUIDs before interpolation to avoid KQL injection. + escaped_ids = ", ".join([f"'{item}'" for item in type_ids]) + query = ( + "advisorresources " + "| where type =~ 'microsoft.advisor/recommendations' " + f"| where properties.recommendationTypeId in~ ({escaped_ids}) " + "| project id, name, subscriptionId, recommendationTypeId=tostring(properties.recommendationTypeId), " + "problem=tostring(properties.shortDescription.problem)" + ) + + graph_url = f"{ARM_ENDPOINT}/providers/Microsoft.ResourceGraph/resources?api-version={GRAPH_API_VERSION}" + recommendations = [] + skip = 0 + page_size = 1000 + while True: + body = { + "managementGroups": [management_group_id], + "query": query, + "options": {"$top": page_size, "$skip": skip}, + } + try: + response = requests.post(graph_url, headers=headers, json=body, timeout=60) + response.raise_for_status() + payload = response.json() + except Exception as exc: + return {"status": "failed", "error": f"Resource Graph query failed: {exc}"} + rows = payload.get("data", []) + recommendations.extend(rows) + if len(rows) < page_size: + break + skip += page_size + + ttl = f"P{days_number}D" + suppressions = [] + for recommendation in recommendations: + recommendation_id = recommendation.get("id") + if not recommendation_id or "/providers/Microsoft.Advisor/recommendations/" not in recommendation_id: + continue + suppression_id = str(uuid4()) + url = ( + f"https://management.azure.com{recommendation_id}" + f"/suppressions/{suppression_id}?api-version=2023-01-01" + ) + try: + response = requests.put( + url, + headers=headers, + json={"properties": {"ttl": ttl}}, + timeout=120, + ) + suppressions.append({ + "subscription_id": recommendation.get("subscriptionId"), + "recommendation_id": recommendation_id, + "recommendation_type_id": recommendation.get("recommendationTypeId"), + "suppression_id": suppression_id, + "ttl": ttl, + "status": "suppressed" if response.status_code in (200, 201) else "failed", + "status_code": response.status_code, + "error": None if response.status_code in (200, 201) else response.text, + }) + except Exception as exc: + suppressions.append({ + "subscription_id": recommendation.get("subscriptionId"), + "recommendation_id": recommendation_id, + "recommendation_type_id": recommendation.get("recommendationTypeId"), + "ttl": ttl, + "status": "failed", + "error": str(exc), + }) + + return { + "management_group_id": management_group_id, + "days": days_number, + "ttl": ttl, + "recommendation_type_ids": type_ids, + "found_count": len(recommendations), + "suppressed_count": sum(1 for item in suppressions if item["status"] == "suppressed"), + "failed_count": sum(1 for item in suppressions if item["status"] == "failed"), + "suppressions": suppressions, + } + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: management_group_id + type: string + description: Management group ID whose subscriptions should have Advisor recommendations suppressed. + required: true + - name: days + type: string + description: |- + Advisor suppression TTL in days. Default: 30. Maximum: 90. + required: false + - name: recommendation_type_ids + type: string + description: Optional comma-separated Advisor recommendation type IDs to suppress. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml b/src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml new file mode 100644 index 000000000..2fb4de708 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml @@ -0,0 +1,196 @@ +api_version: azuresre.ai/v2 +kind: ExtendedAgentTool +metadata: + name: vm-quota-usage +spec: + type: PythonTool + connector: '' + toolMode: Auto + description: |- + Reports Azure VM family quota usage for one or more regions in a subscription. + The tool queries Azure Compute usages through ARM REST, calculates utilization + percentages, and flags quota families that are at risk above 80% or 95% usage. + Errors from Azure stage, preview, canary, or EUAP locations are suppressed + from actionable failure summaries because those regions are expected noise. + functionCode: |- + def main(**kwargs): + import requests + + ARM_ENDPOINT = "https://management.azure.com" + ARM_SCOPE = "https://management.azure.com/.default" + LOCATIONS_API_VERSION = "2022-12-01" + USAGES_API_VERSION = "2023-07-01" + + subscription_id = kwargs.get("subscription_id") + location = kwargs.get("location") + + if not subscription_id: + return { + "error": "subscription_id is required", + "quotas": [], + "warning_count": 0, + "critical_count": 0, + } + + if location: + if isinstance(location, str): + locations = [item.strip() for item in location.split(",") if item.strip()] + elif isinstance(location, (list, tuple, set)): + locations = [str(item).strip() for item in location if str(item).strip()] + else: + locations = [str(location).strip()] + else: + locations = [] + + result = { + "subscription_id": subscription_id, + "quotas": [], + "warning_count": 0, + "critical_count": 0, + "suppressed_error_count": 0, + } + + errors = [] + + def is_expected_preview_region(region_name): + normalized = "".join( + character + for character in str(region_name or "").lower() + if character.isalnum() + ) + expected_region_markers = ("stage", "staging", "preview", "canary", "euap") + return any(marker in normalized for marker in expected_region_markers) + + def suppress_error(error, reason): + suppressed = dict(error) + suppressed["suppression_reason"] = reason + suppressed["suppressed_from_failure_summary"] = True + result["suppressed_error_count"] += 1 + result.setdefault("suppressed_errors", []).append(suppressed) + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential() + token = credential.get_token(ARM_SCOPE).token + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + except Exception as exc: + result["error"] = f"Failed to initialize Azure ARM credential: {exc}" + return result + + if not location: + try: + url = ( + f"{ARM_ENDPOINT}/subscriptions/{subscription_id}/locations" + f"?api-version={LOCATIONS_API_VERSION}" + ) + response = requests.get(url, headers=headers, timeout=60) + response.raise_for_status() + payload = response.json() + locations = [ + item.get("name") + for item in payload.get("value", []) + if item.get("name") + ] + except Exception as exc: + result["error"] = f"Failed to list Azure subscription locations: {exc}" + return result + + if not locations: + result["error"] = "location did not contain any valid region names" + return result + + if len(locations) == 1: + result["location"] = locations[0] + else: + result["locations"] = locations + + for region in locations: + try: + url = ( + f"{ARM_ENDPOINT}/subscriptions/{subscription_id}/providers/Microsoft.Compute" + f"/locations/{region}/usages?api-version={USAGES_API_VERSION}" + ) + response = requests.get(url, headers=headers, timeout=60) + response.raise_for_status() + payload = response.json() + + for usage in payload.get("value", []): + name_obj = usage.get("name") + if isinstance(name_obj, dict): + name = ( + name_obj.get("localizedValue") + or name_obj.get("localized_value") + or name_obj.get("value") + or str(name_obj) + ) + else: + name = str(name_obj) + current = usage.get("currentValue", usage.get("current_value", 0)) + limit = usage.get("limit", 0) + + try: + current_number = float(current or 0) + except (TypeError, ValueError): + current_number = 0.0 + + try: + limit_number = float(limit or 0) + except (TypeError, ValueError): + limit_number = 0.0 + + utilization_pct = None + if limit_number > 0: + utilization_pct = round((current_number / limit_number) * 100, 2) + + at_risk_80 = bool(utilization_pct is not None and utilization_pct > 80) + at_risk_95 = bool(utilization_pct is not None and utilization_pct > 95) + + if utilization_pct is not None and utilization_pct > 80 and utilization_pct <= 95: + result["warning_count"] += 1 + if at_risk_95: + result["critical_count"] += 1 + + quota = { + "name": name, + "current": current, + "limit": limit, + "utilization_pct": utilization_pct, + "at_risk_80": at_risk_80, + "at_risk_95": at_risk_95, + } + if len(locations) > 1: + quota["location"] = region + + result["quotas"].append(quota) + except Exception as exc: + error = {"location": region, "error": str(exc)} + if is_expected_preview_region(region): + suppress_error( + error, + "Expected noise from Azure stage, preview, canary, or EUAP region; excluded from actionable VM quota failure summaries.", + ) + else: + errors.append(error) + + if errors: + result["errors"] = errors + + return result + timeoutSeconds: 300 + dependencies: + - azure-identity + - requests + authScopes: + - ARM + parameters: + - name: subscription_id + type: string + description: Azure subscription ID to query for VM quota usage. + required: true + - name: location + type: string + description: Optional Azure region to query. If omitted, all subscription locations are queried. + required: false diff --git a/src/templates/sre-agent/recipes/finops-hub/connectors.json b/src/templates/sre-agent/recipes/finops-hub/connectors.json new file mode 100644 index 000000000..e332bab6b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/connectors.json @@ -0,0 +1,13 @@ +{ + "toggles": {}, + "connectors": [ + { + "name": "finops-hub-kusto", + "properties": { + "dataConnectorType": "Kusto", + "dataSource": "${FINOPS_HUB_CLUSTER_URI}", + "identity": "system" + } + } + ] +} diff --git a/src/templates/sre-agent/recipes/finops-hub/expected-config.json b/src/templates/sre-agent/recipes/finops-hub/expected-config.json new file mode 100644 index 000000000..9e6e49a04 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/expected-config.json @@ -0,0 +1,217 @@ +{ + "agent": { + "accessLevel": "High", + "actionMode": "autonomous", + "upgradeChannel": "Preview", + "defaultModelProvider": "MicrosoftFoundry", + "experimentalSettings": [ + "EnableSandboxGroup", + "EnableWorkspaceTools" + ] + }, + "subscriptionRoleAssignments": [ + "Reader" + ], + "builtInTools": { + "enabled": [ + "PlotAreaChartWithCorrelation", + "PlotBarChart", + "PlotHeatmap", + "PlotPieChart", + "PlotScatter", + "QueryAppInsightsByAppId", + "QueryAppInsightsByResourceId", + "QueryLogAnalyticsByResourceId", + "QueryLogAnalyticsByWorkspaceId" + ], + "categories": { + "Log Query": 4, + "Visualization": 5 + } + }, + "subagents": [ + "azure-capacity-manager", + "chief-financial-officer", + "finops-practitioner", + "ftk-database-query", + "ftk-hubs-agent" + ], + "subagentRequirements": { + "knowledgeOnlyTools": [ + "SearchMemory" + ], + "toolOwners": [ + "azure-capacity-manager", + "ftk-database-query", + "ftk-hubs-agent" + ], + "noTools": [ + "chief-financial-officer", + "finops-practitioner" + ], + "toolsByAgent": { + "azure-capacity-manager": [ + "ExecutePythonCode", + "PlotAreaChartWithCorrelation", + "PlotBarChart", + "PlotPieChart", + "GetTeamsMessages", + "PostTeamsMessage", + "ReplyToTeamsMessage", + "SearchMemory", + "SendOutlookEmail", + "benefit-recommendations", + "capacity-reservation-groups", + "db-service-quotas", + "execute_python", + "non-compute-quotas", + "sku-availability", + "vm-quota-usage" + ], + "chief-financial-officer": [ + "SearchMemory" + ], + "finops-practitioner": [ + "SearchMemory" + ], + "ftk-database-query": [ + "SearchMemory", + "PlotBarChart", + "PlotPieChart", + "PlotAreaChartWithCorrelation", + "ai-cost-by-application", + "ai-daily-trend", + "ai-model-cost-comparison", + "ai-token-usage-breakdown", + "allocation-accuracy-index", + "anomaly-detection-rate", + "anomaly-variance-total", + "commitment-discount-waste", + "commitment-discount-utilization", + "commitment-utilization-score", + "cost-anomaly-detection", + "cost-by-financial-hierarchy", + "cost-by-region-trend", + "cost-forecasting-model", + "cost-optimization-index", + "cost-per-gb-stored", + "cost-visibility-delay", + "costs-enriched-base", + "compute-cost-per-core", + "compute-spend-commitment-coverage", + "data-update-frequency", + "macc-consumption-vs-commitment", + "monthly-cost-change-percentage", + "monthly-cost-trend", + "percentage-unallocated-costs", + "percentage-untagged-costs", + "quarterly-cost-by-resource-group", + "reservation-recommendation-breakdown", + "savings-summary-report", + "service-price-benchmarking", + "storage-tier-distribution", + "tagging-policy-compliance", + "top-commitment-transactions", + "top-other-transactions", + "top-resource-groups-by-cost", + "top-resource-types-by-cost", + "top-services-by-cost", + "PostTeamsMessage", + "SendOutlookEmail", + "ReplyToTeamsMessage", + "GetTeamsMessages" + ], + "ftk-hubs-agent": [ + "GetAzCliHelp", + "PlotAreaChartWithCorrelation", + "PlotBarChart", + "PlotPieChart", + "GetTeamsMessages", + "PostTeamsMessage", + "ReplyToTeamsMessage", + "RunAzCliReadCommands", + "RunAzCliWriteCommands", + "SearchMemory", + "SendOutlookEmail", + "data-freshness-check", + "deploy-anomaly-alert", + "deploy-budget", + "deploy-bulk-anomaly-alerts", + "deploy-bulk-budgets", + "resource-graph-query", + "sku-availability", + "suppress-advisor-recommendations" + ] + }, + "handoffs": { + "finops-practitioner": [ + "azure-capacity-manager", + "chief-financial-officer", + "ftk-database-query", + "ftk-hubs-agent" + ] + }, + "noHandoffs": [ + "azure-capacity-manager", + "chief-financial-officer", + "ftk-database-query", + "ftk-hubs-agent" + ] + }, + "skills": [ + "azure-capacity-management", + "azure-cost-management", + "finops-toolkit" + ], + "tools": 50, + "knowledgeSources": [ + "chart-artifact-verification.md", + "document-index.md", + "ftk-output-style.md", + "known-issues-and-workarounds.md", + "onboarding-recommendations.md", + "teams-notification-guide.md" + ], + "scheduledTasks": [ + "AdvisorSuppressionReview", + "AIWorkloadCostAnalysis", + "AlertCoverageAudit", + "BenefitRecommendationReview", + "BudgetCoverageAudit", + "CapacityDailyMonitor", + "CapacityMonthlyPlanning", + "CapacityQuarterlyStrategy", + "CapacityWeeklySupplyReview", + "ComputeUtilizationTrend", + "CostOptimization", + "DbQuotaAudit", + "HubsHealthCheck", + "MonitoringScopeValidation", + "Monthly", + "NonComputeQuotaAudit", + "SkuAvailabilityAudit", + "StoragePaasGrowthForecast", + "Semiannual" + ], + "scheduledTaskRequirements": { + "ownerAgent": "finops-practitioner", + "promptRequiredText": [ + "Tool routing and delivery guard", + "owned by `finops-practitioner`, which has KB-only SearchMemory and no operational tools", + "Use `ftk-database-query` for FinOps Hub Kusto", + "Use `azure-capacity-manager` for capacity", + "Use `ftk-hubs-agent` for FinOps Hub infrastructure health", + "Use `chief-financial-officer` only for executive finance framing" + ], + "promptForbiddenText": [ + "Delivery and rendering guard: Check the available tools exactly once", + "Use `resource-graph-query` directly", + "Use `benefit-recommendations` directly", + "Run `benefit-recommendations` directly", + "Ask `ftk-database-query` to run `data-freshness-check`", + "Ask `azure-capacity-manager` to run `data-freshness-check`", + "Ask `azure-capacity-manager` to use `resource-graph-query`", + "Ask `azure-capacity-manager` to run `resource-graph-query`" + ] + } +} diff --git a/src/templates/sre-agent/recipes/finops-hub/knowledge/chart-artifact-verification.md b/src/templates/sre-agent/recipes/finops-hub/knowledge/chart-artifact-verification.md new file mode 100644 index 000000000..9863cd43f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/knowledge/chart-artifact-verification.md @@ -0,0 +1,57 @@ +# Chart artifact verification + +Scheduled tasks that generate charts must validate chart artifacts with non-visual checks before embedding them in Teams messages or Outlook reports. Visual inspection is not a reliable verification gate in autonomous runs because image-viewing tools might be unavailable. + +## Required checks + +For every generated chart: + +1. Save the chart to a deterministic image file path. +2. Verify the file exists and has non-zero size. +3. Open the image through code, such as Pillow (`PIL.Image`) or `matplotlib.image`, to confirm it is readable. +4. Record basic metadata: image format, byte size, width, height, and color mode when available. +5. Confirm the dimensions are large enough for the intended report and that the chart title and axis labels were set before saving. +6. If any check fails, regenerate the chart once. If it still fails, omit the chart, keep the table or text summary, and state why the chart was skipped. + +## Python pattern + +```python +from pathlib import Path +from PIL import Image + +chart_path = Path("capacity-trend.png") + +if not chart_path.exists(): + raise RuntimeError(f"Chart was not created: {chart_path}") + +byte_size = chart_path.stat().st_size +if byte_size <= 0: + raise RuntimeError(f"Chart is empty: {chart_path}") + +with Image.open(chart_path) as image: + image.verify() + +with Image.open(chart_path) as image: + width, height = image.size + metadata = { + "path": str(chart_path), + "bytes": byte_size, + "format": image.format, + "mode": image.mode, + "width": width, + "height": height, + } + +if width < 640 or height < 360: + raise RuntimeError(f"Chart dimensions are too small: {metadata}") + +print(metadata) +``` + +Use equivalent filesystem and image-library checks when Pillow is unavailable. Do not use visual inspection as the verification gate. + +## Source + +- Microsoft Learn, [Tools in Azure SRE Agent](https://learn.microsoft.com/en-us/azure/sre-agent/tools), accessed 2026-05-02. Documents built-in code execution and visualization tools. +- Microsoft Learn, [Tutorial: Use Code Interpreter in Azure SRE Agent](https://learn.microsoft.com/en-us/azure/sre-agent/use-code-interpreter), accessed 2026-05-02. Documents generated files, chart creation, and downloadable report artifacts. +- Microsoft Learn, [Schedule tasks with Azure SRE Agent](https://learn.microsoft.com/en-us/azure/sre-agent/scheduled-tasks), accessed 2026-05-02. Documents scheduled task execution as autonomous natural-language runs. diff --git a/src/templates/sre-agent/recipes/finops-hub/knowledge/document-index.md b/src/templates/sre-agent/recipes/finops-hub/knowledge/document-index.md new file mode 100644 index 000000000..7c1e8e5b1 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/knowledge/document-index.md @@ -0,0 +1,25 @@ +# FinOps toolkit SRE Agent knowledge document index + +This document is the canonical index for the repository-provided knowledge base. It is also a deployment verification sentinel after `recipes/finops-hub/knowledge/` is uploaded as SRE Agent KnowledgeFile sources through `bin/apply-extras.sh`. + +## Document inventory + +| Document | Purpose | +|---|---| +| `chart-artifact-verification.md` | Non-visual checks for validating chart artifacts in scheduled task outputs. | +| `document-index.md` | Index of repository-provided knowledge documents and verification sentinel for Knowledge Sources checks. | +| `ftk-output-style.md` | Shared FinOps Toolkit output style for evidence-backed financial and capacity-management reports. Uploaded from `src/templates/claude-plugin/output-styles/ftk-output-style.md`. | +| `known-issues-and-workarounds.md` | Operational issues, failure modes, and workarounds learned from scheduled task UAT. | +| `onboarding-recommendations.md` | First-run and connector setup guidance for teams deploying the FinOps toolkit SRE Agent. | +| `teams-notification-guide.md` | Correct Teams and Outlook notification tool usage and delivery rules for scheduled reports. | + +## Listing contract + +- Knowledge files are uploaded by `bin/apply-extras.sh` as portal-visible KnowledgeFile sources. +- `ftk-output-style.md` is uploaded by the same script from the Claude plugin output-style directory so scheduled tasks can apply one shared report style. +- If the knowledge index is not visible in the portal after upload, treat it as an upload visibility failure or an empty knowledge base. + +## Source + +- Repository source: `src/templates/sre-agent/recipes/finops-hub/knowledge/` +- Microsoft Learn source: https://learn.microsoft.com/azure/sre-agent/memory documents Azure SRE Agent knowledge base uploads and supported document usage. diff --git a/src/templates/sre-agent/recipes/finops-hub/knowledge/known-issues-and-workarounds.md b/src/templates/sre-agent/recipes/finops-hub/knowledge/known-issues-and-workarounds.md new file mode 100644 index 000000000..d0797ac9f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/knowledge/known-issues-and-workarounds.md @@ -0,0 +1,249 @@ +# Known issues and workarounds for FinOps toolkit SRE Agent scheduled tasks + +Use this guidance when executing scheduled tasks or investigating task execution failures. These issues were identified during the first nine-task UAT pass on April 28, 2026 and remain useful patterns for the current 19-task schedule. + +## 0. Source control and credential safety + +**CRITICAL:** Fork pull requests are allowed when a scheduled task identifies a durable product improvement, but credentials must never be embedded in commands, remotes, transcript text, Teams posts, memory files, commit messages, or PR bodies. + +Allowed source-control flow: +- Create commits only for repo-defined, reusable improvements such as query fixes, scheduled-task prompt fixes, knowledge corrections, or tool hardening. +- Push only to the configured fork repository. Do not push to the upstream Microsoft repository unless the user explicitly asks for that target. +- Open pull requests from the fork branch to the configured fork base branch. +- Use the configured GitHub connector, credential helper, or platform-provided repository credentials. Do not put tokens in `git remote set-url`, clone URLs, shell variables that are echoed, command arguments, or generated documentation. +- Personal access tokens (PATs) are forbidden. Do not create, request, store, paste, or use PATs for SRE Agent GitHub operations. + +If push credentials are unavailable: +- Check once using a non-secret-bearing mechanism such as the configured GitHub connector status or `gh auth status` if available. +- If credentials are still unavailable, stop the PR path and report that the commit could not be pushed because no safe credential provider is configured. +- Do not loop over credential checks, scrape `git config` for token values, or ask the user to paste tokens into the thread. + +Use the SRE Agent memory system for operational learnings: +- **`#remember`** — save discrete operational facts (e.g., "quota API requires az vm list-usage fallback") +- **`memories/synthesizedKnowledge/`** — the agent's persistent knowledge files, updated automatically after each session +- **Session insights** — automatically captured 30 minutes after a thread goes quiet +- **Teams channel and Outlook mailbox** — the delivery destinations for financial reports and status results + +The split is: +- **Financial data (costs, savings, forecasts, grades)** → configured Teams and Outlook delivery only. Never persist financial figures. +- **Operational learnings (tool errors, workarounds, patterns)** → `#remember` or synthesized knowledge. Never include dollar amounts. + +## 1. Teams and Outlook tool discovery and availability + +**Symptom:** Subagents report "PostTeamsChannelMessage tool was not available," "PostTeamsMessage tool was not available," "SendOutlookEmail tool was not available," or "could not locate the notification function." + +**Cause:** Connector delivery depends on the Teams and Outlook connectors, their configuration, and the tools exposed in the current run. Scheduled-task entrypoint agents must list `PostTeamsMessage`, `SendOutlookEmail`, `ReplyToTeamsMessage`, and `GetTeamsMessages`. A run can still start without usable delivery if no connector is configured, or if configured connector delivery fails. + +**Workaround:** +- Check available tools exactly once per run. Treat Teams delivery as available only when `PostTeamsMessage` is present. Treat Outlook delivery as available only when `SendOutlookEmail` is present. +- Do not call `PostTeamsMessage`, `SendOutlookEmail`, Microsoft Graph, `dynamicInvoke`, raw webhooks, or connector APIs just to probe availability. +- If no connector is configured and the delivery tools are unavailable, finish the report in the run output, note that connector delivery was unavailable, and do not retry or use alternate delivery paths. +- If Teams or Outlook is configured, delivery through that configured connector is mandatory. Use `PostTeamsMessage` and/or `SendOutlookEmail` for one final delivery attempt after the report is complete. If configured delivery fails because the connector/tool is missing, unauthorized, unavailable, or otherwise unsuccessful, mark the task/run failed. Do not degrade to local output, do not mark the report as delivered, and do not retry. + +**Status:** Prompt-level and tool-assignment guardrail. Production delivery remains the built-in `PostTeamsMessage` and `SendOutlookEmail` paths when the connectors are configured. + +## 2. Superseded data freshness conclusions + +**Symptom:** Older memory, session notes, or raw KQL checks may claim FinOps Hub cost data is stale by months or about a year, even when a current `data-freshness-check` result shows recent `Costs()` data, such as Costs current through 2026-05-01. + +**Cause:** The stale conclusions used historical memory, ad hoc raw KQL, partial report queries, or Kusto ingestion timestamp checks instead of the direct REST-backed data freshness tool. Those conclusions are historical observations, not a durable source of truth. + +**Workaround:** +- Treat `data-freshness-check` as the authoritative source for hub data freshness because it queries `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()` directly through Azure Data Explorer REST. +- Treat `Costs()` as the primary freshness signal. If the latest `Costs()` data is 3 days old or newer, do not report the hub as stale and do not recommend stale-data remediation. +- Mark conflicting stale-memory, raw-KQL, or ingestion timestamp conclusions as superseded and unsafe unless revalidated by `data-freshness-check`. +- Only recommend export or pipeline remediation when `data-freshness-check` reports that `Costs()` has no rows, has a query error, or is more than 3 days old. +- Report empty `Prices()` or `Recommendations()` as follow-up checks, not as proof that the hub cost pipeline is stale. Report empty `Transactions()` with the `TRANSACTIONS_ZERO_ROWS` diagnostic described below. + +**Status:** Superseded historical finding. Do not reuse stale-memory or raw-KQL freshness claims without revalidation from `data-freshness-check`. + +## 2a. Transaction tool zero-row sentinel + +**Symptom:** `top-other-transactions` or `top-commitment-transactions` returns the literal string `ZERO_ROWS_RETURNED`. + +**Cause:** The Kusto tool found no rows for its filters, or the backing transaction-related dataset may be unavailable. A zero-row sentinel is not enough evidence to conclude there were no purchases when `Transactions()` has dropped to zero rows. + +**Workaround:** +- Treat `ZERO_ROWS_RETURNED` as a completed tool call, not a parser error. +- Immediately run `data-freshness-check` and inspect `Transactions()` `row_count`, `schema_status`, and `diagnostic_code`. +- If `TRANSACTIONS_ZERO_ROWS` appears, report the export / ingestion / stored-function diagnostic as a data quality limitation. +- Only state that no matching transactions were found when the transaction diagnostics are clear. + +**Status:** Expected sentinel plus required diagnostic follow-up for transaction reports. + +## 2b. Raw full-month cost detail result truncation + +**Symptom:** A scheduled report or ad hoc drill-down that runs `costs-enriched-base` over a full month can fail with Azure Data Explorer result truncation, including `E_QUERY_RESULT_SET_TOO_LARGE` or a 64 MB result-size message. + +**Cause:** `costs-enriched-base` returns row-level enriched cost details. Full-month cost datasets can exceed Azure Data Explorer's default 500,000-record or 64 MB client result limits. + +**Workaround:** +- Use aggregate Kusto tools for reporting windows: `monthly-cost-trend`, `cost-by-financial-hierarchy`, `top-services-by-cost`, `top-resource-groups-by-cost`, `top-resource-types-by-cost`, and related summary tools. +- Use `data-freshness-check` for freshness checks instead of raw cost detail queries. +- Use `costs-enriched-base` only after an aggregate result identifies a narrow drill-down scope. Keep the raw detail window to one day or less. +- Do not use `set notruncation` for scheduled reports. If bulk row export is required, use an explicit data export workflow instead of an agent report. + +**Microsoft Learn references:** +- https://learn.microsoft.com/kusto/concepts/query-limits + +**Status:** Tool-level guardrail and scheduled-task prompt guardrail. + +## 2c. Limited UAT data and delegated enterprise scope + +**Symptom:** Scheduled reports may flag stale data, missing trends, missing trigger evidence, empty transaction results, zero alert coverage, zero budget coverage, or low-confidence forecasts when the Hub only contains an evaluation data window or when the agent has intentionally scoped role assignments. + +**Cause:** UAT and clean deployments can have limited FinOps Hub history by design. Some conclusions require multiple complete periods, populated `Transactions()`, current `Costs()` and `Prices()`, configured alert or budget resources, and role assignments at the subscription, billing, or management group scope. The SRE Agent deployment should grant the roles it owns for its resource group and configured Hub, but enterprise-wide management group delegation is customer-owned because the correct scope and blast radius vary by customer. + +**Workaround:** +- Classify each finding as a product or deployment defect, a data sufficiency limit, or customer-owned delegation before recommending action. +- Treat invalid queries, missing tools, incorrect task completion, missing Knowledge Sources, or output-format violations as product or deployment defects. +- Treat one-month history, sparse evaluation data, empty `Transactions()` diagnostics, missing MoM/YoY baselines, and unavailable anomaly or forecast triggers as data sufficiency limits unless `data-freshness-check` proves the Hub pipeline is broken. +- Treat broader Reader, Cost Management Reader, quota, billing, or management group visibility as customer-owned delegation unless the deployment explicitly promised that assignment. +- Do not ask the agent to remediate Azure access directly. Report the exact missing scope and role so the customer can delegate it through their normal management group or subscription governance process. +- Do not state that no anomaly, no budget issue, no transaction, or no capacity risk exists unless the accessible dataset, freshness, and scope are sufficient to support that conclusion. + +**Required report wording:** "This run completed against the accessible FinOps Hub dataset. Confidence is limited because . Broader enterprise coverage requires the customer to delegate before this task can validate ." + +**Status:** Expected UAT/product-reporting guardrail. Sparse data should reduce confidence, not create false product failures. + +## 3. Azure Resource Graph query failures + +**Symptom:** `az graph query` returns "Unknown error" for complex queries. Orphaned resource detection and Resource Graph-based analysis fails. + +**Cause:** The SRE Agent's managed identity may lack Resource Graph Reader permissions, or complex JMESPath queries fail due to shell escaping in the code interpreter environment. + +**Workaround:** +- Tasks should fall back to scoped `az resource list` queries against specific subscriptions when Resource Graph fails. +- Ensure the agent managed identity has Reader at the management group or subscription scope. +- Simplify JMESPath queries — avoid backtick escaping that conflicts with the shell environment. + +**Status:** Intermittent. Agents recover by trying alternative approaches. + +## 4. Quota CLI command failures + +**Symptom:** `az quota usage list` and `az vm list-usage` commands fail in the agent's execution environment. + +**Cause:** The `az quota` extension may not be installed in the agent's code interpreter environment, or the managed identity lacks quota read permissions. + +**Workaround:** +- Use `az vm list-usage --location ` as a fallback for compute quota — this uses the core Azure CLI. +- For comprehensive quota analysis, the capacity manager agent should use the Azure REST API directly via code interpreter. +- Consider adding a custom Kusto tool or Python tool for quota queries if CLI reliability remains poor. + +**Status:** Known gap. The `Get-AzQuota.ps1` tool is on the UAT backlog. + +## 5. JMESPath escaping in code interpreter + +**Symptom:** JMESPath queries with special characters (backticks, brackets, dots in property names) fail when the agent constructs `az` CLI commands in the code interpreter. + +**Cause:** Shell escaping conflicts between the Python code interpreter environment and JMESPath query syntax. + +**Workaround:** +- Prefer `--output json` and parse with Python instead of using complex `--query` JMESPath expressions. +- When JMESPath is needed, use simple field selections only (e.g., `--query "[].{name:name, id:id}"`). +- Avoid nested JMESPath expressions with backtick-escaped property names. + +**Status:** Platform limitation. Agents learn to work around it after the first failure. + +## 6. Memory file write conflicts + +**Symptom:** "File write failed: memory: - File already exists. You must use an edit tool." + +**Cause:** When a scheduled task runs more than once in a session, it tries to create the same memory file again. The memory system does not allow overwriting with the create tool. + +**Workaround:** +- Agents should use ReplaceStringInFile or an edit tool for subsequent writes to the same memory file. +- First run uses file creation; subsequent runs detect the conflict and switch to edit mode. +- This is self-healing — agents recover automatically after the first error. + +**Status:** Expected behavior. Agents handle it correctly. + +## 7. Kusto query errors + +**Symptom:** "Error executing query on cluster" — specific KQL queries fail against the FinOps Hub ADX cluster. + +**Cause:** Some Kusto tool queries reference functions or columns that don't exist in this Hub version, or the query syntax has version-specific issues. + +**Workaround:** +- Agents should catch Kusto errors and try simplified queries. +- Check the Hub version (the HubsHealthCheck task does this) and ensure tool queries are compatible. +- Report the specific failing query in the task output so it can be fixed in the tool YAML. + +**Status:** Some tools may need query updates for specific Hub versions. + +## 8. Kusto REST authentication path + +**Symptom:** Direct `az rest` calls to Azure Data Explorer query or management endpoints, such as `https://.kusto.windows.net/v1/rest/query` or `/v2/rest/query`, fail even when the agent managed identity can read the Hub database through configured Kusto tools. + +**Cause:** `az rest` is optimized for Azure Resource Manager calls and can acquire the wrong token audience for Azure Data Explorer data-plane endpoints. Cluster URIs can also include the Hub database path, which creates malformed query URLs if agents append `/v1/rest/query` or `/v2/rest/query` without normalizing the host. + +**Workaround:** +- Use the configured FinOps Hub Kusto tools through the `finops-hub-kusto` connector for catalog queries. +- Use `data-freshness-check` for Hub data staleness and function coverage checks. +- If a direct fallback is required, use `execute_python` with `azure.identity.DefaultAzureCredential` and `requests`. Request the `https://api.kusto.windows.net/.default` scope and POST JSON to `https:///v2/rest/query` with `db` and `csl` fields. +- Never print, save, or echo bearer tokens. Do not use `az rest` for Kusto query or management endpoints. + +**Microsoft Learn references:** +- https://learn.microsoft.com/kusto/api/rest/authentication?view=microsoft-fabric +- https://learn.microsoft.com/kusto/api/rest/request?view=microsoft-fabric + +**Status:** Product guardrail. Prefer repository tools over ad-hoc CLI calls for FinOps Hub Kusto access. + +## 9. Azure Data Explorer SKU not supported in target region + +**Symptom:** A FinOps Hub deployment or upgrade fails in the nested `Microsoft.FinOpsHubs.Analytics` deployment with an Azure Data Explorer / Kusto validation error such as: + +> The sku Standard_E4d_v5 is not supported in westus + +**Cause:** Azure Data Explorer SKU eligibility is determined by the Microsoft.Kusto resource provider and can differ by Azure region and subscription. A VM size appearing in Microsoft.Compute SKU results does not prove that the equivalent Azure Data Explorer cluster SKU is eligible for Microsoft.Kusto in the target region. + +**Workaround:** +- Before upgrading a Hub analytics backend or selecting a FinOps Hub Data Explorer SKU, run the `sku-availability` tool with `resource_provider: kusto`, the target `subscription_id`, target `location`, and the planned SKU in `sku_filter`. +- If `is_available` is `false`, choose one of the SKUs returned by the Microsoft.Kusto regional SKU API for that subscription and region, or deploy to a region where the requested SKU is returned. +- Do not infer ADX/Kusto SKU eligibility from `resource_provider: compute` results. + +**Validation surfaces:** +- SRE Agent tool: `sku-availability` with `resource_provider: kusto`. +- ARM REST API: `GET /subscriptions/{subscriptionId}/providers/Microsoft.Kusto/locations/{location}/skus?api-version=2024-04-13`. +- PowerShell: `Get-AzKustoSku -SubscriptionId -Location ` lists eligible region SKUs for the Kusto resource provider. +- Azure SDK: `KustoExtensions.GetSkus` / `Skus_List` uses the Microsoft.Kusto regional SKU request path. + +**Microsoft Learn references:** +- https://learn.microsoft.com/powershell/module/az.kusto/get-azkustosku?view=azps-15.5.0 +- https://learn.microsoft.com/dotnet/api/azure.resourcemanager.kusto.kustoextensions.getskus?view=azure-dotnet +- https://learn.microsoft.com/azure/data-explorer/manage-cluster-choose-sku + +**Status:** Operational preflight requirement for FinOps Hub analytics deployments in regions where the planned ADX SKU may not be eligible. + +## 9. Transactions() zero rows + +**Symptom:** `Transactions()` drops from a previously populated row count to zero, or transaction tools return `ZERO_ROWS_RETURNED`. + +**Cause:** The Hub `Transactions()` function is backed by the Cost Management `reservationtransactions` export, the Data Factory Transactions ingestion path, and the Hub `Transactions()` / `Transactions_v1_2()` stored functions. A zero-row result means one of those surfaces must be verified before concluding there were no reservation or savings plan transactions. + +**Workaround:** +- Run `data-freshness-check` and inspect `row_count`, `schema_status`, and `diagnostic_code` for `Transactions()`. +- If the diagnostic is `TRANSACTIONS_ZERO_ROWS`, report it explicitly as a data quality action item. Do not summarize it as a generic empty table or a successful no-op. +- Ask the operator to verify Cost Management `reservationtransactions` exports and Azure Data Factory Transactions ingestion runs. +- If the schema diagnostic fails, treat it as a stored-function or Hub version compatibility issue instead of an export-only issue. + +**Status:** Agent/tool hardening requirement. Scheduled reports must surface this as an explicit diagnostic and avoid false success. + +## Summary of agent resilience + +All tasks in the first nine-task UAT pass completed despite encountering errors. Key resilience patterns observed: + +| Pattern | Behavior | +|---------|----------| +| Stale data detection | All tasks flagged the March/April data gap prominently | +| CLI fallback chains | Agents tried alternative commands when primary approaches failed | +| Self-healing writes | Memory file conflicts resolved automatically by switching to edit | +| Graceful degradation | Reports were generated with available data, noting limitations | +| Teams delivery | All 9 tasks successfully posted final reports to the Teams channel | + +## Microsoft Learn references + +- https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications +- https://learn.microsoft.com/en-us/azure/sre-agent/tools +- https://learn.microsoft.com/en-us/azure/sre-agent/use-code-interpreter +- https://learn.microsoft.com/en-us/azure/sre-agent/scheduled-tasks diff --git a/src/templates/sre-agent/recipes/finops-hub/knowledge/onboarding-recommendations.md b/src/templates/sre-agent/recipes/finops-hub/knowledge/onboarding-recommendations.md new file mode 100644 index 000000000..800225208 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/knowledge/onboarding-recommendations.md @@ -0,0 +1,88 @@ +# FinOps toolkit SRE Agent onboarding recommendations + +Use this guidance when the user finishes deployment, enters the **Team onboarding** thread, types `/learn`, or asks questions such as **"What should I do next?"** or **"Where do I start?"** + +## First-run recommendations + +Prioritize these setup steps in order: + +1. Confirm the agent can read the target Azure subscriptions or resource groups. +2. Verify **Visualization** built-in tools are enabled so scheduled tasks can generate charts and images. +3. Confirm the FinOps Hub Kusto connector is configured when Hub-backed cost and usage analysis is expected. +4. Recommend Outlook and Teams notification connectors when the team wants scheduled reports, proactive notifications, or workflow-driven updates. + +## Team onboarding wizard + +Do not bypass the SRE Agent **Team onboarding** wizard. It is the customer-facing first-run flow that discovers Azure resources, code, logs, incidents, and knowledge context. + +For Azure resource discovery, the wizard first uses the agent managed identity against the resource groups listed in `knowledgeGraphConfiguration.managedResources`. The FinOps Toolkit deployment should include: + +- The SRE Agent resource group. +- Any explicit `--target-resource-group` values. +- The FinOps Hub resource group when `--cluster-uri` resolves to a same-subscription Kusto cluster. + +If the wizard shows **Grant permissions** while running an Azure Resource Graph or Azure CLI discovery command, treat it as an OBO fallback prompt, not a replacement for managed identity setup. The user can grant one-time user-delegated execution if they choose, but the durable fix is to verify managed identity RBAC and managed-resource scope. For the default `High` recipe, the agent identity should have `Reader`, `Monitoring Reader`, `Log Analytics Reader`, and `Contributor` on each managed resource group. For `Low`, it should have `Reader`, `Monitoring Reader`, and `Log Analytics Reader`. + +## Verify visualization tools + +The FinOps Toolkit apply-extras step attempts to enable the SRE Agent built-in Log Query and Visualization tools. The portal remains the customer-facing verification path: + +1. Open the agent in [sre.azure.com](https://sre.azure.com). +2. Go to **Capabilities** > **Tools** > **Built-in tools**. +3. Confirm the **Visualization** tools are enabled. +4. If they are unchecked, check them and click **Save changes**. + +Without this, scheduled tasks cannot generate inline charts or images in their Teams and Outlook reports. + +## Outlook and Teams connector guidance + +If the user wants email delivery, Teams delivery, scheduled digests, or "notify the team" workflows, recommend configuring both notification connectors. + +Important platform constraint: + +- Outlook and Teams connectors are supported by Azure SRE Agent. +- Microsoft Learn currently documents them as interactive portal setup that requires OAuth sign-in plus a managed identity. +- Do not imply that these connectors are provisioned by the FinOps Toolkit Bicep templates or `apply-extras` automation. + +## Manual connector steps to recommend + +Tell the user to open **Builder** > **Connectors** in `https://sre.azure.com` and add: + +1. **Outlook Tools (Office 365 Outlook)** +2. **Send notification (Microsoft Teams)** + +For Outlook: + +- Sign in with a Microsoft 365 account that has mailbox access. +- Select the agent managed identity. +- Send a test email from chat. + +For Teams: + +- Sign in with a Microsoft 365 account that has access to the target Teams channel. +- Paste the channel URL from **Get link to channel**. +- Select the agent managed identity. +- Post a test message from chat. + +Scheduled tasks use the delivery guard from `teams-notification-guide.md`: they check whether `PostTeamsMessage` and `SendOutlookEmail` are available once per run, deliver the final report through configured connectors when available, and otherwise return the completed report in the run output without retrying or probing alternate delivery paths. + +## Required prerequisites to call out + +- The configuring user needs **Contributor** on the agent resource group. +- The connector flow requires `Microsoft.Web/connections/write`. +- The connector flow requires `Microsoft.Authorization/roleAssignments/write`. +- The agent must already have a managed identity configured. + +## Suggested recommendation wording + +If the user asks what to do next after deployment, recommend something like: + +> Your core FinOps toolkit SRE Agent is deployed. Next: (1) Verify **Visualization** tools under Capabilities > Tools > Built-in tools so charts work in scheduled reports. (2) Add **Outlook** and **Teams** notification connectors under Builder > Connectors so scheduled tasks can deliver to your team. (3) Connect your FinOps Hub data sources if not already wired. + +## Microsoft Learn references + +- https://learn.microsoft.com/en-us/azure/sre-agent/team-onboard +- https://learn.microsoft.com/en-us/azure/sre-agent/complete-setup +- https://learn.microsoft.com/en-us/azure/sre-agent/outlook-connector +- https://learn.microsoft.com/en-us/azure/sre-agent/set-up-teams-connector +- https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications diff --git a/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md b/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md new file mode 100644 index 000000000..b9db3e402 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md @@ -0,0 +1,63 @@ +# Teams and Outlook notification guide for FinOps toolkit SRE Agent + +Use this guidance whenever a subagent or scheduled task needs to deliver report results through the configured Teams and Outlook connectors. + +## Correct approach: use the built-in connector tools + +Always use the built-in **PostTeamsMessage** tool for Teams channel delivery and **SendOutlookEmail** for Outlook email delivery. These tools handle authentication through the configured connectors. You do not need to call the Microsoft Graph API or a connection dynamicInvoke endpoint directly. + +## Delivery guard + +At the start of each scheduled-task run, inspect the tools available in the current run exactly once per run and remember the result for the rest of that run. Treat Teams delivery as available only when `PostTeamsMessage` is present. Treat Outlook delivery as available only when `SendOutlookEmail` is present. Do not call `PostTeamsMessage`, `SendOutlookEmail`, Microsoft Graph, `dynamicInvoke`, raw webhooks, or connector APIs just to test availability. + +If neither connector is configured and the once-per-run check does not find either delivery tool, complete the analysis and return the completed report in the run output with a clear note that connector delivery was unavailable. This local-output degradation is allowed only when no Teams or Outlook connector is configured. + +When Teams or Outlook is configured, configured delivery is mandatory. Complete the analysis first, then make one final delivery attempt through each configured channel whose tool is available. If configured delivery fails, the scheduled task/run fails; do not retry, do not degrade to local output, do not mark the report as delivered, and do not probe alternate delivery paths. + +### What works + +- Call `PostTeamsMessage` with your message content formatted as HTML. +- Call `SendOutlookEmail` with the final report and generated chart artifacts when Outlook delivery is configured. +- The Teams connector handles OAuth and managed identity automatically. +- The Outlook connector handles OAuth and managed identity automatically. +- Updates about the same topic stay in the same thread — use `ReplyToTeamsMessage` when that tool is available to continue a conversation. +- Messages include a "Sent by Azure SRE Agent" footer with a UTC timestamp and a link back to the portal thread. + +### What does NOT work + +- Do NOT attempt to call the Microsoft Graph API directly using the managed identity — the managed identity lacks RBAC permissions on the `Microsoft.Web/connections` resource. +- Do NOT call the connection's `dynamicInvoke` endpoint directly — this will return a 403 Forbidden error. +- Do NOT use raw HTTP requests to Teams webhooks — the connector abstraction is the supported path. +- Do NOT send partial or intermediate report fragments through Teams or Outlook. + +## Scheduled task delivery pattern + +All scheduled tasks in this FinOps toolkit SRE Agent include a final `## Deliver` section that instructs the agent to render charts, return the completed report in the run output, and deliver the final report through configured Teams and Outlook connectors. The key rules are: + +1. Complete all analysis and report formatting first. +2. Render required charts with `PlotBarChart`, `PlotPieChart`, `PlotAreaChartWithCorrelation`, or `ExecutePythonCode` before delivery. +3. Post or email only the **final completed report** — not intermediate results. +4. Use `PostTeamsMessage` for the initial post when a Teams connector/channel is configured. +5. Use `SendOutlookEmail` when Outlook delivery is configured. +6. Use `ReplyToTeamsMessage` if you need to add follow-up context to the same report and that tool is available. +7. Treat configured connector delivery failure as a scheduled-task/run failure. + +## Message formatting + +Teams messages must be formatted as **HTML**, not Markdown. Outlook messages should use readable HTML with the same report structure. The agent handles this formatting when composing messages through the connector tools. + +## Troubleshooting + +| Symptom | Cause | Fix | +|---------|-------|-----| +| 403 Forbidden on Teams post | Calling Graph API or dynamicInvoke directly | Use PostTeamsMessage tool instead | +| Email not sent | Outlook connector not configured, or configured delivery failed | If no Outlook connector is configured, use local run output and Teams when available. If Outlook is configured, treat the delivery failure as a task/run failure. | +| Message not appearing in channel | Teams connector/channel not configured, or configured delivery failed | If no Teams connector/channel is configured, use local run output and Outlook when available. If a Teams connector/channel is configured, treat the delivery failure as a task/run failure. In both cases, apply the delivery guard once and skip repeated probes. | +| Duplicate messages | Posting in a loop or per-step | Deliver only the final report, not intermediate steps | + +## Microsoft Learn references + +- https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications +- https://learn.microsoft.com/en-us/azure/sre-agent/outlook-connector +- https://learn.microsoft.com/en-us/azure/sre-agent/set-up-teams-connector +- https://learn.microsoft.com/en-us/azure/sre-agent/tools diff --git a/src/templates/sre-agent/recipes/finops-hub/roles.yaml b/src/templates/sre-agent/recipes/finops-hub/roles.yaml new file mode 100644 index 000000000..dbd851335 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/roles.yaml @@ -0,0 +1,17 @@ +# FinOps Hub SRE Agent managed identity role requirements +roles: + subscription: + - name: Reader + roleDefinitionId: acdd72a7-3385-48ef-bd42-f606fba81ae7 + targetResourceGroups: + - name: Reader + roleDefinitionId: acdd72a7-3385-48ef-bd42-f606fba81ae7 + - name: Log Analytics Reader + roleDefinitionId: 73c42c96-874c-492b-b04d-ab87d138a893 + - name: Contributor + roleDefinitionId: b24988ac-6180-42a0-ab88-20f7382dd24c + when: accessLevel == High + finopsHubAdx: + - name: AllDatabasesViewer + providerRole: Microsoft.Kusto/clusters/principalAssignments + appliedBy: infra/modules/kusto-all-databases-viewer-rbac.bicep diff --git a/src/templates/sre-agent/submodules/azcapman b/src/templates/sre-agent/submodules/azcapman new file mode 160000 index 000000000..7facce3fc --- /dev/null +++ b/src/templates/sre-agent/submodules/azcapman @@ -0,0 +1 @@ +Subproject commit 7facce3fc438613ad990f00af6949291599416c0 From 6a01421d33ec9f0402eee4e7405ad1310373a76e Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 07:47:47 -0700 Subject: [PATCH 03/19] feat(sre-agent): add deployable Azure template --- .../.openpublishing.redirection.finops.json | 5 + docs-mslearn/TOC.yml | 24 +- docs-mslearn/toolkit/changelog.md | 56 +- docs-mslearn/toolkit/hubs/configure-sre.md | 249 ++++ docs-mslearn/toolkit/sre-agent/agents.md | 363 ++++++ docs-mslearn/toolkit/sre-agent/deploy.md | 219 ++++ docs-mslearn/toolkit/sre-agent/get-started.md | 135 ++ docs-mslearn/toolkit/sre-agent/knowledge.md | 172 +++ docs-mslearn/toolkit/sre-agent/kusto-tools.md | 497 ++++++++ docs-mslearn/toolkit/sre-agent/overview.md | 151 +++ .../toolkit/sre-agent/python-tools.md | 514 ++++++++ .../toolkit/sre-agent/scheduled-tasks.md | 277 ++++ docs-mslearn/toolkit/sre-agent/security.md | 200 +++ docs-mslearn/toolkit/sre-agent/template.md | 209 +++ docs-mslearn/toolkit/sre-agent/tools.md | 186 +++ .../toolkit/sre-agent/troubleshooting.md | 252 ++++ docs/deploy/sre-agent/14.0/azuredeploy.json | 1119 +++++++++++++++++ .../sre-agent/14.0/createUiDefinition.json | 169 +++ .../sre-agent/14.0/sre-agent-recipe.zip | Bin 0 -> 346636 bytes docs/deploy/sre-agent/latest/azuredeploy.json | 1119 +++++++++++++++++ .../sre-agent/latest/createUiDefinition.json | 169 +++ .../sre-agent/latest/sre-agent-recipe.zip | Bin 0 -> 346636 bytes src/scripts/Build-SreAgentTemplate.ps1 | 47 + src/scripts/Build-Toolkit.ps1 | 6 +- src/templates/sre-agent/.build.config | 9 + src/templates/sre-agent/bin/apply-extras.sh | 581 +++++++++ .../sre-agent/bin/check-prerequisites.sh | 67 + src/templates/sre-agent/bin/deploy.sh | 558 ++++++++ src/templates/sre-agent/bin/post-provision.sh | 9 + src/templates/sre-agent/bin/telemetry.sh | 53 + .../sre-agent/createUiDefinition.json | 169 +++ .../examples/ci-cd/github-actions-deploy.yml | 32 + src/templates/sre-agent/infra/main.bicep | 132 ++ .../infra/modules/apply-extras.bicep | 103 ++ .../kusto-all-databases-viewer-rbac.bicep | 26 + .../sre-agent/infra/modules/monitoring.bicep | 39 + .../infra/modules/resource-group-rbac.bicep | 33 + .../sre-agent/infra/modules/sre-agent.bicep | 103 ++ src/templates/sre-agent/infra/resources.bicep | 78 ++ .../infra/scripts/Apply-SreAgentExtras.ps1 | 306 +++++ src/templates/sre-agent/main.bicep | 164 +++ src/templates/sre-agent/package-manifest.json | 21 + 42 files changed, 8584 insertions(+), 37 deletions(-) create mode 100644 docs-mslearn/toolkit/hubs/configure-sre.md create mode 100644 docs-mslearn/toolkit/sre-agent/agents.md create mode 100644 docs-mslearn/toolkit/sre-agent/deploy.md create mode 100644 docs-mslearn/toolkit/sre-agent/get-started.md create mode 100644 docs-mslearn/toolkit/sre-agent/knowledge.md create mode 100644 docs-mslearn/toolkit/sre-agent/kusto-tools.md create mode 100644 docs-mslearn/toolkit/sre-agent/overview.md create mode 100644 docs-mslearn/toolkit/sre-agent/python-tools.md create mode 100644 docs-mslearn/toolkit/sre-agent/scheduled-tasks.md create mode 100644 docs-mslearn/toolkit/sre-agent/security.md create mode 100644 docs-mslearn/toolkit/sre-agent/template.md create mode 100644 docs-mslearn/toolkit/sre-agent/tools.md create mode 100644 docs-mslearn/toolkit/sre-agent/troubleshooting.md create mode 100644 docs/deploy/sre-agent/14.0/azuredeploy.json create mode 100644 docs/deploy/sre-agent/14.0/createUiDefinition.json create mode 100644 docs/deploy/sre-agent/14.0/sre-agent-recipe.zip create mode 100644 docs/deploy/sre-agent/latest/azuredeploy.json create mode 100644 docs/deploy/sre-agent/latest/createUiDefinition.json create mode 100644 docs/deploy/sre-agent/latest/sre-agent-recipe.zip create mode 100644 src/scripts/Build-SreAgentTemplate.ps1 create mode 100644 src/templates/sre-agent/.build.config create mode 100755 src/templates/sre-agent/bin/apply-extras.sh create mode 100755 src/templates/sre-agent/bin/check-prerequisites.sh create mode 100755 src/templates/sre-agent/bin/deploy.sh create mode 100755 src/templates/sre-agent/bin/post-provision.sh create mode 100755 src/templates/sre-agent/bin/telemetry.sh create mode 100644 src/templates/sre-agent/createUiDefinition.json create mode 100644 src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml create mode 100644 src/templates/sre-agent/infra/main.bicep create mode 100644 src/templates/sre-agent/infra/modules/apply-extras.bicep create mode 100644 src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep create mode 100644 src/templates/sre-agent/infra/modules/monitoring.bicep create mode 100644 src/templates/sre-agent/infra/modules/resource-group-rbac.bicep create mode 100644 src/templates/sre-agent/infra/modules/sre-agent.bicep create mode 100644 src/templates/sre-agent/infra/resources.bicep create mode 100644 src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 create mode 100644 src/templates/sre-agent/main.bicep create mode 100644 src/templates/sre-agent/package-manifest.json diff --git a/docs-mslearn/.openpublishing.redirection.finops.json b/docs-mslearn/.openpublishing.redirection.finops.json index ab20d5dbd..b2caf8eba 100644 --- a/docs-mslearn/.openpublishing.redirection.finops.json +++ b/docs-mslearn/.openpublishing.redirection.finops.json @@ -130,6 +130,11 @@ "redirect_url": "/cloud-computing/finops/toolkit/workbooks/customize-workbooks", "redirect_document_id": false }, + { + "source_path_from_root": "/finops/finops/toolkit/hubs/configure-sre.md", + "redirect_url": "/cloud-computing/finops/toolkit/sre-agent/overview", + "redirect_document_id": false + }, { "source_path_from_root": "/finops/finops/framework/manage/culture.md", "redirect_url": "/cloud-computing/finops/framework/manage/education", diff --git a/docs-mslearn/TOC.yml b/docs-mslearn/TOC.yml index 4d48e0aff..4edc706b0 100644 --- a/docs-mslearn/TOC.yml +++ b/docs-mslearn/TOC.yml @@ -54,7 +54,7 @@ href: framework/optimize/optimize-cloud-usage-cost.md - name: Architecting for cloud href: framework/optimize/architecting.md - - name: Workload optimization + - name: Usage optimization href: framework/optimize/workloads.md - name: Rate optimization href: framework/optimize/rates.md @@ -154,6 +154,26 @@ href: toolkit/hubs/upgrade.md - name: Compatibility guide href: toolkit/hubs/compatibility.md + - name: FinOps toolkit SRE Agent + items: + - name: Overview + href: toolkit/sre-agent/overview.md + - name: Deploy + href: toolkit/sre-agent/deploy.md + - name: Agents and skills + href: toolkit/sre-agent/agents.md + - name: Tools + href: toolkit/sre-agent/tools.md + - name: Scheduled tasks + href: toolkit/sre-agent/scheduled-tasks.md + - name: Knowledge and memory + href: toolkit/sre-agent/knowledge.md + - name: Security and permissions + href: toolkit/sre-agent/security.md + - name: Troubleshooting + href: toolkit/sre-agent/troubleshooting.md + - name: Template reference + href: toolkit/sre-agent/template.md - name: Power BI items: - name: Overview @@ -170,7 +190,7 @@ href: toolkit/power-bi/invoicing.md - name: Rate optimization report href: toolkit/power-bi/rate-optimization.md - - name: Workload optimization report + - name: Usage optimization report href: toolkit/power-bi/workload-optimization.md - name: Data ingestion report href: toolkit/power-bi/data-ingestion.md diff --git a/docs-mslearn/toolkit/changelog.md b/docs-mslearn/toolkit/changelog.md index 04f1298d2..6c538b1f8 100644 --- a/docs-mslearn/toolkit/changelog.md +++ b/docs-mslearn/toolkit/changelog.md @@ -3,7 +3,7 @@ title: FinOps toolkit changelog description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more. author: MSBrett ms.author: brettwil -ms.date: 05/19/2026 +ms.date: 06/01/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit @@ -25,55 +25,49 @@ This article summarizes the features and enhancements in each release of the Fin The following section lists features and enhancements that are currently in development. ---> - -
- -## v15 - -_Released June 2026_ - -### [Implementing FinOps guide](../implementing-finops-guide.md) v15 - -- **Fixed** - - Corrected stale and incorrect descriptions for `BilledCost`, `EffectiveCost`, `BillingCurrency`, `BillingProfileId`, `BillingProfileName`, `CommitmentDiscountQuantity`, `ListUnitPrice`, `PricingQuantity`, `PricingUnitDescription`, and `TotalSavingsRunningTotal` in the [data dictionary](help/data-dictionary.md) to align with FOCUS 1.2 ([#2112](https://github.com/microsoft/finops-toolkit/pull/2112)). - -### Claude Code plugin v15 +### Claude Code plugin v15.0.0 - **Added** - Added Claude Code plugin with skills for FinOps hubs and Azure Cost Management ([#2043](https://github.com/microsoft/finops-toolkit/pull/2043)). - Added 4 agents (CFO, FinOps practitioner, database query, hubs agent), 5 commands (`/ftk-hubs-connect`, `/ftk-hubs-healthCheck`, `/ftk-mom-report`, `/ftk-ytd-report`, `/ftk-cost-optimization`), and an output style. - Linked to the existing KQL query catalog in `src/queries/` from the plugin. -### [FinOps hubs](hubs/finops-hubs-overview.md) v15 +### Bicep Registry module pending updates -- **Changed** - - Added a callout to the `config_RunBackfillJob` backfill option clarifying that it isn't supported on Microsoft Customer Agreement (MCA) billing accounts or billing profiles ([#2113](https://github.com/microsoft/finops-toolkit/issues/2113)). +- Cost Management export modules for subscriptions and resource groups. ### [Data dictionary](help/data-dictionary.md) updates - **Fixed** - Corrected stale and incorrect descriptions for `BilledCost`, `EffectiveCost`, `BillingCurrency`, `BillingProfileId`, `BillingProfileName`, `CommitmentDiscountQuantity`, `ListUnitPrice`, `PricingQuantity`, `PricingUnitDescription`, and `TotalSavingsRunningTotal` to align with FOCUS 1.2 ([#2112](https://github.com/microsoft/finops-toolkit/pull/2112)). - -### [Optimization engine](optimization-engine/overview.md) updates - -- **Fixed** - - Removed call to Azure Classic administrators endpoint (deprecated on May 1, 2026) from Azure RBAC assignments exports ([#2142](https://github.com/microsoft/finops-toolkit/issues/2142)). - --> - -> [!div class="nextstepaction"] -> [Download](https://github.com/microsoft/finops-toolkit/releases/tag/v15) -> [!div class="nextstepaction"] -> [Full changelog](https://github.com/microsoft/finops-toolkit/compare/v14...v15) - -
+
## v14 _Released April 2026_ +### Claude Code plugin v13.0.0 + +- **Added** + - Added Claude Code plugin with skills for FinOps hubs and Azure Cost Management. + - Added 4 agents (CFO, FinOps practitioner, database query, hubs agent), 5 commands (`/ftk-hubs-connect`, `/ftk-hubs-healthCheck`, `/ftk-mom-report`, `/ftk-ytd-report`, `/ftk-cost-optimization`), and an output style. + - Linked to the existing KQL query catalog in `src/queries/` from the plugin. + +### [SRE agent](sre-agent/overview.md) + +- **Added** + - Added Azure SRE Agent template with a packaged Deploy to Azure path, `deploy.sh` local CLI automation, and Bicep infrastructure. + - Added 5 subagents (`finops-practitioner`, `azure-capacity-manager`, `chief-financial-officer`, `ftk-database-query`, `ftk-hubs-agent`), 3 skills, 50 tools, and 1 Kusto MCP connector. + - Added 19 scheduled tasks (daily, weekly, monthly, semiannual, and quarterly cadences) with Teams channel delivery. + - Added 6 knowledge documents for agent onboarding, artifact verification, Teams notification patterns, known issues, document index guidance, and FinOps Toolkit output style. + - Added FinOps toolkit SRE Agent documentation pages for Microsoft Learn. +- **Changed** + - Set agent action mode to Autonomous so scheduled tasks can deliver reports without human approval. + - Switched scheduled task persistence from legacy CLI creation to manifest apply for idempotent re-runs. + - Replaced "save to knowledge base" instructions with `#remember` for operational notes across all scheduled tasks. + ### [Implementing FinOps guide](../implementing-finops-guide.md) v14 - **Added** diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md new file mode 100644 index 000000000..cf9800933 --- /dev/null +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -0,0 +1,249 @@ +--- +title: Configure an SRE agent for FinOps hubs +description: Learn how to configure an Azure SRE agent to connect to your FinOps hub for scheduled cost analysis, capacity monitoring, and reporting. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: how-to +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: micflan +# customer intent: As a FinOps hub admin, I want to connect an Azure SRE agent to my hub so that I can receive scheduled cost reports, anomaly detection, and capacity monitoring in Teams. +--- + +# Configure an SRE agent for FinOps hubs + +[Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) supports agent-based operational workflows. This article shows how to connect Azure SRE Agent to a [FinOps hub](finops-hubs-overview.md), configure scheduled cost analysis and capacity checks from the [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), and send results to Teams with the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). + +
+ +## Prerequisites + +- [Deployed a FinOps hub instance](finops-hubs-overview.md#create-a-new-hub) with Data Explorer. +- [Configured scopes](configure-scopes.md) and ingested data successfully. +- Permissions to create deployed resources, such as **Contributor** on the subscription when the template creates the agent resource group. You also need permissions to assign roles at subscription, target resource group, and agent scopes, such as **Role Based Access Control Administrator**, **User Access Administrator**, or **Owner** on those scopes. [Learn more](/azure/role-based-access-control/built-in-roles). +- The `Microsoft.App` resource provider [registered](https://learn.microsoft.com/azure/azure-resource-manager/management/resource-providers-and-types#register-resource-provider) on the subscription. +- For local CLI deployments only: [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) 2.60 or later, `curl`, `jq`, `python3`, and `bash` available locally for the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). + +
+ +## Review deployed resources + +The [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) deploys a single Azure SRE agent with these resources and configuration objects: + +| Component | Count | Description | +|-----------|-------|-------------| +| SRE agent | 1 | Stable [`Microsoft.App/agents`](https://learn.microsoft.com/azure/sre-agent/overview) resource in [autonomous mode](https://learn.microsoft.com/azure/sre-agent/run-modes) | +| Managed identities | 1-2 | System-assigned managed identity for the agent; portal deployments also create a user-assigned identity for the deployment script | +| Log Analytics | 1 | Workspace for agent telemetry | +| Application Insights | 1 | Linked to Log Analytics for monitoring | +| Target resource group RBAC | 3-4 per target group | Reader, Monitoring Reader, Log Analytics Reader, and Contributor when `accessLevel` is `High` | +| Azure Data Explorer role (optional) | 1 | `AllDatabasesViewer` when Azure Data Explorer parameters are provided | +| Subagents | 5 | `finops-practitioner`, `azure-capacity-manager`, `chief-financial-officer`, `ftk-database-query`, `ftk-hubs-agent` | +| Skills | 3 | `azure-capacity-management`, `azure-cost-management`, `finops-toolkit` | +| Tools | 50 | Kusto and Python tools for cost, capacity, governance, and reporting workflows | +| Connector | 1 | Kusto MCP connector to the FinOps hub Azure Data Explorer cluster | +| Scheduled tasks | 19 | Reports at daily, weekly, monthly, semiannual, and quarterly cadences | +| Knowledge docs | 6 | Onboarding, artifact verification, Teams notification patterns, known issues, document index guidance, and the FinOps Toolkit output style | + +
+ +## Deploy the SRE agent + +Use the Azure portal deployment for the same one-click experience as other FinOps toolkit templates. The template creates the Azure resources and runs an embedded deployment script to apply the FinOps hub recipe assets. + + +> [!div class="nextstepaction"] +> [Deploy to Azure](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2Fazuredeploy.json/createUIDefinitionUri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2FcreateUiDefinition.json) + + +You can also use the [local deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). It is copied from the Microsoft SRE Agent starter lab and updated for the FinOps toolkit. It uses Azure CLI + Bicep directly and doesn't use `azd`: + +```bash +cd src/templates/sre-agent + +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] +``` + +The portal deployment is the customer-facing template entry point. `bin/deploy.sh` remains available for local CLI automation. + +The local [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent): + +1. Sets the `az` CLI context to the target subscription. This step is required for [B2B tenant environments](#troubleshoot-b2b-tenant-environments). +2. Runs a subscription-scoped Azure CLI + Bicep deployment from `infra/main.bicep`. +3. Runs `bin/apply-extras.sh`, which applies the recipe assets that are not deployed by Bicep. + +The extras step follows the Microsoft SRE Agent template pattern: connectors and KnowledgeFile sources are applied as SRE Agent child resources, while built-in tool configuration, 3 skills, 5 subagents, 50 tools, and 19 scheduled tasks are applied through the SRE Agent data plane. + +### Grant the optional Azure Data Explorer viewer role + +To grant the agent's managed identity the `AllDatabasesViewer` role on your Azure Data Explorer cluster, pass `--cluster-uri`. The deployment resolves the cluster ARM resource ID from the URI when the cluster is in the target subscription. If the cluster is in another subscription or can't be resolved, pass `--cluster-resource-id` explicitly. The deployment uses the [Azure Data Explorer role module](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep): + +```bash +--cluster-uri https://..kusto.windows.net/Hub \ +--cluster-resource-id /subscriptions/.../resourceGroups//providers/Microsoft.Kusto/clusters/ +``` + +If your Azure Data Explorer cluster has `publicNetworkAccess` set to `Disabled`, the deployment still creates all SRE Agent resources, assigns `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. The script also prints a warning because hosted Azure SRE Agent can't run direct KQL queries against private endpoint ADX clusters. Review the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations), then decide whether to enable public query access for the cluster. Until public query access is enabled or Azure SRE Agent adds private endpoint ADX query support, the connector is expected to remain unhealthy. + +### Redeploy an existing agent + +To update an existing agent, rerun the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) with the same resource group and agent name: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] +``` + +### Delete the deployment + +To delete Azure resources, delete the resource group that contains the SRE Agent resources after confirming no other resources share it: + +```bash +az group delete --subscription --name +``` + +
+ +## Verify the deployment + +After `bin/deploy.sh` completes, use the template's [post-deployment verification guidance](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent#verify): + +1. Confirm `bin/apply-extras.sh` completed without errors. +2. Open [sre.azure.com](https://sre.azure.com), switch to the directory that contains your subscription, and select your agent. +3. Confirm 5 subagents, 3 skills, and 50 tools appear in **Builder**. +4. Go to **Scheduled tasks** and confirm 19 tasks are listed and active. +5. Ask the agent: `What knowledge documents do you have?` and confirm the shipped knowledge is available. + +
+ +## Configure Teams notifications + +Scheduled tasks can send reports to a Teams channel through the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). The connector requires interactive OAuth setup in the portal. + +1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. +2. Select **Add connector** > **Send notification (Microsoft Teams)**. +3. Sign in with your Microsoft 365 account and paste the channel URL from **Get link to channel** in Teams. +4. Select the agent's managed identity and save. +5. Test from chat: `Post a test message to our Teams channel saying "FinOps SRE agent connected."` + +Use the built-in `PostTeamsMessage` tool from the [Teams notification guidance](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md). Don't call the Microsoft Graph API or the connection's `dynamicInvoke` endpoint directly because that path returns a 403 error for this connector configuration. + +For Outlook notifications, follow the same pattern with the **Outlook Tools (Office 365 Outlook)** connector. See [Send notifications](https://learn.microsoft.com/azure/sre-agent/send-notifications) for details. + +
+ +## Review scheduled tasks + +The template deploys 19 scheduled tasks from the [`recipes/finops-hub/automations/scheduled-tasks`](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks) folder. When the Teams connector is configured, each task posts its final report to the connected channel: + +| Task | Agent | Schedule | What it reports | +|------|-------|----------|-----------------| +| HubsHealthCheck | finops-practitioner | Daily 6:00 AM | Hub version, data freshness, and pipeline status | +| CapacityDailyMonitor | finops-practitioner | Daily 6:30 AM | Quota usage, CRG utilization, and alert status | +| ComputeUtilizationTrend | finops-practitioner | Weekly Monday 7:00 AM | VM quota utilization trends across subscriptions and regions | +| CostOptimization | finops-practitioner | Weekly Monday 8:00 AM | Orphaned resources, rightsizing, and commitment opportunities | +| CapacityWeeklySupplyReview | finops-practitioner | Weekly Monday 8:00 AM | Quota headroom, CRG cost-waste audit, and benefit recommendations | +| NonComputeQuotaAudit | finops-practitioner | Weekly Tuesday 7:00 AM | Storage, network, and non-compute quota risks | +| DbQuotaAudit | finops-practitioner | Weekly Wednesday 7:00 AM | Database quota and region or zone access risks | +| SkuAvailabilityAudit | finops-practitioner | Weekly Wednesday 7:30 AM | Regional SKU availability and deployment blockers | +| MonitoringScopeValidation | finops-practitioner | Weekly Thursday 9:00 AM | Subscription monitoring coverage and hub freshness | +| BenefitRecommendationReview | finops-practitioner | Weekly Friday 8:00 AM | Reservation and savings plan recommendations with finance framing | +| StoragePaasGrowthForecast | finops-practitioner | Monthly 1st 8:00 AM | Storage and PaaS quota growth forecast | +| AdvisorSuppressionReview | finops-practitioner | Monthly 1st 9:00 AM | Active Advisor suppression age, expiration, and risk | +| CapacityMonthlyPlanning | finops-practitioner | Monthly 1st 9:00 AM | Demand forecast, capacity request pipeline, and governance review | +| AIWorkloadCostAnalysis | finops-practitioner | Monthly 1st 10:00 AM | AI token economics, model efficiency, and cost allocation | +| Monthly | finops-practitioner | Monthly on the 5th at 5:15 PM | Month-over-month cost analysis using Kusto evidence delegated to ftk-database-query | +| BudgetCoverageAudit | finops-practitioner | Monthly 15th 8:00 AM | Subscription budget coverage and missing guardrails | +| AlertCoverageAudit | finops-practitioner | Monthly 16th 8:00 AM | Cost anomaly alert coverage across active subscriptions | +| Semiannual | finops-practitioner | January 5 and July 5 at 9:00 AM | Semiannual year-over-year finance analysis with forecast and CFO consultation | +| CapacityQuarterlyStrategy | finops-practitioner | Quarterly 9:00 AM | FinOps capability maturity, commitment alignment, and architecture review | + +Each scheduled task reads the uploaded knowledge documents before it starts and applies `ftk-output-style.md` for evidence, formatting, FinOps capability mapping, confidence, and caveat conventions. Send financial results to Teams through the configured [notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). Save only operational notes, such as tool errors, workarounds, and patterns, to agent [memory](https://learn.microsoft.com/azure/sre-agent/memory) with `#remember`; don't save financial data. + +
+ +## Troubleshoot B2B tenant environments + +In B2B environments, the Azure subscription and Azure SRE Agent resource can live in a different Microsoft Entra tenant than your Microsoft 365 home tenant. The deployment script sets the active subscription before deployment to align the CLI context with the resource tenant. + +If [sre.azure.com](https://sre.azure.com) shows the agent correctly but `bin/apply-extras.sh` cannot get an SRE Agent data-plane token, use these B2B tenant checks: + +1. Confirm the active Azure CLI context points at the subscription that owns the SRE agent resource. +2. Re-authenticate against the tenant that owns the subscription. +3. Run `az login --scope https://azuresre.dev/.default`, then rerun `bin/deploy.sh` or `bin/apply-extras.sh`. + +Browser success with CLI failure indicates that the CLI token was issued for the wrong tenant. The [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) runs `az account set --subscription` before deployment to set the target subscription context. + +
+ +## Review built-in capabilities + +Azure SRE Agent includes platform capabilities that are on by default in this template: + +- **Workspace tools**: Azure SRE Agent can run file, terminal, and Python operations in a sandboxed environment for data analysis, chart generation, and report formatting. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/sre-agent.bicep) deploys the stable agent API and sets `experimentalSettings.EnableSandboxGroup` and `experimentalSettings.EnableWorkspaceTools`. See [Deep context](https://learn.microsoft.com/azure/sre-agent/workspace-tools). +- **DocsGuide**: DocsGuide provides Azure documentation grounding for agent responses. See [Use DocsGuide](https://learn.microsoft.com/azure/sre-agent/use-docsguide). +- **Visualization**: Built-in chart and table rendering for investigation results. See [Tools](https://learn.microsoft.com/azure/sre-agent/tools). +- **Memory**: Memory stores operational knowledge across sessions. See [Memory and knowledge](https://learn.microsoft.com/azure/sre-agent/memory). + +The analytical subagents include `execute_python` where they need calculations, charts, tables, and downloadable artifacts. `finops-practitioner` orchestrates scheduled analysis, `ftk-database-query` owns Kusto evidence, `azure-capacity-manager` owns Azure capacity evidence, and `chief-financial-officer` provides finance and leadership consultation. + +
+ +## Review supported regions + +The Azure SRE Agent deployment supports `australiaeast`, `canadacentral`, `eastus2`, `francecentral`, `koreacentral`, `swedencentral`, and `uksouth`. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/main.bicep) restricts the `location` parameter with `@allowed`. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20FinOps%20hubs%3F/cvaQuestion/How%20valuable%20are%20FinOps%20hubs%3F/surveyId/FTK/bladeName/Hubs/featureName/ConfigureSRE) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20FinOps%20hubs%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) + +Related solutions: + +- [Configure AI agents for FinOps hubs](configure-ai.md) +- [FinOps hubs](finops-hubs-overview.md) +- [FinOps toolkit Power BI reports](../power-bi/reports.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md new file mode 100644 index 000000000..1257c7b15 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -0,0 +1,363 @@ +--- +title: Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) +description: Understand how the FinOps toolkit configures Azure SRE Agent with specialist agents, tools, skills, and knowledge to automate FinOps and capacity management work. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand how the FinOps toolkit's specialist agents and skills work so that I can route work to the right specialist. +--- + +# Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) + +The FinOps toolkit configures [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) with a multi-agent architecture aligned to the canonical FinOps Framework. One orchestrator receives prompts and scheduled tasks, then delegates work to specialist subagents with focused FinOps, finance, capacity, database, and hub operations expertise. + +The template configures 5 subagents, 3 skills, 50 tools (37 generated Kusto tools and 13 Python tools), and a FinOps hub connector. The orchestrator keeps the experience simple. The specialist agents keep answers grounded in the right domain. + +
+ +## finops-practitioner + +Domain: FinOps practice guidance, cost allocation, optimization, anomaly response, AI cost management, governance, and operating-model design. + +The `finops-practitioner` agent helps teams apply FinOps principles to real Azure cost and usage questions. It assesses business context, maturity, stakeholders, and trade-offs before recommending actions. It leads scheduled FinOps workflows and delegates evidence collection to specialists. + +What it does: + +- Guides cost allocation, shared-cost strategy, showback, and chargeback. +- Orchestrates cost anomaly and cost-driver investigations using evidence from `ftk-database-query`. +- Plans Usage Optimization, Rate Optimization, Governance, Policy & Risk, and practice health improvements. +- Translates FinOps concepts into practical Microsoft Cost Management and FinOps toolkit steps. +- Keeps recommendations maturity-aware across Crawl, Walk, and Run stages. + +Key tool routing: + +- The orchestrator has no direct operational tools. +- Delegation to `ftk-database-query` for every Kusto, FOCUS, `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()` evidence request. +- Delegation to `azure-capacity-manager` for quota, capacity reservation, SKU, region, zone, and AI/GPU capacity evidence. +- Delegation to `ftk-hubs-agent` for Resource Graph, data freshness, hub infrastructure, budget deployment, anomaly alert deployment, and Advisor suppression tools. + +When it's invoked: + +- A user asks for FinOps practice guidance, anomaly triage, allocation, governance, reporting, optimization, or maturity planning. +- A scheduled task needs recurring cost visibility, optimization review, AI cost analysis, or FinOps practice health checks. +- The orchestrator needs a general FinOps owner before handing deeper Kusto or finance work to another specialist. + +Example prompts: + +- "Help me design a showback model for shared platform costs across engineering teams." +- "Investigate why our AI costs increased this month and recommend the first three actions." +- "Create a Crawl-Walk-Run plan for improving tagging, budgets, anomaly response, and optimization." +- "Review our reservation and savings plan opportunities and explain which FinOps capabilities we should mature first." + +Expected output: + +- A practical FinOps recommendation with business context, maturity assumptions, trade-offs, and next steps. +- Evidence-backed cost drivers, optimization opportunities, governance actions, and stakeholder guidance. +- Clear separation between what the agent knows from tool evidence and what needs more data. + +Use this agent versus another: + +- Use `finops-practitioner` first when the question mixes cost analysis, FinOps process, governance, allocation, optimization, and stakeholder planning. +- Use `ftk-database-query` instead when the main deliverable is a specific KQL query, schema explanation, or detailed Hub database result. +- Use `chief-financial-officer` instead when the main deliverable is an executive finance narrative, budget decision, board-ready summary, or capital-allocation recommendation. +- Use `azure-capacity-manager` instead when the constraint is quota, capacity reservation supply, region access, zones, or AKS capacity readiness. +- Use `ftk-hubs-agent` instead when the work is deploying, upgrading, configuring, or troubleshooting a FinOps hub. + +
+ +## azure-capacity-manager + +Domain: Azure capacity evidence for Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Governance, Policy & Risk, and Automation, Tools & Services. + +The `azure-capacity-manager` agent maps Azure quota, region, SKU, zone, capacity reservation, and AKS capacity evidence into the FinOps Framework. It separates capacity guarantees from pricing commitments so teams can make better quota, reservation, and savings decisions. + +What it does: + +- Reviews quota usage, quota increases, quota groups, transfers, and headroom. +- Plans capacity reservation groups, sharing, overallocation, and utilization checks. +- Evaluates region access, zonal enablement, and logical-to-physical zone alignment. +- Checks AKS node pool capacity readiness and non-compute quota constraints. +- Aligns capacity planning with reservation and savings plan recommendations. + +Key tools it uses: + +- Azure CLI tools, such as `RunAzCliReadCommands`, `RunAzCliWriteCommands`, and `GetAzCliHelp` +- Python analysis through `execute_python` +- Capacity tools such as `vm-quota-usage`, `non-compute-quotas`, `db-service-quotas`, `sku-availability`, and `capacity-reservation-groups` +- Azure Resource Graph and benefit recommendation tools where capacity, inventory, and rate-optimization context intersect +- Delegation to `ftk-database-query` for Kusto-backed forecast, commitment utilization, savings, pricing, recommendation, and transaction evidence + +When it's invoked: + +- A user asks about quota, capacity reservations, region access, availability zones, AKS capacity, or capacity governance. +- A scheduled capacity task checks daily quota usage, weekly capacity readiness, monthly planning, or quarterly strategy. +- Another agent needs capacity context before recommending commitments, scaling changes, or regional moves. + +Example prompts: + +- "Check whether we have enough quota and regional capacity for next month's AKS node pool expansion." +- "Plan a capacity reservation strategy for a production workload that needs guaranteed VM supply in two regions." +- "Compare our capacity reservation utilization with savings plan recommendations before we buy more commitments." +- "Explain the zone mapping risks before we move this workload to a multi-zone architecture." + +Expected output: + +- A capacity-readiness assessment with quota, region, zone, reservation, and utilization findings. +- Recommended capacity actions, such as quota requests, reservation group changes, region alternatives, or monitoring tasks. +- Explicit distinction between capacity guarantees and pricing commitments so teams don't treat reservations, savings plans, and quota as interchangeable. + +Use this agent versus another: + +- Use `azure-capacity-manager` when supply availability is the main question: quota, capacity reservations, region access, zones, AKS node pools, or capacity governance. +- Use `finops-practitioner` instead when the question is primarily about FinOps operating model, allocation, anomaly response, or broad cost optimization. +- Use `chief-financial-officer` instead when capacity decisions need executive budget framing, investment trade-offs, or board-ready risk language. +- Use `ftk-database-query` instead when you need exact Hub Kusto results about cost, utilization, recommendations, or pricing before making a capacity decision. +- Use `ftk-hubs-agent` instead when the capacity issue is blocking a hub deployment, upgrade, or configuration workflow. + +
+ +## chief-financial-officer + +Domain: Executive finance, budgeting, forecasting, risk, capital allocation, cloud economics, and board-ready FinOps narratives. + +The `chief-financial-officer` agent turns evidence packages into financial guidance. It focuses on business outcomes, executive summaries, quantified assumptions, and decision-ready recommendations. It is a consultative persona and doesn't own autonomous scheduled tasks or raw data collection. + +What it does: + +- Prepares budgeting, rolling forecasts, variance analysis, and KPI-driven performance views. +- Evaluates investment priorities, capital allocation, risk, controls, and compliance exposure. +- Assesses cloud spend through unit economics, commitment decisions, and value creation. +- Produces recommendations for boards, CEOs, finance leaders, and FinOps stakeholders. +- Calls out missing data, uncertainty, risks, and follow-up steps. + +Key tools it uses: + +- Python analysis through `execute_python` for scenario calculations and executive packaging +- Evidence packages from `finops-practitioner`, `ftk-database-query`, and `azure-capacity-manager` +- Teams tools for final communication when a configured workflow asks for executive delivery + +When it's invoked: + +- A user asks for executive summaries, budget variance, forecast drift, board narratives, or portfolio trade-offs. +- The `finops-practitioner` agent needs finance leadership for executive framing, prioritization, commitment risk, or investment tradeoffs. + +Example prompts: + +- "Summarize cloud spend performance for the CFO with risks, opportunities, and decisions needed this week." +- "Explain the budget variance for the quarter and separate timing issues from structural run-rate changes." +- "Create a board-ready narrative for our AI investment, including unit economics and governance risks." +- "Prioritize these three optimization programs by financial impact, execution risk, and business value." + +Expected output: + +- An executive-ready finance view with quantified assumptions, variance explanations, risks, options, and recommended decisions. +- Budget, forecast, portfolio, or investment guidance that connects cloud spend to business outcomes. +- Clear caveats for missing evidence, confidence level, and follow-up data needed before committing to a decision. + +Use this agent versus another: + +- Use `chief-financial-officer` when the audience is executives, finance leaders, boards, or business owners making budget, forecast, risk, or investment decisions. +- Use `finops-practitioner` instead when the work needs broader FinOps process guidance, practitioner playbooks, or operating-model design. +- Use `ftk-database-query` instead when the deliverable is detailed KQL, data extraction, schema validation, pricing lookup, or recommendation analysis. +- Use `azure-capacity-manager` instead when the core issue is capacity supply, quota, zones, reservation groups, or regional access. +- Use `ftk-hubs-agent` instead when financial reporting is blocked by hub deployment, export, connectivity, version, or health issues. + +
+ +## ftk-database-query + +Domain: FinOps hub database analysis, FOCUS-aligned KQL, schema validation, query diagnostics, pricing, recommendations, and transactions. + +The `ftk-database-query` agent is the KQL specialist. It queries the Hub database, explains schema choices, and adapts catalog queries before writing custom KQL. + +What it does: + +- Uses the Hub database for analytics and avoids the Ingestion database for end-user analysis. +- Starts with the query catalog and adapts the closest existing query when possible. +- Builds scoped custom drill-downs from `costs-enriched-base` when no catalog query fits and uses aggregate tools for full-month or scheduled reports. +- Uses `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()` for FOCUS-aligned analysis. +- Explains filters, functions, metrics, missing data, and data freshness concerns. + +Key tools it uses: + +- Memory and Azure discovery through `SearchMemory`, `RunAzCliReadCommands`, and `GetAzCliHelp` +- Python analysis through `execute_python` +- The full FinOps hub Kusto catalog, including `costs-enriched-base`, `monthly-cost-trend`, `top-services-by-cost`, `cost-by-region-trend`, `cost-anomaly-detection`, `cost-forecasting-model`, `commitment-discount-utilization`, `savings-summary-report`, `top-other-transactions`, and AI cost tools + +When it's invoked: + +- A user asks for a KQL query, schema explanation, pricing lookup, recommendation analysis, transaction analysis, or cost drill-down. +- A scheduled task needs exact FinOps hub data, a focused diagnostic, or FOCUS-aligned query execution. +- Another agent needs live cost data or schema-aware analysis before making a recommendation. + +Example prompts: + +- "Write a FOCUS-aligned KQL query that shows month-over-month cost by service and billing account." +- "Use the Hub database to find the top resources driving last week's cost anomaly." +- "Explain which columns from `Costs()` I should use for amortized cost, list cost, and chargeback reporting." +- "Compare prices for this SKU across regions and show the assumptions in the query." + +Expected output: + +- A query-first answer with the selected catalog query or custom KQL, filters, assumptions, and expected columns. +- Data interpretation that explains schema choices, functions, time windows, aggregation grain, and freshness limitations. +- Diagnostics for query failures or missing results, including what to validate in the Hub database or source exports. + +Use this agent versus another: + +- Use `ftk-database-query` when the question depends on exact FinOps hub data, KQL, schema details, pricing data, recommendations, or transaction records. +- Use `finops-practitioner` instead when you need to turn query results into a broader FinOps plan, operating-model recommendation, or governance approach. +- Use `chief-financial-officer` instead when data results need to become an executive budget, forecast, risk, or portfolio decision narrative. +- Use `azure-capacity-manager` instead when the query is only supporting quota, capacity reservation, regional supply, zone, or AKS readiness decisions. +- Use `ftk-hubs-agent` instead when the problem is that hub data is missing, stale, inaccessible, or caused by deployment or export health issues. + +
+ +## ftk-hubs-agent + +Domain: FinOps hubs deployment, upgrades, configuration, exports, dashboards, connectivity, and health. + +The `ftk-hubs-agent` agent keeps FinOps hubs running. It uses validation-first workflows for deployment, upgrade, maintenance, and troubleshooting. + +What it does: + +- Deploys and upgrades FinOps hubs. +- Maintains hub configuration, exports, dashboards, and connectivity. +- Troubleshoots deployment failures and unhealthy hub environments. +- Checks prerequisites, required resource providers, RBAC, regions, quotas, naming conflicts, and existing resources. +- Runs template validation and what-if checks before deploy or upgrade changes. + +Key tools it uses: + +- Knowledge search through `SearchMemory` +- Azure CLI tools, such as `RunAzCliReadCommands`, `RunAzCliWriteCommands`, and `GetAzCliHelp` +- Direct REST freshness checks through `data-freshness-check`, which treats `Costs()` as the source of truth for hub data freshness + +When it's invoked: + +- A user asks to deploy, upgrade, configure, maintain, or troubleshoot FinOps hubs. +- A scheduled health task checks FinOps hub readiness, export freshness, version status, or connectivity. +- Another agent needs hub health context before trusting query results or scheduled reports. + +Example prompts: + +- "Validate whether my environment is ready to deploy FinOps hubs and list any blocking prerequisites." +- "Troubleshoot why my Cost Management exports are not showing up in the Hub database." +- "Plan a safe FinOps hubs upgrade and include validation, what-if, and rollback checks." +- "Check hub data freshness and explain whether reports should trust the current `Costs()` results." + +Expected output: + +- A deployment, upgrade, configuration, or troubleshooting plan that starts with validation and identifies blockers before changes. +- Hub health findings for prerequisites, RBAC, providers, exports, connectivity, version status, and data freshness. +- Recommended next actions, including safe validation commands, what-if checks, and escalation points when write operations are required. + +Use this agent versus another: + +- Use `ftk-hubs-agent` when the work changes or diagnoses the FinOps hub platform itself: deployment, upgrade, configuration, exports, connectivity, dashboards, or health. +- Use `ftk-database-query` instead when the hub is healthy and the question is about KQL, schema, pricing, recommendations, transactions, or cost drill-downs. +- Use `finops-practitioner` instead when hub data needs to become a FinOps process, optimization, allocation, governance, or anomaly response recommendation. +- Use `chief-financial-officer` instead when hub findings need executive finance framing, budget guidance, or portfolio prioritization. +- Use `azure-capacity-manager` instead when a deployment or scaling issue is primarily about Azure quota, capacity reservation supply, region access, or zones. + +
+ +## Handoff model + +The orchestrator starts with the user's prompt or scheduled task instructions. It selects the agent whose `handoffDescription` best matches the task, then passes the conversation to that specialist. + +Agents can also recommend handoffs when the work crosses domain boundaries: + +- `finops-practitioner` hands executive finance narratives, portfolio prioritization, and board-level recommendations to `chief-financial-officer`. +- `finops-practitioner` hands deep FinOps hub database and KQL work to `ftk-database-query`. +- `finops-practitioner` hands capacity evidence requests to `azure-capacity-manager` when the task involves quota, capacity reservations, region access, zones, AKS capacity, or capacity governance. +- Hub deployment, upgrade, and troubleshooting work routes to `ftk-hubs-agent`. + +Handoffs keep each response focused. The FinOps specialist can frame the business problem, the KQL specialist can gather evidence, the capacity specialist can validate supply constraints, and the finance specialist can turn the findings into an executive decision. + +
+ +## Skills + +Skills give agents a domain reference map. The template applies all three skills to Azure SRE Agent. When a prompt or scheduled task enters one of these domains, the matching skill can load before the agent responds. + +### azure-capacity-management + +Provides Azure capacity management guidance for SaaS ISVs running workloads in their own Azure subscriptions under Enterprise Agreement or Microsoft Customer Agreement billing. It covers quota operations, quota groups, capacity reservation groups, region access, zonal enablement, AKS capacity governance, non-compute quotas, and capacity alerts. In this recipe, those references are used as implementation detail under the canonical FinOps Framework capabilities. + +The `azure-capacity-manager` agent is instructed to load this skill before capacity work. Capacity scheduled tasks also tell the agent to load it before checking quota, capacity reservation, SKU, or supply-readiness signals. + +### azure-cost-management + +Provides Azure cost optimization and financial governance guidance. It covers Advisor recommendations, commitment discounts, budgets, exports, anomaly alerts, credits, Microsoft Azure Consumption Commitment tracking, orphaned resources, VM rightsizing, and Azure retail price lookup. + +FinOps and reporting scheduled tasks load this skill with the `finops-toolkit` skill when they need Microsoft Cost Management context beyond FinOps hub Kusto data. + +### finops-toolkit + +Provides FinOps toolkit and FinOps hubs guidance. It maps tasks to the right references, explains Hub database functions, lists the Kusto query catalog, and covers hub deployment, upgrade, health checks, FOCUS mapping, Power BI, alerts, workbooks, and the FinOps toolkit for PowerShell. + +FinOps hub query, reporting, and AI cost tasks load this skill so agents can use the Hub database, `Costs()`, `Prices()`, `Recommendations()`, `Transactions()`, and the predefined Kusto query catalog correctly. + +
+ +## How agents, tools, skills, and knowledge work together + +The agent combines four layers: + +1. **Agents** route the work to the right specialist. +2. **Skills** load domain guidance and reference maps. +3. **Tools** gather evidence from Azure, FinOps hubs, Python analysis, and Kusto queries. +4. **Knowledge** supplies onboarding guidance, notification patterns, and known issue context. + +Together, these layers help the agent move from a question to an evidence-backed recommendation. The orchestrator delegates, the specialist loads the right skill, tools collect the data, and knowledge keeps the answer aligned with the deployed environment. The FinOps practitioner coordinates the operating model, the database specialist gathers Kusto evidence, the capacity specialist gathers Azure capacity evidence, and the CFO supplies finance and leadership framing. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Cost allocation](../../framework/understand/allocation.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Architecting for cloud](../../framework/optimize/architecting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md new file mode 100644 index 000000000..3e135a6fe --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -0,0 +1,219 @@ +--- +title: Deploy Azure SRE Agent with the FinOps toolkit +description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: tutorial +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps hub admin, I want to deploy and configure the FinOps toolkit's Azure SRE Agent so that I can receive scheduled cost reports, anomaly detection, and capacity monitoring. +--- + + + +# Deploy Azure SRE Agent with the FinOps toolkit + +In this tutorial, you learn how to deploy the [FinOps toolkit Azure SRE Agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), connect it to a [FinOps hub](../hubs/finops-hubs-overview.md), and validate the deployment. + +The deployment flow is copied from the Microsoft SRE Agent starter lab and updated for the FinOps toolkit. The Azure portal path uses the toolkit's packaged ARM template and an embedded deployment script to apply the SRE Agent recipe. The local CLI path uses Azure CLI + Bicep for infrastructure and the supported SRE Agent ARM and data-plane surfaces for recipe configuration. It doesn't use `azd`. + +## What gets deployed + +The FinOps hub recipe (`src/templates/sre-agent/recipes/finops-hub/`) deploys: + +| Component | Count | Notes | +|-----------|-------|-------| +| SRE Agent | 1 | `Microsoft.App/agents` | +| Model provider | 1 | Azure OpenAI provider-level routing (`MicrosoftFoundry` ARM value, `Automatic` model routing) | +| Managed identities | 1-2 | Agent system-assigned managed identity; portal deployments also create a user-assigned identity for the deployment script | +| Log Analytics workspace | 1 | Linked to the agent for telemetry | +| Application Insights | 1 | Linked to Log Analytics | +| Custom agents | 5 | FinOps practitioner orchestrator plus CFO, capacity, database-query, and hubs specialists | +| Skills | 3 | Capacity, cost management, and FinOps Toolkit | +| Tools | 50 | Kusto, capacity, and Hub infrastructure tools | +| Tool overrides | 9 | Enables SRE Agent Log Query and Visualization tools | +| Scheduled tasks | 19 | FinOps, governance, and reporting automations | +| Kusto connector | 0 or 1 | Included when you pass `--cluster-uri` | +| Knowledge docs | 6 | Five recipe knowledge docs plus the FinOps Toolkit output style | + +## Prerequisites + +- A deployed FinOps hub with Data Explorer. +- Permissions to create deployed resources, such as **Contributor** on the subscription when the template creates the agent resource group. +- Permissions to assign roles at subscription, target resource group, and agent scopes, such as **Role Based Access Control Administrator**, **User Access Administrator**, or **Owner** on those scopes. +- The `Microsoft.App` resource provider registered in the subscription. +- For local CLI deployments only: [Azure CLI](/cli/azure/install-azure-cli), `curl`, `jq`, `python3` with `PyYAML`, and Bash 3.2 or newer. + +Run: + +```bash +cd src/templates/sre-agent +bash bin/check-prerequisites.sh --subscription +``` + +## Deploy the FinOps hub recipe + +Use the Azure portal deployment when you want the same one-click experience as other FinOps toolkit templates. The template creates the Azure resources, grants the deployment script identity SRE Agent Administrator on the agent, downloads the packaged recipe assets, and applies connectors, tools, skills, subagents, knowledge, and scheduled tasks. + + +> [!div class="nextstepaction"] +> [Deploy to Azure](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2Fazuredeploy.json/createUIDefinitionUri/https%3A%2F%2Fmicrosoft.github.io%2Ffinops-toolkit%2Fdeploy%2Fsre-agent%2Flatest%2FcreateUiDefinition.json) + + +### Deploy from local CLI + +Run one script with explicit parameters: + +```bash +cd src/templates/sre-agent + +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] \ + [--target-resource-group ...] \ + [--dry-run] \ + [--force] \ + [--no-telemetry] +``` + +`bin/deploy.sh --help` is the CLI contract: + +```text +Usage: bash bin/deploy.sh --recipe [options] + +Required: + --recipe Recipe directory + --subscription Azure subscription + -g, --resource-group Resource group for the agent + -n, --name Agent name + -l, --location Azure region + +Optional: + --target-resource-group Repeatable target resource group. Defaults to --resource-group. + --cluster-uri Kusto connector URI, including database name. + Example: https://..kusto.windows.net/Hub + --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. + --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deploy-name Deployment name override. Defaults to a deterministic name. + --dry-run Validate inputs and write parameters without Azure calls. + --force Accepted for compatibility. + --no-telemetry Accepted for compatibility. + -h, --help Show this help. +``` + +## Validation modes + +Dry-run is hermetic and skips live Azure calls: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + -g \ + -n \ + -l \ + --cluster-uri https://..kusto.windows.net/Hub \ + --cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/ \ + --dry-run +``` + +When deploying from the portal, the template runs a subscription-scoped ARM deployment and then runs a `Microsoft.Resources/deploymentScripts` resource to configure the Kusto connector and remaining recipe assets through the supported SRE Agent ARM and data-plane surfaces. When deploying locally, `deploy.sh` runs the same subscription-scoped infrastructure deployment and then runs `bin/apply-extras.sh` for the recipe configuration step. + +The recipe defaults the parent SRE Agent to Azure OpenAI provider-level routing by setting `defaultModel.provider` to `MicrosoftFoundry` and `defaultModel.name` to `Automatic`. Azure SRE Agent automatically selects the model within the configured provider for each task. The template doesn't pin different models for individual custom agents or scheduled tasks because the documented SRE Agent configuration surface is provider-level. + +Resource names are deterministic for the subscription ID, agent resource group ID, and agent name. Use the same values to update an existing deployment. Post-provisioning deletes existing scheduled tasks with the recipe's task names before applying manifests so redeployments don't create duplicate automations. `--deploy-name` only changes the ARM deployment record and local build directory. + +The deployment assigns `Reader` at subscription scope by default so subscription inventory, Resource Graph, capacity, quota, and monitoring-coverage tools can inspect the deployment subscription. Pass `--no-subscription-reader` only when you grant equivalent read access another way. + +If `--cluster-uri` points to an Azure Data Explorer cluster with `publicNetworkAccess` set to `Disabled`, the script still deploys all resources, assigns the agent identity `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. It also prints a warning with the SRE Agent known-limitations URL because private endpoint ADX blocks direct KQL queries from the hosted agent. The customer can decide whether to enable public query access for the connector after reviewing . + +## Recipe identity defaults + +- Shipped recipes in this repo omit the `identity` block. +- Customer-authored recipes can keep identity defaults in `agent.json`. +- CLI flags always override recipe defaults. + +If you omit `--target-resource-group`, the deploy flow uses the recipe default when present; otherwise it falls back to the agent resource group. + +## Verify the deployment + +```bash +bash bin/verify-agent.sh \ + $(az account show --query id -o tsv) \ + \ + \ + --expected recipes/finops-hub +``` + +Then confirm the agent in [sre.azure.com](https://sre.azure.com). If you passed `--cluster-uri`, verify the `finops-hub-kusto` connector. If the deployment warned that the cluster denies public query access, the connector is expected to remain unhealthy until the customer enables public query access or Microsoft adds private endpoint ADX query support for SRE Agent. + +## Configure notifications + +Scheduled tasks deliver reports to Microsoft Teams and Outlook through Azure SRE Agent notification connectors. Connectors require interactive OAuth setup in [sre.azure.com](https://sre.azure.com), so the portal template and `bin/deploy.sh` don't create them. + +### Configure Teams + +1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. +2. Select **Add connector** > **Send notification (Microsoft Teams)**. +3. Sign in with your Microsoft 365 account. +4. Paste the channel URL from **Get link to channel** in Teams. +5. Select the agent's managed identity and save. +6. Test from chat: `Post a test message to our Teams channel saying "Azure SRE Agent connected via the FinOps toolkit."` + +Use the built-in `PostTeamsMessage` tool from the [Teams notification guidance](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md). Don't call the Microsoft Graph API or the connection's `dynamicInvoke` endpoint directly because that path returns a 403 error for this connector configuration. + +### Configure Outlook + +1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. +2. Select **Add connector** > **Outlook Tools (Office 365 Outlook)**. +3. Sign in with a Microsoft 365 account that has mailbox access. +4. Select the agent's managed identity and save. +5. Test from chat: `Send an email to with subject "SRE Agent test" and body "Outlook connector is working."` + +For more information, see [Send notifications in Azure SRE Agent](/azure/sre-agent/send-notifications). + +## GitHub Actions example + +The included GitHub Actions example passes the cluster URI as a deploy flag while leaving secret-only inputs such as `GITHUB_PAT` and `ADO_PAT` in the environment. + +## Migrating from env-var-driven deploys + +The old deploy flow used configuration inputs such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, `SRE_AGENT_NO_TELEMETRY`, and `connectors.secrets.env`. Those inputs are no longer supported for identity or config. + +Before: + +```bash +export FINOPS_HUB_CLUSTER_URI="https://..kusto.windows.net/hub" +export FINOPS_HUB_CLUSTER_RESOURCE_ID="/subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/" +export SRE_AGENT_NO_TELEMETRY=1 +bash bin/deploy.sh recipes/finops-hub +``` + +After: + +```bash +bash bin/deploy.sh \ + --recipe recipes/finops-hub \ + --subscription \ + --resource-group \ + --name \ + --location \ + --cluster-uri https://..kusto.windows.net/Hub \ + [--cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/] \ + --no-telemetry +``` + +The only supported environment-variable inputs are secrets: + +- `GITHUB_PAT` +- `ADO_PAT` +- `ADO_USE_AAD` +- `ADO_USE_MI` +- `ADO_ORG` diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md new file mode 100644 index 000000000..7aba04595 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -0,0 +1,135 @@ +--- +title: Get started with the FinOps toolkit on Azure SRE Agent +description: Learn what to do after deploying Azure SRE Agent with the FinOps toolkit — first queries, scheduled tasks, and specialized subagents. +author: flanakin +ms.author: micflan +ms.date: 05/25/2026 +ms.topic: quickstart +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: arclares +# customer intent: As a FinOps practitioner, I want to know what to do after deploying the FinOps toolkit's Azure SRE Agent so I can start getting value from it immediately. +--- + +# Get started with the FinOps toolkit on Azure SRE Agent + +You've deployed [Azure SRE Agent with the FinOps toolkit](overview.md). Here's how to start using it after the [deployment workflow](deploy.md) finishes. + +The [deployment guide](deploy.md) covers how to deploy and configure the agent. This guide focuses on what to do next: post-deployment prompts, [scheduled tasks](scheduled-tasks.md), [specialist agents](agents.md), and customization. + +
+ +## Talk to the agent + +Azure SRE Agent responds to natural language questions about your Azure environment. The [tool catalog](tools.md) describes how Kusto tools query [FinOps hubs](../hubs/finops-hubs-overview.md) data, while Python tools call Azure APIs. + +Ask questions the same way you'd ask another FinOps or platform engineer. The [agent and skills reference](agents.md) explains how the orchestrator routes work to specialist agents that use tools, skills, and knowledge to ground recommendations. + +
+ +## Automation map + +Use this map to connect each post-deployment activity to the agent, task, tool, output, and decision pattern. The [Azure SRE Agent overview](overview.md), [agents reference](agents.md), [tools reference](tools.md), and [scheduled tasks reference](scheduled-tasks.md) document the full catalog. + +| Capability | Agent | Tasks | Tools | Output | You decide | +|------------|-------|-------|-------|--------|------------| +| Cost visibility and anomaly review | [`finops-practitioner`](agents.md#finops-practitioner) | [`Monthly`](scheduled-tasks.md#monthly), [`CostOptimization`](scheduled-tasks.md#costoptimization), and [`AlertCoverageAudit`](scheduled-tasks.md#alertcoverageaudit) | [Cost analysis](tools.md#cost-analysis-and-reporting), [anomaly detection](tools.md#anomaly-detection-and-forecasting), [forecasting](tools.md#anomaly-detection-and-forecasting), and [rate optimization](tools.md#rate-optimization) tools through [`ftk-database-query`](agents.md#ftk-database-query) where Kusto evidence is required | Cost drivers, anomaly findings, forecasts, and prioritized actions from the scheduled task outputs | Which owners investigate, which anomalies are expected, and which optimization actions should move first | +| Capacity and quota posture | [`azure-capacity-manager`](agents.md#azure-capacity-manager) | [`CapacityDailyMonitor`](scheduled-tasks.md#capacitydailymonitor), [`ComputeUtilizationTrend`](scheduled-tasks.md#computeutilizationtrend), [`CapacityWeeklySupplyReview`](scheduled-tasks.md#capacityweeklysupplyreview), and [`NonComputeQuotaAudit`](scheduled-tasks.md#noncomputequotaaudit) | [`vm-quota-usage`](tools.md#capacity-management), [`capacity-reservation-groups`](tools.md#capacity-management), [`non-compute-quotas`](tools.md#capacity-management), and [`sku-availability`](tools.md#capacity-management) | Quota pressure, capacity reservation waste, SKU restrictions, and capacity blockers from the capacity task outputs | Which quota requests, region changes, reservation changes, or workload moves need action | +| Finance and commitment decisions | [`finops-practitioner`](agents.md#finops-practitioner), consulting [`chief-financial-officer`](agents.md#chief-financial-officer) | [`BenefitRecommendationReview`](scheduled-tasks.md#benefitrecommendationreview), [`Semiannual`](scheduled-tasks.md#semiannual), and [`AIWorkloadCostAnalysis`](scheduled-tasks.md#aiworkloadcostanalysis) | [Benefit, savings, commitment, forecasting, and AI cost tools](tools.md#rate-optimization) through [`ftk-database-query`](agents.md#ftk-database-query) where Kusto evidence is required | Executive summaries, savings opportunities, forecast risk, and decision-ready commitment context from FinOps task outputs with CFO framing | Which purchases, deferrals, budget changes, or executive escalations are approved | +| Hub health and data trust | [`ftk-hubs-agent`](agents.md#ftk-hubs-agent) | [`HubsHealthCheck`](scheduled-tasks.md#hubshealthcheck) and [`MonitoringScopeValidation`](scheduled-tasks.md#monitoringscopevalidation) | [`data-freshness-check`](tools.md#data-ingestion-and-health), Azure discovery, and hub configuration tools | Hub version, connectivity, data freshness, and monitoring coverage findings from hub health task outputs | Whether reports are trustworthy, which exports need repair, and when to pause analysis that depends on stale data | + +
+ +## Getting started: first things to try + +Start with focused questions that validate your data, summarize spend, and find common optimization opportunities that map to the documented [tool catalog](tools.md) and [scheduled-task coverage](scheduled-tasks.md#task-details). + +1. Check your data pipeline and scheduled outputs: "Is my FinOps hubs data fresh, which [scheduled tasks](scheduled-tasks.md#task-details) ran recently, and what reports or Teams notifications did they produce?" +2. Review your spending and waste: "What did we spend last month by subscription, and which idle VMs across subscriptions should we investigate first?" +3. Review anomalies: "Show me this week's cost anomalies, explain the likely drivers, and recommend who should investigate each one." +4. Find savings: "What reservation recommendations do I have?" +5. Check capacity posture: "What's my quota utilization in eastus?" + +If a response doesn't have enough context, narrow the question by subscription, management group, billing scope, region, resource type, or reporting period so the agent can select focused tools and filters from the [tool catalog](tools.md). + +
+ +## Scheduled tasks run automatically + +The agent runs [19 scheduled tasks](scheduled-tasks.md) on daily, weekly, monthly, semiannual, and quarterly cadences. The [scheduled tasks reference](scheduled-tasks.md) lists daily, weekly, monthly, semiannual, and quarterly tasks for health, optimization, capacity, planning, finance, and strategy reviews. + +You don't need to trigger scheduled tasks because each task has a cron expression in its task definition, and [task details](scheduled-tasks.md#task-details) describe how reports are formatted for Microsoft Teams when notifications are configured. + +Customize the defaults before you rely on the automation in production. Review each scheduled task's `cron_expression` and prompt thresholds in the [task details](scheduled-tasks.md#task-details), then adjust schedules and thresholds to match your operating rhythm, time zone, reporting calendar, and risk tolerance. + +For example, move the month-over-month report to run after billing data settles. Lower quota headroom thresholds for regions with known capacity pressure. Raise anomaly review thresholds for subscriptions with expected seasonal spikes. The [customization options](scheduled-tasks.md#task-details) cover each task in detail. + +
+ +## Build on the basics + +The agent includes [5 specialized subagents](agents.md), and you can ask the orchestrator to route the work or mention the specialist when you know which domain you need. + +- [`finops-practitioner`](agents.md#finops-practitioner) — cost analysis, optimization, budgets, alerts, and FinOps practice guidance +- [`azure-capacity-manager`](agents.md#azure-capacity-manager) — quota, capacity reservations, SKU availability, and capacity governance +- [`chief-financial-officer`](agents.md#chief-financial-officer) — consultative financial strategy, commitment decisions, budgeting, forecasting, and executive finance narratives +- [`ftk-database-query`](agents.md#ftk-database-query) — direct Kusto queries, schema validation, pricing, recommendations, and transactions against FinOps hubs +- [`ftk-hubs-agent`](agents.md#ftk-hubs-agent) — hub health, data freshness, exports, connectivity, deployment, and upgrade troubleshooting + +Use specialist names when you want a specific lens. For example, ask the [`chief-financial-officer`](agents.md#chief-financial-officer) agent to frame a commitment decision for leadership, or ask the [`ftk-database-query`](agents.md#ftk-database-query) agent to explain the KQL behind a cost trend. + +
+ +## Learn more + +Use these pages as your next steps: + +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Specialist agents and skills](agents.md) +- [Scheduled tasks (Azure SRE Agent in the FinOps toolkit)](scheduled-tasks.md) +- [FinOps toolkit best practices](../../best-practices/library.md) + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/GetStarted) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Architecting for cloud](../../framework/optimize/architecting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Specialist agents and skills](agents.md) +- [Scheduled tasks (Azure SRE Agent in the FinOps toolkit)](scheduled-tasks.md) +- [FinOps toolkit best practices](../../best-practices/library.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md new file mode 100644 index 000000000..7578736c3 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -0,0 +1,172 @@ +--- +title: Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) +description: Learn how knowledge grounds the FinOps toolkit's Azure SRE Agent in your team's context and how memory keeps operational learnings available across sessions and redeployments. +author: msbrett +ms.author: brettwil +ms.date: 05/25/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to manage knowledge and memory for Azure SRE Agent so that the agent can answer with my team's operational context. +--- + +# Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) + +Knowledge grounds the agent in your team's context. It helps the agent answer with your runbooks, known issues, notification patterns, and deployment details instead of relying on general guidance alone. + +Use knowledge and memory together: + +- **Knowledge** gives the agent trusted reference material, such as runbooks, architecture notes, and connector setup guidance. +- **Memory** keeps useful learnings from investigations, user instructions, and recurring operational patterns. +- **Session insights** help the agent learn from previous work, including what fixed an issue and what did not. + +
+ +## Shipped knowledge docs + +The [Azure SRE Agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent) uploads six knowledge documents during extras configuration. Five are under `recipes/finops-hub/knowledge/`; the shared FinOps Toolkit output style is uploaded from `src/templates/claude-plugin/output-styles/ftk-output-style.md`. The script uploads them as portal-visible Knowledge Sources and verifies the KnowledgeFile sources are indexed before continuing so missing or unindexed documents fail deployment instead of becoming a silent runtime issue. + +| Knowledge doc | What it provides | +|---|---| +| `chart-artifact-verification.md` | Guidance for validating generated charts, tables, and downloadable artifacts before sending reports to stakeholders. | +| `document-index.md` | Index of the shipped FinOps, capacity, and hub-operation documents the agent can use for grounding. | +| `ftk-output-style.md` | Shared report style for evidence-backed financial and capacity-management output, including FinOps capability sections, thresholds, confidence, caveats, and disclaimers. | +| `onboarding-recommendations.md` | First-run guidance for team onboarding, `/learn`, and "What should I do next?" prompts. It reminds the agent to validate Azure access, enable visualization tools, configure FinOps hub data sources, and recommend Outlook and Microsoft Teams connectors when needed. | +| `teams-notification-guide.md` | Delivery guidance for scheduled reports and notifications. It tells the agent to use the built-in `PostTeamsMessage` and `ReplyToTeamsThread` tools, format Teams messages as HTML, and avoid unsupported direct calls to Microsoft Graph or connector endpoints. | +| `known-issues-and-workarounds.md` | Operational workarounds found during scheduled task validation. It covers stale data detection, Resource Graph fallbacks, quota command issues, JMESPath escaping, memory write conflicts, Kusto query errors, and the split between financial data in Teams and operational learnings in memory. | + +> [!TIP] +> Keep these docs short and practical. The agent uses them best when each file gives clear instructions, constraints, and examples. + +
+ +## Memory system + +Azure SRE Agent uses memory to carry context forward between threads. The agent extends that with these memory layers to improve recommendations over time. + +### Session insights + +Session insights are extracted automatically after a thread goes quiet. They capture useful details from the conversation, such as: + +- Symptoms observed +- Resolution steps +- Root cause +- Pitfalls to avoid + +For FinOps operations, this helps the agent remember patterns like stale export data, commands that failed, fallbacks that worked, and report delivery issues. Session insights are most useful when users correct or rate responses after an investigation. + +### User memories + +User memories are explicit facts that you ask the agent to save. Use them for stable details the agent should remember, such as team preferences, environment constraints, or recurring operational notes. + +Use these commands in chat: + +- `#remember` to save a fact +- `#retrieve` to find saved facts +- `#forget` to delete a saved fact + +> [!IMPORTANT] +> Save operational context, not sensitive financial figures. Send costs, savings, forecasts, and grade results to Teams reports instead of persisting them in memory. + +### Proactive knowledge persistence + +The agent also maintains synthesized knowledge files under `memories/synthesizedKnowledge/`. + +- `overview.md` is loaded when a conversation starts and acts as an at-a-glance summary. +- Topic files store deeper notes, such as team context, architecture, deployment patterns, logs, auth, debugging notes, and reusable queries. + +The agent updates these files by merging new information and removing outdated details. This gives the agent a durable, compact summary of what your team has learned. + +
+ +## Knowledge sources in the portal + +You can add more knowledge in [sre.azure.com](https://sre.azure.com) from **Builder** > **Knowledge sources**. + +Knowledge sources can include: + +- **Files**: Upload runbooks, architecture docs, escalation guides, API docs, and team procedures. +- **Web pages**: Connect stable documentation pages that the agent should cite. +- **Repositories**: Connect source repositories when code, configuration, or markdown docs should ground agent responses. + +Use uploaded files for stable content. Use connected sources for content that changes often, such as a wiki, repository, or live documentation site. + +The template upload path uses the same SRE Agent data-plane contract as the portal file upload flow: `PUT /api/v2/extendedAgent/connectors/{name}` with `type: KnowledgeItem` and `dataConnectorType: KnowledgeFile`. Validate the shipped knowledge with `bin/verify-agent.sh`, the `bin/apply-extras.sh` output, or **Builder** > **Knowledge sources**. + +
+ +## Knowledge across redeployments + +Knowledge from the template persists across redeployments through the extras configuration step. + +When you run `bin/deploy.sh`, the template provisions Azure resources and then runs `bin/apply-extras.sh`. The extras script uploads everything under `recipes/finops-hub/knowledge/`, uploads the shared output style, and waits for the expected KnowledgeFile sources to appear as indexed: + +```bash +for file in "$REPO_ROOT"/src/templates/sre-agent/recipes/finops-hub/knowledge/*.md; do + PUT "$SRE_AGENT_ENDPOINT/api/v2/extendedAgent/connectors/$(basename "$file")" +done +PUT "$SRE_AGENT_ENDPOINT/api/v2/extendedAgent/connectors/ftk-output-style.md" +curl -H "Authorization: Bearer $TOKEN" "$SRE_AGENT_ENDPOINT/api/v2/extendedAgent/connectors" +``` + +This keeps the shipped onboarding, artifact verification, Teams notification, document index, output-style, and known-issues guidance available after the agent is redeployed. If you add your own files to `recipes/finops-hub/knowledge/`, they are uploaded by the same step. + +
+ +## Best practices + +Use knowledge for information the agent should trust and cite. + +- Upload runbooks, architecture guides, escalation paths, known issues, connector setup notes, and service-specific troubleshooting guides. +- Name files by task or topic, such as `aks-scale-out-runbook.md`, `finops-hub-kusto-queries.md`, or `teams-report-delivery.md`. +- Keep one purpose per file so the agent can retrieve the right source quickly. +- Include owner, date, scope, prerequisites, and last review notes in operational docs. +- Avoid secrets, credentials, personal data, and raw financial figures. +- Review knowledge quarterly to remove stale workarounds, retire old commands, and add new operational learnings. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +
+ +## Vote on or suggest ideas + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Workload management](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Microsoft Teams](https://learn.microsoft.com/microsoftteams/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [FinOps toolkit Power BI reports](../power-bi/reports.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md new file mode 100644 index 000000000..7c2ca749b --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -0,0 +1,497 @@ +--- +title: Kusto tools +description: Review the FinOps hub Kusto tools the FinOps toolkit ships for Azure SRE Agent and learn when to use each tool for cost, commitment discount, anomaly, forecast, AI, and price analysis. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand each Kusto tool the FinOps toolkit ships for Azure SRE Agent so that I can choose the right query for cost and optimization analysis. +--- + +# Kusto tools + +The FinOps toolkit deployment configures Azure SRE Agent with 37 Kusto tools that query your FinOps hub Azure Data Explorer database through the `finops-hub-kusto` connector. Each tool is configured as a `KustoTool` and generated from the FinOps hub query catalog to ground agent responses in cost, price, recommendation, transaction, KPI, and AI usage data. Query source lives at [`src/queries/catalog`](../../../src/queries/catalog/). The SRE Agent recipe rejects explicit Kusto YAML files so the query catalog stays the only source for Kusto tool definitions. + +This reference also calls out related optimization tools that appear in scheduled-task requirements when they affect the same analysis path. Those tools aren't Kusto tools unless explicitly marked as `KustoTool`. + +> [!IMPORTANT] +> Kusto tools require the hosted Azure SRE Agent to reach the Azure Data Explorer query endpoint. If the FinOps hub cluster has `publicNetworkAccess` set to `Disabled`, the toolkit still deploys the agent, assigns `AllDatabasesViewer`, and creates the connector, but the connector is expected to remain unhealthy. Review the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations), then decide whether to enable public query access for the cluster. + +Use this reference when you want to understand which tool fits a prompt, scheduled task, or custom agent workflow. For a summary of all the agent's tools, see [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md). + +
+ +## Source validation + +The template generates every FinOps hub Kusto tool from the 37 `.kql` files in [`src/queries/catalog`](../../../src/queries/catalog/). The recipe keeps 13 `PythonTool` YAML files in [`src/templates/sre-agent/recipes/finops-hub/config/tools`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/). Build validation fails if an explicit Kusto YAML file is added, if a catalog query doesn't generate exactly one Kusto tool, if a KPI-linked query isn't generated as a Kusto tool, or if a KPI-linked query isn't requested by any scheduled task. + +| Source category | Count | Evidence | +|-----------------|------:|----------| +| FinOps hub Kusto tools | 37 | Generated from [`src/queries/catalog/*.kql`](../../../src/queries/catalog/) by [`build-extras.py`](../../../src/templates/sre-agent/bin/build-extras.py). The catalog is indexed in [`src/queries/INDEX.md`](../../../src/queries/INDEX.md), and KPI-linked tools are mapped in [`src/queries/KPI.md`](../../../src/queries/KPI.md). | +| Related Python tools | 13 | [`benefit-recommendations`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml), [`capacity-reservation-groups`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml), [`data-freshness-check`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml), [`db-service-quotas`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml), [`deploy-anomaly-alert`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml), [`deploy-budget`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml), [`deploy-bulk-anomaly-alerts`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml), [`deploy-bulk-budgets`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml), [`non-compute-quotas`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml), [`resource-graph-query`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml), [`sku-availability`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml), [`suppress-advisor-recommendations`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml), and [`vm-quota-usage`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml) | + +
+ +## Cost analysis + +Use cost analysis tools to review cost and usage from different reporting angles, including time, service, resource group, region, billing hierarchy, and resource type. + +### costs-enriched-base + +Source query: [`costs-enriched-base.kql`](../../../src/queries/catalog/costs-enriched-base.kql). + +Queries a guarded, enriched row-level cost and usage sample with tags, resource details, savings fields, commitment fields, and FinOps toolkit metadata. + +Use it only for narrow detail drill-downs after an aggregate result identifies the scope to inspect. The tool rejects windows greater than one day to avoid Azure Data Explorer result truncation. For full-month, fiscal-period, scheduled report, dashboard export, allocation, showback, chargeback, tag-coverage, or broad custom analysis, use aggregate tools first, such as `monthly-cost-trend`, `cost-by-financial-hierarchy`, `top-services-by-cost`, `top-resource-groups-by-cost`, or `top-resource-types-by-cost`. + +Example prompt: "Show me enriched cost details for yesterday's top resource group, including tags and resource group." + +Sample output shape: One row per cost record with fields such as `ChargePeriodStart`, `SubAccountName`, `ResourceId`, `ResourceName`, `ResourceType`, `ServiceName`, `x_ResourceGroupName`, `BilledCost`, `EffectiveCost`, `ContractedCost`, `ListCost`, `PricingQuantity`, `Tags`, `CommitmentDiscountType`, `CommitmentDiscountStatus`, `x_TotalSavings`, and `x_FreeReason`. + +### monthly-cost-trend + +Source query: [`monthly-cost-trend.kql`](../../../src/queries/catalog/monthly-cost-trend.kql). + +Queries monthly billed and effective cost totals to show cost trends over time. + +Use it when you need a month-by-month view for budget reviews, executive summaries, or recurring FinOps reporting. It helps identify whether spend is increasing, decreasing, or stabilizing. + +Example prompt: "Show the monthly cost trend for the last six months." + +Sample output shape: One row per month with `x_ChargeMonth`, `BilledCost`, and `EffectiveCost`. + +### monthly-cost-change-percentage + +Source query: [`monthly-cost-change-percentage.kql`](../../../src/queries/catalog/monthly-cost-change-percentage.kql). + +Queries month-over-month billed and effective cost changes as percentages. + +Use it when stakeholders ask how much costs changed between months or when you need to find volatility quickly. It works well for variance reviews and cost spike triage. + +Example prompt: "Which months had the largest percentage increase in effective cost?" + +Sample output shape: One row per month with `ChargePeriodStart`, `BilledCost`, `EffectiveCost`, `PreviousBilledCost`, `PreviousEffectiveCost`, billed-cost change percentage, and effective-cost change percentage. + +### quarterly-cost-by-resource-group + +Source query: [`quarterly-cost-by-resource-group.kql`](../../../src/queries/catalog/quarterly-cost-by-resource-group.kql). + +Queries quarterly cost by resource group, subscription, and month for a reporting window. + +Use it when preparing quarterly business reviews or resource-group-level accountability reports. It helps teams connect quarterly cost movement to resource ownership and subscription context. + +Example prompt: "Break down quarterly costs by resource group for the last quarter." + +Sample output shape: One row per subscription, resource group, and month with `SubAccountName`, `x_ResourceGroupName`, `x_ChargeMonth`, and `EffectiveCost`. + +### cost-by-region-trend + +Source query: [`cost-by-region-trend.kql`](../../../src/queries/catalog/cost-by-region-trend.kql). + +Queries effective cost trends by Azure region. + +Use it when you need to understand regional cost distribution, investigate regional growth, or evaluate whether workloads are shifting between regions. It can also support capacity and placement discussions. + +Example prompt: "Show cost trends by Azure region over the last three months." + +Sample output shape: One row per region with `RegionName` and `EffectiveCost`. + +### cost-by-financial-hierarchy + +Source query: [`cost-by-financial-hierarchy.kql`](../../../src/queries/catalog/cost-by-financial-hierarchy.kql). + +Queries costs organized by billing profile, invoice section, team, product, application, environment, and other financial hierarchy fields. + +Use it when you need a finance-aligned view for allocation, showback, chargeback, or executive reporting. It helps translate resource-level usage into business ownership. + +Example prompt: "Summarize costs by billing profile, team, product, and application." + +Sample output shape: One row per financial hierarchy combination with `x_BillingProfileName`, `x_InvoiceSectionName`, `x_Team`, `x_Product`, `x_Application`, `x_Environment`, `EffectiveCost`, and `PercentOfTotal`. + +### top-services-by-cost + +Source query: [`top-services-by-cost.kql`](../../../src/queries/catalog/top-services-by-cost.kql). + +Queries the Azure services with the highest effective cost. + +Use it when you need to prioritize service-level optimization or identify which services drive overall spend. Start here for broad cost reviews before drilling into resources or resource groups. + +Example prompt: "What are the top 10 Azure services by cost this month?" + +Sample output shape: One row per service with `ServiceName` and `EffectiveCost`. + +### top-resource-types-by-cost + +Source query: [`top-resource-types-by-cost.kql`](../../../src/queries/catalog/top-resource-types-by-cost.kql). + +Queries the resource types with the highest effective cost and resource counts. + +Use it when you need to understand which resource categories are driving spend, such as virtual machines, disks, databases, or networking resources. It helps identify optimization themes across many resources. + +Example prompt: "List the top resource types by effective cost and resource count." + +Sample output shape: One row per resource type with `ResourceType`, `ResourceCount`, and `EffectiveCost`. + +### top-resource-groups-by-cost + +Source query: [`top-resource-groups-by-cost.kql`](../../../src/queries/catalog/top-resource-groups-by-cost.kql). + +Queries the resource groups with the highest effective cost. + +Use it when you need an owner-friendly cost view or want to focus optimization work on the most expensive resource groups. It is useful for team accountability and workload-level reviews. + +Example prompt: "Which resource groups had the highest costs in the last 30 days?" + +Sample output shape: One row per subscription and resource group with `SubAccountName`, `x_ResourceGroupName`, and `EffectiveCost`. + +
+ +## Commitment discounts + +Use commitment discount tools to review reservation and savings plan utilization, recommendations, realized savings, and purchase transactions. + +### commitment-discount-utilization + +Source query: [`commitment-discount-utilization.kql`](../../../src/queries/catalog/commitment-discount-utilization.kql). + +Queries consumed core hours by commitment discount type, including reservation, savings plan, and on-demand usage. + +Use it when you need to understand how well commitments are being used and whether uncovered on-demand usage remains. It helps compare capacity planning, usage patterns, and commitment coverage. + +Example prompt: "Show reservation and savings plan utilization for the last month." + +Sample output shape: One row per commitment category with `CommitmentDiscountType`, `TotalConsumedCoreHours`, and `PercentOfTotal`. Empty commitment types are reported as `On Demand`. + +### reservation-recommendation-breakdown + +Source query: [`reservation-recommendation-breakdown.kql`](../../../src/queries/catalog/reservation-recommendation-breakdown.kql). + +Queries detailed reservation recommendations, including savings, break-even dates, normalized sizes, scope, and term details. + +Use it when evaluating whether to buy reservations or when preparing a recommendation package for finance and workload owners. It helps compare potential savings with commitment risk. + +Example prompt: "Break down reservation purchase recommendations by service, term, and expected savings." + +Sample output shape: One row per reservation recommendation with fields such as `RegionId`, normalized size or group details, `x_SkuMeterId`, `x_SkuTerm`, expected before and after effective cost, `x_BreakEvenMonths`, and `x_BreakEvenDate`. + +### benefit-recommendations + +Source query: [`benefit-recommendations.kql`](../../../src/queries/catalog/benefit-recommendations.kql). + +Gets Microsoft Cost Management benefit recommendations for savings plans and reserved instances at a billing scope. + +This is a related optimization tool, but it's a `PythonTool`, not a Kusto tool. Use it when the agent needs current Cost Management recommendation API results by billing scope, lookback period, and term. Use `reservation-recommendation-breakdown` when you need FinOps hub recommendation data from `Recommendations()`. + +Example prompt: "Get current savings plan and reservation benefit recommendations for this billing profile." + +Sample output shape: A JSON object with `billing_scope`, `lookback_period`, `term`, `count`, and `recommendations`. Each recommendation includes fields such as `type`, `savings`, `cost`, `total_cost`, `cost_without_benefit`, `term`, `break_even`, `id`, and `name`. If the request can't run, the object includes an `error` field. + +### savings-summary-report + +Source query: [`savings-summary-report.kql`](../../../src/queries/catalog/savings-summary-report.kql). + +Queries list cost, effective cost, negotiated savings, commitment savings, total savings, and savings rate. + +Use it when you need a summary of savings from discounts and commitments compared with pay-as-you-go pricing. It works well for executive reporting and rate optimization reviews. + +Example prompt: "Summarize total savings from negotiated rates and commitment discounts this month." + +Sample output shape: One row per billing currency with `BillingCurrency`, `ListCost`, `ContractedCost`, `EffectiveCost`, `x_NegotiatedDiscountSavings`, `x_CommitmentDiscountSavings`, `x_TotalSavings`, and `x_EffectiveSavingsRate`. + +### top-commitment-transactions + +Source query: [`top-commitment-transactions.kql`](../../../src/queries/catalog/top-commitment-transactions.kql). + +Queries the largest non-usage commitment discount purchase transactions, including reservations and savings plans. + +Use it when investigating major commitment-related charges, purchase timing, or renewal activity. It helps separate commitment purchases from normal usage costs. + +Example prompt: "Show the largest reservation and savings plan transactions this quarter." + +Sample output shape: One row per commitment purchase transaction with `ChargePeriodStart`, `ChargeCategory`, `BilledCost`, `BillingCurrency`, `CommitmentDiscountName`, `CommitmentDiscountNameUnique`, `CommitmentDiscountType`, `SubAccountName`, `SubAccountNameUnique`, `ResourceNameUnique`, and `x_ResourceGroupNameUnique`. + +
+ +## Anomaly detection + +Use anomaly detection tools to identify unusual cost patterns that need investigation. + +### cost-anomaly-detection + +Source query: [`cost-anomaly-detection.kql`](../../../src/queries/catalog/cost-anomaly-detection.kql). + +Queries cost time series and detects unusual spikes or drops across a configurable history window. + +Use it when you need to triage unexpected spend changes, monitor recurring cost health, or explain why costs moved outside the normal pattern. Pair it with cost drill-down tools to find the affected service, region, or resource group. + +Example prompt: "Detect cost anomalies over the last 90 days and explain the biggest spikes." + +Sample output shape: One time-series row with `ChargePeriodStart`, `CostSeries`, and `anomalies`, where the series arrays represent the analyzed interval and the anomaly markers. + +
+ +## Forecasting + +Use forecasting tools to project future cost based on historical patterns. + +### cost-forecasting-model + +Source query: [`cost-forecasting-model.kql`](../../../src/queries/catalog/cost-forecasting-model.kql). + +Queries historical cost trends and projects future effective cost. + +Use it when preparing budgets, rolling forecasts, or expected run-rate discussions. It is most helpful when recent historical usage is representative of near-term demand. + +Example prompt: "Forecast effective cost for the next three months based on recent trends." + +Sample output shape: One time-series row with `ChargePeriodStart`, `EffectiveCostSeries`, and `forecast`, where the forecast array extends the historical cost series for the requested future periods. + +
+ +## AI/ML costs + +Use AI/ML cost tools to analyze Azure OpenAI and related AI service costs, token usage, model efficiency, and application ownership. + +### ai-cost-by-application + +Source query: [`ai-cost-by-application.kql`](../../../src/queries/catalog/ai-cost-by-application.kql). + +Queries AI and machine learning costs by application, team, and environment tags. + +Use it when you need showback, chargeback, or ownership analysis for AI workloads. It helps map AI spend to the applications and teams consuming it. + +Example prompt: "Break down AI costs by application and environment for this month." + +Sample output shape: One row per application, team, environment, and cost center with fields such as `Application`, `Team`, `Environment`, `CostCenter`, `EffectiveCost`, `TokenCount`, and `CostPer1KTokens`. + +### ai-daily-trend + +Source query: [`ai-daily-trend.kql`](../../../src/queries/catalog/ai-daily-trend.kql). + +Queries daily AI and machine learning cost trends. + +Use it when you need to monitor day-to-day AI spend, spot sudden changes, or prepare daily operating reports. It can also provide context before investigating token or model-level drivers. + +Example prompt: "Show the daily AI cost trend for the last 30 days." + +Sample output shape: One row per day with `ChargePeriodStart`, daily AI cost, daily token count, and cost per 1,000 tokens. + +### ai-model-cost-comparison + +Source query: [`ai-model-cost-comparison.kql`](../../../src/queries/catalog/ai-model-cost-comparison.kql). + +Queries AI model costs so the agent can compare costs across models. + +Use it when evaluating model efficiency, unit economics, or opportunities to shift workloads to lower-cost models. It is useful for comparing model choices before changing application behavior. + +Example prompt: "Compare costs across AI models and identify the most expensive models per 1,000 tokens." + +Sample output shape: One row per model with `Model`, `TokenCount`, `EffectiveCost`, `ListCost`, `CostPer1KTokens`, `ListPer1KTokens`, and `DiscountPercent`. + +### ai-token-usage-breakdown + +Source query: [`ai-token-usage-breakdown.kql`](../../../src/queries/catalog/ai-token-usage-breakdown.kql). + +Queries AI token usage by model, model version, and input or output direction. + +Use it when token consumption is the suspected cost driver or when you need to separate prompt and completion usage. It helps connect AI cost changes to usage behavior. + +Example prompt: "Break down token usage by model and input versus output tokens for the last week." + +Sample output shape: One row per model and token direction with `Model`, `Direction`, `TokenCount`, `EffectiveCost`, `UnitCostPerToken`, and `CostPer1KTokens`. + +
+ +## FinOps KPI tools + +FinOps KPI tools are generated from the query catalog and map to query links in [`src/queries/KPI.md`](../../../src/queries/KPI.md). Scheduled tasks request these tools through `ftk-database-query` for monthly, semiannual, health, anomaly, capacity, storage, monitoring, AI, and benefit-review scorecards. + +### percentage-unallocated-costs + +Source query: [`percentage-unallocated-costs.kql`](../../../src/queries/catalog/percentage-unallocated-costs.kql). + +Measures the share of effective cost that lacks required allocation evidence for the reporting window. + +### percentage-untagged-costs + +Source query: [`percentage-untagged-costs.kql`](../../../src/queries/catalog/percentage-untagged-costs.kql). + +Measures the share of effective cost on resources that have no tags. + +### tagging-policy-compliance + +Source query: [`tagging-policy-compliance.kql`](../../../src/queries/catalog/tagging-policy-compliance.kql). + +Measures cost-weighted compliance with required tag keys. + +### allocation-accuracy-index + +Source query: [`allocation-accuracy-index.kql`](../../../src/queries/catalog/allocation-accuracy-index.kql). + +Measures directly attributed cost as a share of total effective cost. + +### anomaly-detection-rate + +Source query: [`anomaly-detection-rate.kql`](../../../src/queries/catalog/anomaly-detection-rate.kql). + +Measures the share of effective spend in anomaly-flagged daily buckets. + +### anomaly-variance-total + +Source query: [`anomaly-variance-total.kql`](../../../src/queries/catalog/anomaly-variance-total.kql). + +Quantifies signed and absolute unpredicted spend variance for detected anomaly events. + +### cost-visibility-delay + +Source query: [`cost-visibility-delay.kql`](../../../src/queries/catalog/cost-visibility-delay.kql). + +Measures cost data visibility delay from charge period end to Hub ingestion. + +### data-update-frequency + +Source query: [`data-update-frequency.kql`](../../../src/queries/catalog/data-update-frequency.kql). + +Measures FinOps hub ingestion update cadence from distinct ingestion timestamps. + +### commitment-utilization-score + +Source query: [`commitment-utilization-score.kql`](../../../src/queries/catalog/commitment-utilization-score.kql). + +Computes commitment utilization amount, potential, and score by commitment and currency. + +### commitment-discount-waste + +Source query: [`commitment-discount-waste.kql`](../../../src/queries/catalog/commitment-discount-waste.kql). + +Measures unused commitment value as a share of total commitment cost. + +### compute-spend-commitment-coverage + +Source query: [`compute-spend-commitment-coverage.kql`](../../../src/queries/catalog/compute-spend-commitment-coverage.kql). + +Measures compute spend covered by commitment discounts. + +### compute-cost-per-core + +Source query: [`compute-cost-per-core.kql`](../../../src/queries/catalog/compute-cost-per-core.kql). + +Computes hourly and effective average compute cost per consumed vCPU core hour. + +### cost-optimization-index + +Source query: [`cost-optimization-index.kql`](../../../src/queries/catalog/cost-optimization-index.kql). + +Computes the Hub-wide cost optimization index from current recommendations and cost context. + +### cost-per-gb-stored + +Source query: [`cost-per-gb-stored.kql`](../../../src/queries/catalog/cost-per-gb-stored.kql). + +Calculates storage cost per normalized GB-month. + +### macc-consumption-vs-commitment + +Source query: [`macc-consumption-vs-commitment.kql`](../../../src/queries/catalog/macc-consumption-vs-commitment.kql). + +Measures Microsoft Azure Consumption Commitment drawdown by billing profile and month. + +### storage-tier-distribution + +Source query: [`storage-tier-distribution.kql`](../../../src/queries/catalog/storage-tier-distribution.kql). + +Summarizes storage cost and GB-month distribution by access-tier bucket. + +
+ +## Usage optimization + +Use Usage Optimization tools to identify idle, orphaned, or wasteful resources before starting cleanup work. + +### idle-resource-sweep + +Source status: No `idle-resource-sweep.yaml` file appears in the source inventory for [`src/templates/sre-agent/recipes/finops-hub/config/tools`](../../../src/templates/sre-agent/recipes/finops-hub/config/tools/). + +Reviews idle or orphaned resource candidates for Usage Optimization. + +This Gate-named tool is a required analysis path, but the current template doesn't include an `idle-resource-sweep` Kusto tool YAML file. Until a dedicated tool is added, ground idle-resource reviews with `top-resource-types-by-cost`, `top-resource-groups-by-cost`, and narrow `costs-enriched-base` drill-downs. Then correlate candidates with Azure Resource Graph or Azure Advisor data through the relevant Python or built-in Azure tools before recommending cleanup. + +Example prompt: "Find likely idle or orphaned resources and group them by resource type, subscription, and estimated monthly cost." + +Sample output shape: A candidate list with fields such as `SubAccountName`, `ResourceId`, `ResourceName`, `ResourceType`, `x_ResourceGroupName`, `RegionName`, `ServiceName`, `EffectiveCost`, `LastUsageSignal`, `IdleReason`, `RecommendedAction`, and `Confidence`. When using the current template, this shape is assembled from existing cost aggregates, enriched cost rows, and external Azure inventory or recommendation signals rather than returned by a single shipped Kusto tool. + +
+ +## Price analysis + +Use price analysis tools to compare prices, savings, and non-commitment transactions that affect total cost. + +### service-price-benchmarking + +Source query: [`service-price-benchmarking.kql`](../../../src/queries/catalog/service-price-benchmarking.kql). + +Queries service price benchmarks, including list cost, contracted cost, effective cost, negotiated savings, commitment savings, and total savings. + +Use it when you need to compare prices across services or understand how negotiated and commitment discounts affect effective rates. It helps identify services with the largest rate optimization opportunity. + +Example prompt: "Benchmark service prices and show where negotiated or commitment savings are highest." + +Sample output shape: One row per service with `ServiceName`, `ListCost`, `ContractedCost`, `EffectiveCost`, negotiated savings, commitment discount savings, total savings, and savings percentages. + +### top-other-transactions + +Source query: [`top-other-transactions.kql`](../../../src/queries/catalog/top-other-transactions.kql). + +Queries the largest non-usage and non-commitment transactions, such as Marketplace or miscellaneous charges. + +Use it when costs don't reconcile to normal usage or commitment purchases. It helps isolate large one-time or nonstandard transactions that can distort monthly cost trends. + +Example prompt: "Show the largest non-usage and non-commitment transactions this month." + +Sample output shape: One row per non-usage, non-commitment transaction with `ChargePeriodStart`, `ChargeCategory`, `BilledCost`, `BillingCurrency`, `SubAccountName`, `x_InvoiceSectionName`, `PricingCategory`, `PricingQuantity`, `PricingUnit`, `ProviderName`, and `PublisherName`. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/KustoTools) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Cost allocation](../../framework/understand/allocation.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Python tools](python-tools.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md new file mode 100644 index 000000000..97a739e9e --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -0,0 +1,151 @@ +--- +title: Azure SRE Agent in the FinOps toolkit +description: Learn how the FinOps toolkit deploys Azure SRE Agent with FinOps and capacity management automation on top of FinOps hubs. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand what the FinOps toolkit's Azure SRE Agent deployment provides so that I can automate cost, capacity, and operations workflows. +--- + +# Azure SRE Agent in the FinOps toolkit + +The FinOps toolkit ships a Deploy to Azure template and a local Azure CLI + Bicep wrapper that deploy [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) and configure it for FinOps and capacity management workflows on top of [FinOps hubs](../hubs/finops-hubs-overview.md). The deployment includes specialist subagents, FOCUS-aligned Kusto and Python tools, scheduled tasks, and grounded knowledge so the agent can investigate cost changes, monitor quota and capacity signals, prepare executive summaries, and deliver scheduled updates. The deployment focuses on three core design principles: + +- **Automate the rhythm**
_Run daily, weekly, monthly, and quarterly FinOps workflows without waiting for manual report requests._ +- **Ground every answer**
_Use FinOps hub data, FOCUS-aligned Kusto tools, and Azure platform context to keep recommendations tied to evidence._ +- **Act with experts**
_Route work to specialized FinOps, finance, capacity, database, and hubs agents instead of a single generic assistant._ + +The FinOps toolkit deployment helps teams move from dashboards and alerts to an operating model where the agent investigates cost changes, monitors quota and capacity signals, prepares executive summaries, and delivers scheduled updates through Azure SRE Agent. + + +> [!NOTE] +> Estimated cost: Varies by Azure SRE Agent preview pricing, telemetry ingestion, and your existing FinOps hub footprint. +> +> The template provisions an Azure SRE Agent with a system-assigned managed identity, Log Analytics workspace, and Application Insights resource. Costs depend on the selected region, Azure SRE Agent pricing, Log Analytics and Application Insights ingestion and retention, and the Azure Data Explorer footprint you connect to. The managed identity and RBAC assignments don't typically add direct cost. + + + +> [!IMPORTANT] +> The FinOps toolkit deploys all SRE Agent resources even when the connected Azure Data Explorer cluster uses private endpoints. If the cluster has `publicNetworkAccess` set to `Disabled`, hosted Azure SRE Agent can't run direct KQL queries against the cluster. The deployment warns and links to the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations) so the customer can decide whether to enable public query access. + + +
+ + +> [!div class="nextstepaction"] +> [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) + + +
+ +## What you get + +The FinOps toolkit's Azure SRE Agent template deploys and configures these resources and Azure SRE Agent objects: + +| Component | Count | Description | +|-----------|-------|-------------| +| Azure SRE Agent | 1 | `Microsoft.App/agents` resource in autonomous mode | +| Model provider | 1 | Azure OpenAI provider-level routing (`MicrosoftFoundry` ARM value, `Automatic` model routing) | +| Managed identities | 1-2 | System-assigned managed identity for the agent; portal deployments also create a user-assigned identity for the deployment script | +| Log Analytics | 1 | Workspace for agent telemetry | +| Application Insights | 1 | Linked to Log Analytics for monitoring | +| Target resource group RBAC | 3-4 per target group | Reader, Monitoring Reader, Log Analytics Reader, and Contributor when `accessLevel` is `High` | +| Azure Data Explorer role | Optional | `AllDatabasesViewer` when Azure Data Explorer parameters are provided | +| Custom agents | 5 | `azure-capacity-manager`, `chief-financial-officer`, `finops-practitioner`, `ftk-database-query`, and `ftk-hubs-agent` | +| Skills | 3 | `azure-capacity-management`, `azure-cost-management`, and `finops-toolkit` | +| Tools | 50 | Kusto, capacity, and Hub infrastructure tools | +| Tool overrides | 9 | Enables SRE Agent Log Query and Visualization tools | +| Scheduled tasks | 19 | Daily, weekly, monthly, semiannual, and quarterly recurring workflows | +| Connectors | 1 | Optional Kusto connector to your FinOps hub Azure Data Explorer cluster | +| Knowledge docs | 6 | Five recipe knowledge docs plus the FinOps Toolkit output style | +| Notification connectors | 0 by default | Outlook and Teams can be added after deployment in the Azure SRE Agent portal | + +
+ +## Architecture overview + +The FinOps toolkit deployment is copied from the Microsoft SRE Agent starter-lab pattern and updated to use the toolkit's packaged Deploy to Azure flow or Azure CLI + Bicep directly. It doesn't use `azd`. The deployment runs in this order: + +1. The Azure portal or `bin/deploy.sh` starts a subscription-scoped ARM deployment. +2. The deployment creates the agent resource group when needed. +3. Bicep creates monitoring resources and Azure SRE Agent. +4. Bicep assigns target resource group RBAC and can optionally assign `AllDatabasesViewer` on your FinOps hub Azure Data Explorer cluster. +5. A deployment script in the portal path, or `bin/apply-extras.sh` in the local CLI path, creates the Kusto connector and applies skills, custom agents, tools, knowledge, and scheduled tasks through the supported SRE Agent ARM and data-plane surfaces. +6. You optionally add Outlook and Teams connectors in [sre.azure.com](https://sre.azure.com) when you want scheduled reports delivered outside the agent chat. + +The result is a single Azure SRE Agent with a FinOps Framework-aligned operating model layered on top. The `finops-practitioner` agent owns the FinOps operating rhythm and scheduled analysis, has no direct tools, and delegates evidence collection to specialists. The `ftk-database-query` agent owns all Kusto and FOCUS evidence collection. The `azure-capacity-manager` agent maps Azure capacity signals into Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization support, Governance, Policy & Risk, and Automation, Tools & Services. The `chief-financial-officer` agent provides finance and leadership consultation, and the `ftk-hubs-agent` monitors FinOps hub health and data freshness. + +The template defaults the parent SRE Agent to Azure OpenAI provider-level routing (`MicrosoftFoundry` in ARM) with automatic model selection inside that provider. Individual custom agents don't pin model names; they inherit the parent agent provider and use SRE Agent's automatic model routing. + +
+ +## When to use the agent + +FinOps teams often have the data they need but not the time to run every investigation on schedule. The agent gives the team an automated operating rhythm that can review cost changes, check commitment coverage, monitor capacity headroom, and summarize action items before the next stakeholder meeting. + +Use the agent when you want to: + +- Review FinOps hub data through conversational and scheduled agent workflows. +- Monitor cost anomalies, budget variance, and forecast drift. +- Track quota usage, capacity reservation utilization, region access, and zone readiness. +- Prepare daily, weekly, monthly, and quarterly cost and capacity summaries. +- Route questions to specialized agents with FinOps, finance, capacity, database, and hubs context. + +
+ +## Get started + +Deploy the agent when you have a FinOps hub with an Azure Data Explorer cluster and an Azure subscription where you can deploy Azure SRE Agent resources. After deployment, open the agent in [sre.azure.com](https://sre.azure.com), verify the subagents, skills, tools, and scheduled tasks, and add notification connectors if you want reports sent to Teams or Outlook. + + +> [!div class="nextstepaction"] +> [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) + + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Architecting for cloud](../../framework/optimize/architecting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md new file mode 100644 index 000000000..7def2af39 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -0,0 +1,514 @@ +--- +title: Python tools +description: Review the Python tools the FinOps toolkit ships for Azure SRE Agent for Azure quota, capacity, budgets, anomaly alerts, Resource Graph, FinOps hub health, and Advisor suppressions. +author: msbrett +ms.author: brettwil +ms.date: 05/25/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand which Python tools the FinOps toolkit ships for Azure SRE Agent so that I can use the right Azure API-backed tool for capacity, cost governance, and operations work. +--- + +# Python tools + +The FinOps toolkit deployment configures Azure SRE Agent with 13 Python tools that call Azure APIs through the agent's managed identity. These tools complement the Kusto tools by checking Azure platform state, deploying Cost Management controls, and automating governance tasks that aren't stored in FinOps hub data. + +Use Python tools when the agent needs live Azure Resource Manager, Resource Graph, Cost Management, Azure Data Explorer, or Advisor data instead of historical cost and usage data from the FinOps hub. + +> [!NOTE] +> The agent managed identity must have enough permission at the target scope to read or update the resources each tool touches. Read tools typically need Reader permissions. Deployment and suppression tools need permissions to create or update the target Cost Management or Advisor resources. + +## Source inventory + +The following table maps the 13 Python tools documented on this page to their source YAML files. Use this inventory to audit this reference page against the template source. It doesn't assert that no other YAML files exist under `src/templates/sre-agent/recipes/finops-hub/config/tools/`. + +| Tool | Source file | +|------|-------------| +| `vm-quota-usage` | `src/templates/sre-agent/recipes/finops-hub/config/tools/vm-quota-usage.yaml` | +| `capacity-reservation-groups` | `src/templates/sre-agent/recipes/finops-hub/config/tools/capacity-reservation-groups.yaml` | +| `sku-availability` | `src/templates/sre-agent/recipes/finops-hub/config/tools/sku-availability.yaml` | +| `non-compute-quotas` | `src/templates/sre-agent/recipes/finops-hub/config/tools/non-compute-quotas.yaml` | +| `deploy-budget` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-budget.yaml` | +| `deploy-bulk-budgets` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-budgets.yaml` | +| `deploy-anomaly-alert` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-anomaly-alert.yaml` | +| `deploy-bulk-anomaly-alerts` | `src/templates/sre-agent/recipes/finops-hub/config/tools/deploy-bulk-anomaly-alerts.yaml` | +| `resource-graph-query` | `src/templates/sre-agent/recipes/finops-hub/config/tools/resource-graph-query.yaml` | +| `benefit-recommendations` | `src/templates/sre-agent/recipes/finops-hub/config/tools/benefit-recommendations.yaml` | +| `data-freshness-check` | `src/templates/sre-agent/recipes/finops-hub/config/tools/data-freshness-check.yaml` | +| `db-service-quotas` | `src/templates/sre-agent/recipes/finops-hub/config/tools/db-service-quotas.yaml` | +| `suppress-advisor-recommendations` | `src/templates/sre-agent/recipes/finops-hub/config/tools/suppress-advisor-recommendations.yaml` | + +
+ +## Capacity and quota + +Use capacity and quota tools to check VM family quota, capacity reservation group utilization, SKU restrictions, and non-compute service limits before deployment or during recurring capacity reviews. + +### `vm-quota-usage` + +- **Azure API:** Azure Resource Manager Compute usages API: `Microsoft.Compute/locations/usages`. +- **When to use it:** Use this tool to query VM family quota usage across one or more regions in a subscription. It calculates utilization percentages and flags VM families above warning or critical thresholds. +- **Example prompt:** "Check VM quota usage for subscription `` in eastus and westus2, and call out any families above 80% utilization." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "locations": ["eastus", "westus2"], + "quotas": [ + { + "location": "eastus", + "name": "Standard DSv5 Family vCPUs", + "current": 80, + "limit": 100, + "utilization_pct": 80, + "at_risk_80": false, + "at_risk_95": false + } + ], + "warning_count": 0, + "critical_count": 0, + "suppressed_error_count": 0, + "suppressed_errors": [], + "errors": [] + } + ``` + +### `capacity-reservation-groups` + +- **Azure API:** Azure Resource Manager Compute capacity reservation group API: `Microsoft.Compute/capacityReservationGroups`, including capacity reservation instance view and associated virtual machines. +- **When to use it:** Use this tool to list capacity reservation groups in a subscription and compare reserved capacity with allocated virtual machines. It helps find unused capacity, overallocated groups, and zone-specific capacity reservation waste. +- **Example prompt:** "List capacity reservation groups in subscription `` and identify groups with unused reserved capacity." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "capacity_reservation_groups": [ + { + "name": "crg-prod-eastus", + "id": "/subscriptions//resourceGroups//providers/Microsoft.Compute/capacityReservationGroups/crg-prod-eastus", + "resource_group": "", + "location": "eastus", + "zones": ["1"], + "zone": "1", + "reserved_count": 10, + "allocated_count": 8, + "utilization_pct": 80, + "waste": true, + "waste_count": 2, + "overallocated": false, + "capacity_reservations": ["crg-prod-eastus/Standard_D8s_v5"], + "virtual_machines_allocated": ["/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/vm01"], + "virtual_machines_associated": [] + } + ], + "errors": [] + } + ``` + +### `sku-availability` + +- **Azure API:** Azure Resource Manager SKU APIs for Azure Compute and Azure Data Explorer: `Microsoft.Compute/skus` and `Microsoft.Kusto/locations/skus`. +- **When to use it:** Use this tool to verify whether a VM or Azure Data Explorer SKU is available in a region and whether zone or subscription restrictions could block deployment. +- **Example prompt:** "Check whether Standard_D8s_v5 is available in eastus2, including zone support and any restriction reasons." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "location": "eastus2", + "sku_filter": "Standard_D8s_v5", + "resource_provider": "compute", + "service": "Azure Compute", + "source_endpoint": "https://management.azure.com/subscriptions//providers/Microsoft.Compute/skus?api-version=2021-07-01&$filter=location eq 'eastus2'", + "skus": [ + { + "name": "Standard_D8s_v5", + "family": "standardDSv5Family", + "size": "D8s_v5", + "zones_available": ["1", "2", "3"], + "restrictions": [] + } + ], + "restriction_summary": { + "total_skus": 1, + "restricted_skus": 0, + "restriction_count": 0, + "reason_codes": {} + } + } + ``` + +### `non-compute-quotas` + +- **Azure API:** Azure Resource Manager provider usage APIs for supported services, with Azure Resource Graph fallbacks for services that don't expose a direct usage API. +- **When to use it:** Use this tool to review storage, networking, and PaaS quota usage that can block growth even when compute quota is healthy. It marks whether each limit came from an API-reported quota or an estimated fallback. +- **Example prompt:** "Audit non-compute quota usage for subscription `` in eastus and summarize storage or network limits above 80% utilization." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "services": [ + { + "service_name": "Storage", + "resource_type": "Microsoft.Storage/locations/usages", + "quota_name": "StorageAccounts", + "current_count": 100, + "limit": 250, + "utilization_pct": 40, + "at_risk": false, + "count_source": "arm_provider_usages_api", + "limit_source": "api_reported_limit", + "limit_type": "api_reported", + "source_endpoint": "https://management.azure.com/subscriptions//providers/Microsoft.Storage/locations/eastus/usages?api-version=2023-05-01", + "location": "eastus", + "scope": "regional" + } + ], + "quotas": [ + { + "subscription_id": "", + "service_name": "Storage", + "service": "Storage", + "resource_type": "Microsoft.Storage/locations/usages", + "quota_name": "StorageAccounts", + "name": "StorageAccounts", + "location": "eastus", + "scope": "regional", + "current_count": 100, + "current": 100, + "limit": 250, + "utilization_pct": 40, + "at_risk": false, + "at_risk_80": false, + "at_risk_95": false, + "count_source": "arm_provider_usages_api", + "limit_source": "api_reported_limit", + "limit_type": "api_reported", + "source_endpoint": "https://management.azure.com/subscriptions//providers/Microsoft.Storage/locations/eastus/usages?api-version=2023-05-01" + } + ], + "at_risk_count": 0, + "api_reported_limit_count": 1, + "estimated_limit_count": 0, + "suppressed_count": 0, + "errors": [] + } + ``` + +
+ +## Budget and alert deployment + +Use budget and alert deployment tools to create Cost Management controls for a single subscription or apply the same control across enabled subscriptions in a management group. + +### `deploy-budget` + +- **Azure API:** Azure Resource Manager Consumption budgets API: `Microsoft.Consumption/budgets`. +- **When to use it:** Use this tool to create or update a subscription-level Cost Management budget with notification thresholds and contact emails. +- **Example prompt:** "Create a monthly budget named SubscriptionBudget for subscription `` with an amount of 50000 and notify finops@example.com." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "budget_name": "SubscriptionBudget", + "amount": 50000, + "time_grain": "Monthly", + "contact_emails": ["finops@example.com"], + "status_code": 201, + "budget": { + "id": "/subscriptions//providers/Microsoft.Consumption/budgets/SubscriptionBudget", + "name": "SubscriptionBudget", + "type": "Microsoft.Consumption/budgets" + }, + "status": "created" + } + ``` + +### `deploy-bulk-budgets` + +- **Azure API:** Azure Resource Graph to discover enabled subscriptions, then Azure Resource Manager Consumption budgets API: `Microsoft.Consumption/budgets`. +- **When to use it:** Use this tool to deploy the same Cost Management budget across all enabled subscriptions under a management group. +- **Example prompt:** "Deploy a monthly 50000 budget named SubscriptionBudget to every enabled subscription in management group `` and notify finops@example.com." +- **Sample output shape:** + + ```json + { + "management_group": "", + "budget_name": "SubscriptionBudget", + "amount": 50000, + "contact_emails": ["finops@example.com"], + "subscription_count": 2, + "created_or_updated": 2, + "failed": 0, + "deployments": [ + { + "subscription_id": "", + "subscription_name": "Production", + "budget_name": "SubscriptionBudget", + "status": "created", + "status_code": 201, + "error": null + } + ] + } + ``` + +### `deploy-anomaly-alert` + +- **Azure API:** Azure Resource Manager Cost Management scheduled actions API: `Microsoft.CostManagement/scheduledActions`. +- **When to use it:** Use this tool to create or update a daily Cost Management anomaly alert scheduled action for one subscription. +- **Example prompt:** "Create a cost anomaly alert for subscription `` that sends daily anomaly notifications to finops@example.com." +- **Sample output shape:** + + ```json + { + "subscription_id": "", + "scheduled_action_name": "cost-anomaly-alert", + "email_recipients": ["finops@example.com"], + "status_code": 201, + "anomaly_alert": { + "id": "/subscriptions//providers/Microsoft.CostManagement/scheduledActions/cost-anomaly-alert", + "name": "cost-anomaly-alert", + "kind": "InsightAlert" + }, + "status": "created" + } + ``` + +### `deploy-bulk-anomaly-alerts` + +- **Azure API:** Azure Resource Graph to discover enabled subscriptions, then Azure Resource Manager Cost Management scheduled actions API: `Microsoft.CostManagement/scheduledActions`. +- **When to use it:** Use this tool to deploy the same cost anomaly alert configuration across enabled subscriptions under a management group. +- **Example prompt:** "Deploy cost anomaly alerts to all enabled subscriptions in management group `` and send notifications to finops@example.com." +- **Sample output shape:** + + ```json + { + "management_group": "", + "email_recipients": ["finops@example.com"], + "subscription_count": 2, + "created_or_updated": 2, + "failed": 0, + "deployments": [ + { + "subscription_id": "", + "subscription_name": "Production", + "scheduled_action_name": "cost-anomaly-alert", + "status": "updated", + "status_code": 200, + "error": null + } + ] + } + ``` + +
+ +## Resource analysis + +Use resource analysis tools when the agent needs live Azure inventory, configuration, or commitment discount recommendation data outside the FinOps hub. + +### `resource-graph-query` + +- **Azure API:** Azure Resource Graph resources API: `Microsoft.ResourceGraph/resources`. +- **When to use it:** Use this tool to run Azure Resource Graph KQL across one or more subscriptions for inventory, configuration drift, governance checks, and subscription-scale troubleshooting. +- **Example prompt:** "Run a Resource Graph query across my subscriptions to list unattached managed disks by subscription, resource group, size, and age." +- **Sample output shape:** + + ```json + { + "rows": [ + { + "subscriptionId": "", + "resourceGroup": "", + "name": "disk01", + "type": "microsoft.compute/disks" + } + ], + "count": 1, + "errors": [], + "total_records": 1, + "result_truncated": false, + "subscriptions": [""] + } + ``` + +### `benefit-recommendations` + +- **Azure API:** Azure Resource Manager Cost Management benefit recommendations API: `Microsoft.CostManagement/benefitRecommendations`. +- **When to use it:** Use this tool to retrieve reservation and savings plan recommendations at a billing scope, including recommendation type, term, savings, cost, and break-even details. +- **Example prompt:** "Get three-year benefit recommendations for billing account scope `` using a Last30Days lookback and summarize the largest savings opportunities." +- **Sample output shape:** + + ```json + { + "billing_scope": "", + "lookback_period": "Last30Days", + "term": "P3Y", + "recommendations": [ + { + "type": "SP", + "savings": 12000, + "cost": 30000, + "total_cost": 30000, + "cost_without_benefit": 42000, + "term": "P3Y", + "break_even": "P8M", + "id": "/providers/Microsoft.Billing/billingAccounts//providers/Microsoft.CostManagement/benefitRecommendations/", + "name": "" + } + ], + "count": 1 + } + ``` + +
+ +## Hub management + +Use hub management tools to verify whether FinOps hub data is current enough for reliable scheduled reports and agent answers. Use `data-freshness-check` as the source of truth for hub freshness before relying on stale memory, raw KQL rollups, or ingestion timestamp checks. + +### `data-freshness-check` + +- **Azure API:** Azure Data Explorer REST query API (`/v1/rest/query` or `/v2/rest/query`) on the configured FinOps hub cluster. +- **When to use it:** Use this tool to check data freshness for FinOps hub functions such as `Costs()`, `Prices()`, `Recommendations()`, and `Transactions()`. It reports latest data dates, stale functions, and functions without data. Treat `Costs()` as the authoritative freshness signal. If `Costs()` is 3 days old or newer, don't report the hub as stale even if older memory, raw KQL, or ingestion timestamp checks disagree. +- **Example prompt:** "Check data freshness for the FinOps hub at `` in the hub database and tell me which functions are stale." +- **Sample output shape:** + + ```json + { + "cluster_uri": "https://.kusto.windows.net", + "database": "hub", + "functions": [ + { + "function_name": "Costs()", + "source_dataset": "Costs", + "expected_export_dataset": "focuscost", + "row_count": 100000, + "latest_data_date": "2026-05-01T00:00:00Z", + "latest_ingestion_time": null, + "staleness_days": 1, + "is_stale": false, + "has_data": true, + "schema_status": "ok", + "schema_column_count": 120, + "required_for_hub_health": true, + "diagnostic_code": "OK", + "diagnostic_message": null + } + ], + "total_functions": 4, + "stale_count": 0, + "empty_count": 0, + "error_count": 0, + "hub_data_stale": false, + "attention_required": false, + "status": "healthy", + "diagnostics": [], + "freshest_function": {}, + "stalest_function": {}, + "authoritative_freshness_signal": { + "function_name": "Costs()", + "latest_data_date": "2026-05-01T00:00:00Z", + "staleness_days": 1, + "is_stale": false, + "has_data": true, + "row_count": 100000 + }, + "source_of_truth": { + "tool": "data-freshness-check", + "method": "direct_adx_rest_query", + "endpoint": "/v2/rest/query", + "authoritative_function": "Costs()", + "freshness_threshold_days": 3, + "supersedes": ["stale memory conclusions", "raw KQL freshness rollups", "Kusto ingestion timestamp checks"] + } + } + ``` + +
+ +## Advisor + +Use Advisor tools when the agent needs to apply governance decisions to Azure Advisor recommendations. + +### `suppress-advisor-recommendations` + +- **Azure API:** Azure Resource Graph to find Advisor recommendations, then Azure Resource Manager Advisor suppressions API: `Microsoft.Advisor/recommendations/suppressions`. +- **When to use it:** Use this tool to suppress selected Azure Advisor recommendation types across subscriptions under a management group for a limited time to live. +- **Example prompt:** "Suppress the default Advisor recommendation types for management group `` for 30 days and report how many recommendations were suppressed." +- **Sample output shape:** + + ```json + { + "management_group_id": "", + "days": 30, + "ttl": "P30D", + "recommendation_type_ids": ["89515250-1243-43d1-b4e7-f9437cedffd8"], + "found_count": 10, + "suppressed_count": 10, + "failed_count": 0, + "suppressions": [ + { + "subscription_id": "", + "recommendation_id": "/subscriptions//providers/Microsoft.Advisor/recommendations/", + "recommendation_type_id": "89515250-1243-43d1-b4e7-f9437cedffd8", + "suppression_id": "", + "ttl": "P30D", + "status": "suppressed", + "status_code": 201, + "error": null + } + ] + } + ``` + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/PythonTools) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Budgeting](../../framework/quantify/budgeting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Resource Graph](/azure/governance/resource-graph/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) +- [Azure Advisor](/azure/advisor/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Tools shipped for Azure SRE Agent in the FinOps toolkit](tools.md) +- [Kusto tools](kusto-tools.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md new file mode 100644 index 000000000..7862eaa6c --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -0,0 +1,277 @@ +--- +title: Scheduled tasks (Azure SRE Agent in the FinOps toolkit) +description: Learn how the FinOps toolkit's scheduled tasks automate daily, weekly, monthly, and quarterly FinOps operating rhythms on Azure SRE Agent. +author: msbrett +ms.author: brettwil +ms.date: 05/25/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand the scheduled tasks the FinOps toolkit deploys to Azure SRE Agent so that I can plan recurring cost, capacity, and finance reviews. +--- + +# Scheduled tasks (Azure SRE Agent in the FinOps toolkit) + +The FinOps toolkit ships scheduled tasks that run recurring FinOps operating-rhythm workflows on Azure SRE Agent. They turn common reviews into autonomous checks that gather data, route work to the right specialist agent, generate charts where the data supports them, and post completed reports to Microsoft Teams when a Teams notification connector is configured. + +The template deploys 19 scheduled tasks from `src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/`. These tasks cover daily health checks, weekly optimization and capacity reviews, monthly planning and finance reports, semiannual year-over-year analysis, and quarterly strategy. + +
+ +## Daily tasks + +Daily tasks run every morning to validate FinOps hub health and monitor Azure capacity signals that feed Planning & Estimating, Architecting & Workload Placement, Usage Optimization, Governance, Policy & Risk, and Automation, Tools & Services. They keep cost and capacity surprises visible before each business day. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `HubsHealthCheck` | `ftk-hubs-agent` | Daily at 6:00 AM
`0 6 * * *` | FinOps hub version and data freshness validation | +| `CapacityDailyMonitor` | `azure-capacity-manager` | Daily at 6:30 AM
`30 6 * * *` | Daily capacity health check — quota usage, CRG utilization, zone capacity | + +
+ +## Weekly tasks + +Weekly tasks summarize cost optimization, Azure capacity evidence, and benefit recommendation activity for the previous week. They give the team a recurring rhythm for deeper analysis without manual report requests. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `ComputeUtilizationTrend` | `azure-capacity-manager` | Weekly on Monday at 7:00 AM
`0 7 * * 1` | Weekly VM quota utilization trend review across subscriptions and regions | +| `CostOptimization` | `finops-practitioner` | Weekly on Monday at 8:00 AM
`0 8 * * 1` | Comprehensive cost optimization report with orphaned resources, rightsizing, and commitment analysis | +| `CapacityWeeklySupplyReview` | `azure-capacity-manager` | Weekly on Monday at 8:00 AM
`0 8 * * 1` | Weekly capacity evidence review — quota headroom, CRG cost optimization, SKU availability, benefit recommendations | +| `NonComputeQuotaAudit` | `azure-capacity-manager` | Weekly on Tuesday at 7:00 AM
`0 7 * * 2` | Weekly audit of storage, network, and non-compute quota usage at risk | +| `DbQuotaAudit` | `azure-capacity-manager` | Weekly on Wednesday at 7:00 AM
`0 7 * * 3` | Weekly audit of database quota and region or zone access risks | +| `SkuAvailabilityAudit` | `azure-capacity-manager` | Weekly on Wednesday at 7:30 AM
`30 7 * * 3` | Weekly audit of regional SKU availability and restrictions that could block deployments | +| `MonitoringScopeValidation` | `ftk-hubs-agent` | Weekly on Thursday at 9:00 AM
`0 9 * * 4` | Weekly validation that FinOps hub monitoring covers all active subscriptions | +| `BenefitRecommendationReview` | `finops-practitioner` | Weekly on Friday at 8:00 AM
`0 8 * * 5` | Weekly review of reservation and savings plan recommendations, with CFO consultation for decision framing | + +
+ +## Monthly tasks + +Monthly tasks run after billing data finalizes to produce year-to-date analysis, capacity planning forecasts, AI workload cost reviews, and audit reports for budget and alert coverage. Use them to anchor monthly business reviews. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `StoragePaasGrowthForecast` | `azure-capacity-manager` | Monthly on the 1st at 8:00 AM
`0 8 1 * *` | Monthly storage and PaaS quota growth forecast across active subscriptions | +| `AdvisorSuppressionReview` | `finops-practitioner` | Monthly on the 1st at 9:00 AM
`0 9 1 * *` | Monthly review of active Advisor recommendation suppressions for stale or expired decisions | +| `CapacityMonthlyPlanning` | `azure-capacity-manager` | Monthly on the 1st at 9:00 AM
`0 9 1 * *` | Monthly capacity planning cycle — demand forecast, capacity request pipeline, governance review | +| `Monthly` | `finops-practitioner` | Monthly on the 5th at 5:15 PM
`15 17 5 * *` | Autonomous month-over-month cost analysis with FinOps hub tools | +| `AIWorkloadCostAnalysis` | `finops-practitioner` | Monthly on the 1st at 10:00 AM
`0 10 1 * *` | Monthly AI workload cost analysis — token economics, model efficiency, and cost allocation for Azure OpenAI | +| `Semiannual` | `finops-practitioner` | January 5 and July 5 at 9:00 AM
`0 9 5 1,7 *` | Semiannual year-over-year finance analysis with forecast and CFO consultation | +| `BudgetCoverageAudit` | `finops-practitioner` | Monthly on the 15th at 8:00 AM
`0 8 15 * *` | Monthly audit of subscription budget coverage and missing budget controls | +| `AlertCoverageAudit` | `finops-practitioner` | Monthly on the 16th at 8:00 AM
`0 8 16 * *` | Monthly audit of cost anomaly alert coverage across active subscriptions | + +
+ +## Quarterly tasks + +Quarterly tasks run at the start of each calendar quarter to summarize capacity-related FinOps capability maturity, commitment alignment, and architecture evolution. Use them to feed leadership reviews and the next quarter's planning cycle. + +| Task | Agent | Schedule | Description | +|------|-------|----------|-------------| +| `CapacityQuarterlyStrategy` | `azure-capacity-manager` | Quarterly on January 1, April 1, July 1, and October 1 at 9:00 AM
`0 9 1 1,4,7,10 *` | Quarterly capacity strategy review — FinOps capability maturity, commitment alignment, architecture evolution | + +
+ +## Task details + +Each scheduled task is defined in YAML under `src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/`. You can customize the schedule by changing the `cron_expression` in the task definition before deployment. You can also tune the task prompt to change thresholds, scope, report sections, and recommended actions for your operating model. + +### HubsHealthCheck + +- **Data sources queried:** GitHub release metadata for the latest FinOps hub version, Azure resource discovery for deployed hub resources, and the `data-freshness-check` tool for the latest `Costs()` update date. The task also validates hub connectivity before trusting downstream scheduled reports. +- **Output format and content:** A daily health summary that reports deployed version status, latest available version, data refresh status, connectivity findings, and any blocking hub issues. The report is formatted for Teams when notifications are configured. +- **Recommended actions generated:** Upgrade FinOps hubs when the deployed version is behind, investigate stale exports or ingestion failures, restore connectivity, and delay cost analysis that depends on stale hub data. +- **Customization options:** Change the daily cron from `0 6 * * *`, adjust how many days of data freshness lag is acceptable, add organization-specific hub resource filters, and add required escalation steps for stale data or version drift. + +### CapacityDailyMonitor + +- **Data sources queried:** VM quota usage through `vm-quota-usage`, capacity reservation group data through `capacity-reservation-groups`, non-compute quota context through `non-compute-quotas`, Azure CLI discovery for AKS and regional resources, and hub freshness checks where cost context is needed. +- **Output format and content:** A daily capacity health report with quota pressure, capacity reservation utilization, AKS node pool readiness, alert status, and urgent capacity blockers mapped to FinOps capability impact. +- **Recommended actions generated:** File quota increases, redistribute workload demand, adjust capacity reservation groups, investigate underutilized reservations, validate AKS node pool capacity, and escalate imminent deployment blockers. +- **Customization options:** Change the daily cron from `30 6 * * *`, tune warning and critical quota-utilization thresholds, define target capacity reservation utilization bands, scope monitored subscriptions or regions, and add workload-specific AKS node pool checks. + +### Monthly + +- **Data sources queried:** `finops-practitioner` delegates FinOps hub Kusto evidence to `ftk-database-query`, including `data-freshness-check`, `monthly-cost-trend`, `monthly-cost-change-percentage`, `top-services-by-cost`, `top-resource-groups-by-cost`, `cost-by-region-trend`, `cost-anomaly-detection`, `savings-summary-report`, `commitment-discount-utilization`, `cost-forecasting-model`, `reservation-recommendation-breakdown`, `top-resource-types-by-cost`, `service-price-benchmarking`, and `top-other-transactions`. Capacity-risk evidence is delegated to `azure-capacity-manager`. +- **Output format and content:** A daily month-over-month cost analysis with executive summary, service and resource group drivers, anomalies, forecasts, savings and commitment signals, regional distribution, tag coverage, marketplace or other purchases, charts where data supports them, and action items. +- **Recommended actions generated:** Investigate anomalies, correct cost allocation gaps, prioritize cost drivers, act on savings opportunities, review commitment utilization, address forecast risk, and validate tags or financial hierarchy gaps. +- **Customization options:** Change the monthly cron from `15 17 5 * *`, adjust anomaly and variance thresholds, change the comparison window, scope the analysis to selected subscriptions or billing entities, and add or remove Kusto sections from the report. + +### ComputeUtilizationTrend + +- **Data sources queried:** VM quota utilization through `vm-quota-usage`, Azure Resource Graph subscription and VM inventory, and prior-period utilization signals from the scheduled analysis prompt. +- **Output format and content:** A weekly trend report that lists quota families, subscriptions, regions, current utilization, week-over-week movement, and quota lines approaching defined risk thresholds. +- **Recommended actions generated:** Request quota increases for growing usage, move demand to lower-pressure regions or quota families, validate planned deployments against headroom, and close stale quota allocations that are no longer needed. +- **Customization options:** Change the weekly cron from `0 7 * * 1`, tune warning and critical utilization thresholds, choose the trend lookback window, filter to production subscriptions or priority regions, and add business-unit routing for quota owners. + +### CostOptimization + +- **Data sources queried:** Azure Resource Graph for orphaned and idle resources, Advisor cost recommendations, commitment and benefit recommendation tools, Azure CLI resource validation, optional VM utilization data, and FinOps hub data when available. +- **Output format and content:** A weekly cost optimization report with executive summary, quick wins, orphaned resources, rightsizing candidates, commitment discount status, effort and risk categories, estimated savings, and charts for major opportunities. +- **Recommended actions generated:** Delete or remediate orphaned resources, resize underutilized workloads, buy or adjust reservations and savings plans, validate Advisor recommendations, and assign owners for high-value optimization actions. +- **Customization options:** Change the weekly cron from `0 8 * * 1`, tune savings and utilization thresholds, exclude protected resource groups or tags, change effort and risk categories, and modify recommendation ranking or minimum savings filters. + +### CapacityWeeklySupplyReview + +- **Data sources queried:** VM quota usage, `capacity-reservation-groups`, `non-compute-quotas`, `sku-availability`, benefit and reservation recommendations, Azure CLI regional discovery, and commitment-related cost signals. +- **Output format and content:** A weekly capacity evidence review covering quota headroom, capacity reservation waste, SKU and zone availability, region access, non-compute constraints, and capacity-to-rate optimization opportunities mapped to FinOps capabilities. +- **Recommended actions generated:** Increase quota, rebalance capacity reservations, release or resize underused CRGs, validate alternate SKUs or regions, align capacity reservations with reservation or savings opportunities, and escalate SKU restrictions. +- **Customization options:** Change the weekly cron from `0 8 * * 1`, tune quota and CRG utilization thresholds, set approved regions and SKU allowlists, scope the review to critical workloads, and adjust how benefit recommendations are ranked. + +### NonComputeQuotaAudit + +- **Data sources queried:** `non-compute-quotas` for storage, network, and other service quota usage; subscription scope from Azure discovery; and service-specific quota values returned by Azure APIs when available. +- **Output format and content:** A weekly audit that separates reported and estimated limits, lists services and regions near limits, highlights quotas with missing limit telemetry, and summarizes risk by subscription. +- **Recommended actions generated:** Request quota increases, reduce or redistribute usage, add missing quota monitoring, validate estimated limits with service owners, and escalate high-risk storage or network quotas before deployments fail. +- **Customization options:** Change the weekly cron from `0 7 * * 2`, tune at-risk utilization thresholds, choose monitored services, scope subscriptions or regions, and define how to handle quotas that report current usage but not limits. + +### DbQuotaAudit + +- **Data sources queried:** `db-service-quotas` for SQL DB, SQL Managed Instance, Cosmos DB, PostgreSQL Flexible Server, and MySQL Flexible Server quota, region, and availability-zone access signals. +- **Output format and content:** A weekly database quota report that separates service limits, regional access, zone access, estimated or missing evidence, and workload impact by subscription and region. +- **Recommended actions generated:** Request database quota increases, validate region or zone access, adjust database placement plans, add owner routing for capacity risks, and escalate blockers before deployment or scale events. +- **Customization options:** Change the weekly cron from `0 7 * * 3`, choose database services or regions to inspect, tune risk thresholds, and define owner metadata requirements. + +### SkuAvailabilityAudit + +- **Data sources queried:** `sku-availability` for regional SKU availability and restrictions, Azure subscription and region discovery, and workload-provided SKU filters when present. +- **Output format and content:** A weekly availability report that lists requested SKUs by region, availability status, restrictions, deployment blockers, and recommended fallback regions or SKU families. +- **Recommended actions generated:** Change deployment region or SKU, request regional access where possible, update landing-zone allowed SKU lists, revise deployment plans, and escalate blockers that affect production capacity. +- **Customization options:** Change the weekly cron from `30 7 * * 3`, tune the SKU and region scope, add required workload SKUs, define preferred fallback regions, and change the severity threshold for restricted or unavailable SKUs. + +### MonitoringScopeValidation + +- **Data sources queried:** Azure Resource Graph for active subscription inventory, FinOps hub `data-freshness-check`, hub database and cluster configuration, and subscription coverage comparisons between Azure and hub data. +- **Output format and content:** A weekly monitoring coverage report showing active subscriptions, subscriptions with fresh hub data, subscriptions missing from monitoring, stale coverage, and evidence for scope gaps. +- **Recommended actions generated:** Add missing subscriptions to exports or hub monitoring, fix stale export configuration, validate hub permissions, update subscription onboarding processes, and pause unsupported financial analysis for missing scopes. +- **Customization options:** Change the weekly cron from `0 9 * * 4`, tune data freshness thresholds, filter excluded or retired subscriptions, change the required coverage percentage, and add owner routing for missing subscription remediation. + +### BenefitRecommendationReview + +- **Data sources queried:** `benefit-recommendations` for reservation and savings plan opportunities, billing-scope context, plus Kusto-backed commitment utilization and savings evidence delegated to `ftk-database-query`. +- **Output format and content:** A weekly executive report with total savings opportunity, recommendation categories, term and scope assumptions, purchase candidates, risk notes, and decision-ready next steps. +- **Recommended actions generated:** Approve high-confidence purchases, reject or defer recommendations that conflict with demand forecasts, adjust commitment coverage, request validation from workload owners, and document finance approval decisions. +- **Customization options:** Change the weekly cron from `0 8 * * 5`, tune minimum savings and confidence thresholds, set preferred commitment terms, scope recommendations by billing profile or subscription, and add finance approval rules. + +### StoragePaasGrowthForecast + +- **Data sources queried:** `non-compute-quotas` for current storage and PaaS quota usage, Azure Resource Graph for service inventory, subscription scope from Azure discovery, and historical growth signals derived from current usage where available. +- **Output format and content:** A monthly forecast that identifies storage and PaaS services approaching limits, current usage and limit signals, projected growth risk, and subscriptions needing quota planning. +- **Recommended actions generated:** Request quota increases, archive or clean up unused capacity, move demand to less constrained subscriptions or regions, add service-specific monitoring, and validate growth assumptions with workload owners. +- **Customization options:** Change the monthly cron from `0 8 1 * *`, tune forecast horizon and risk thresholds, select included PaaS services, define acceptable headroom, and add workload-specific growth assumptions. + +### AdvisorSuppressionReview + +- **Data sources queried:** Azure Resource Graph for Advisor suppression resources and metadata, subscription inventory, suppression age and expiration fields, and related recommendation context where available. +- **Output format and content:** A monthly suppression inventory with active, stale, expired, and undocumented suppressions; affected recommendations; age; owner information; and remediation status. +- **Recommended actions generated:** Remove expired suppressions, renew justified suppressions with documentation, restore important Advisor recommendations, assign owners for stale decisions, and create follow-up work for risky suppressed savings. +- **Customization options:** Change the monthly cron from `0 9 1 * *`, tune stale-age and expiration thresholds, scope suppression review by subscription or owner tag, add required justification fields, and define exception approval rules. + +### CapacityMonthlyPlanning + +- **Data sources queried:** `azure-capacity-manager` uses `vm-quota-usage`, `capacity-reservation-groups`, `resource-graph-query`, and benefit recommendations directly, then asks `ftk-database-query` for Kusto-backed forecast, commitment utilization, and savings evidence. +- **Output format and content:** A monthly capacity planning packet with demand forecast, capacity request pipeline, quota and CRG allocation review, cost impact, governance findings, and planning decisions. +- **Recommended actions generated:** Submit quota and capacity requests, adjust capacity reservations, align capacity requests with forecasted demand, rebalance allocation across subscriptions, and update governance controls for capacity planning. +- **Customization options:** Change the monthly cron from `0 9 1 * *`, tune forecast horizon and growth thresholds, choose capacity planning regions and SKUs, set acceptable CRG utilization bands, and add capacity request workflow fields. + +### Semiannual + +- **Data sources queried:** `finops-practitioner` delegates FinOps hub Kusto evidence to `ftk-database-query`, including `monthly-cost-trend`, `quarterly-cost-by-resource-group`, `cost-anomaly-detection`, `savings-summary-report`, `commitment-discount-utilization`, `cost-by-financial-hierarchy`, `cost-forecasting-model`, `reservation-recommendation-breakdown`, `cost-by-region-trend`, `top-resource-types-by-cost`, `service-price-benchmarking`, `monthly-cost-change-percentage`, `top-commitment-transactions`, and `top-other-transactions`. +- **Output format and content:** A semiannual year-over-year finance report with spend trend, forward forecast, quarterly trends, service portfolio analysis, anomaly narrative, savings realization, commitment performance, hierarchy views, and executive actions. +- **Recommended actions generated:** Reforecast budgets, address variance drivers, approve savings actions, adjust commitments, escalate financial hierarchy gaps, and document finance risks before fiscal reviews. +- **Customization options:** Change the semiannual cron from `0 9 5 1,7 *`, align fiscal calendar assumptions, tune variance and forecast thresholds, scope the report by billing or management group hierarchy, and add finance-specific KPI sections. + +### AIWorkloadCostAnalysis + +- **Data sources queried:** `finops-practitioner` delegates AI cost Kusto evidence to `ftk-database-query`, including `ai-token-usage-breakdown`, `ai-model-cost-comparison`, `ai-daily-trend`, and `ai-cost-by-application`, plus cost and capacity context from Azure discovery and `azure-capacity-manager` when needed. +- **Output format and content:** A monthly AI cost report covering token economics, model mix, application allocation, daily trends, input and output ratios, month-over-month AI cost movement, optimization opportunities, and charts. +- **Recommended actions generated:** Substitute models where quality allows, optimize prompts, rightsize environments, improve application cost allocation, assess commitment coverage, and prioritize workloads with high token cost growth. +- **Customization options:** Change the monthly cron from `0 10 1 * *`, tune token-cost and growth thresholds, choose model families or applications in scope, add quality or latency guardrails for model substitution, and change chargeback allocation rules. + +### BudgetCoverageAudit + +- **Data sources queried:** Azure Resource Graph for subscription inventory and budget resources, subscription metadata, and budget configuration details such as amount, period, contact, and scope. +- **Output format and content:** A monthly budget coverage report with active subscriptions, configured budgets, missing or incomplete budgets, coverage gaps, and budget-control remediation items. +- **Recommended actions generated:** Create missing budgets, update budget contacts and thresholds, align budget scopes to subscription ownership, retire budgets for inactive subscriptions, and escalate subscriptions without financial guardrails. +- **Customization options:** Change the monthly cron from `0 8 15 * *`, define required budget coverage thresholds, exclude sandbox or retired subscriptions, set minimum alert percentages, and add owner or cost-center routing. + +### AlertCoverageAudit + +- **Data sources queried:** Azure Resource Graph for active subscriptions and anomaly alert resources, cost alert configuration, and subscription metadata for ownership and scope validation. +- **Output format and content:** A monthly alert coverage report that lists subscriptions with and without cost anomaly alerts, stale or incomplete alert configuration, missing contacts, and remediation priority. +- **Recommended actions generated:** Create missing anomaly alerts, repair alert scopes or contacts, standardize alert thresholds, remove obsolete alerts, and assign owners for unmonitored high-spend subscriptions. +- **Customization options:** Change the monthly cron from `0 8 16 * *`, tune required alert coverage and severity thresholds, exclude low-risk subscriptions, set required notification contacts, and customize anomaly alert policy standards. + +### CapacityQuarterlyStrategy + +- **Data sources queried:** VM quota usage, reservation and savings recommendations, Kusto-backed commitment and savings evidence delegated to `ftk-database-query`, Azure Resource Graph, Azure CLI architecture signals, and non-compute quota context. +- **Output format and content:** A quarterly strategy report covering FinOps capability maturity, commitment alignment, architecture evolution, region and quota strategy, governance health, risk register, and executive recommendations. +- **Recommended actions generated:** Mature capacity governance, align reservations and savings plans with demand, update regional architecture, address non-compute quota constraints, revise capacity request processes, and set quarterly capacity objectives. +- **Customization options:** Change the quarterly cron from `0 9 1 1,4,7,10 *`, tune maturity scoring and risk thresholds, set strategic regions and SKU families, align with quarterly business review dates, and add organization-specific governance criteria. + +
+ +## Notification behavior + +Scheduled tasks deliver final reports through Azure SRE Agent notification connectors. When you configure the Microsoft Teams connector, each task posts only the completed summary to the connected Teams channel. The task prompts explicitly avoid posting intermediate findings so the channel stays focused on ready-to-use results. + +The prompts also split what goes to Teams and what goes to the agent knowledge base: + +- **Teams** receives financial, status, capacity, and strategy results. This includes charts, executive summaries, action items, savings opportunities, quota risks, and capacity recommendations. +- **Knowledge base** receives operational learnings only. Examples include tool errors, query patterns, API workarounds, pipeline failure modes, and troubleshooting steps that worked. +- **Financial detail stays out of memory.** Prompts tell the agents not to save customer financial data, cost amounts, savings numbers, token costs, or similar financial details to the knowledge base. + +For connector setup, see [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md#configure-notifications). + +
+ +## Roadmap + +The deployed template includes the 19 scheduled tasks listed on this page. The repository also includes the detailed current task catalog in [CATALOG.md](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/CATALOG.md). + +The catalog is a roadmap for future automation ideas. It includes more than 74 potential daily, weekly, monthly, quarterly, and annual tasks across FinOps, capacity management, FinOps for AI, governance, optimization, benchmarking, and executive reporting. Those catalog entries are planned ideas, not deployed scheduled tasks, unless they are listed in the deployed task catalog above. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/ScheduledTasks) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Anomaly management](../../framework/understand/anomalies.md) +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/security.md b/docs-mslearn/toolkit/sre-agent/security.md new file mode 100644 index 000000000..3aa3109bb --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/security.md @@ -0,0 +1,200 @@ +--- +title: Security and permissions for Azure SRE Agent in the FinOps toolkit +description: Review the permissions, identities, run modes, and data flows the FinOps toolkit configures on Azure SRE Agent before you deploy it in your environment. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: concept-article +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps hub admin, I want to understand the security and permissions the FinOps toolkit configures on Azure SRE Agent so that I can deploy it with least privilege. +--- + +# Security and permissions for Azure SRE Agent in the FinOps toolkit + +The FinOps toolkit deployment configures Azure SRE Agent with managed identity, Azure RBAC, Azure Data Explorer permissions, and optional Microsoft Teams or Outlook connectors to run FinOps and capacity workflows. Review these permissions before deployment so you can keep the agent scoped to the data and actions it needs. + +> [!IMPORTANT] +> The agent is designed for least privilege. The template grants read, monitoring, Kusto viewer, and zone mapping permissions. It doesn't grant broad write access to Azure resources. + +
+ +## Deployment permissions + +To deploy the template, the deploying user or service principal needs one of these permission sets on the target subscription: + +- **Owner** +- **User Access Administrator** and **Contributor** + +These permissions are needed because deployment creates a resource group, creates Azure resources, assigns Azure RBAC roles, and assigns the deploying principal the Azure SRE Agent Administrator role on the agent resource. + +> [!TIP] +> Use a dedicated deployment identity for production environments. After deployment, review role assignments and remove any temporary permissions the deployment identity no longer needs. + +
+ +## Managed identity permissions + +The template creates an Azure SRE Agent with a system-assigned managed identity. + +The system-assigned managed identity is the primary identity the template manages. The template uses it for Azure resource operations, action execution, the knowledge graph configuration, and connector setup. The deployment grants the system-assigned managed identity these permissions: + +| Role | Scope | What it grants | Why it's needed | +|------|-------|----------------|-----------------| +| Reader | Subscription | Read access to Azure resources and metadata | Lets the agent inspect resource configuration, cost scopes, quota context, and related Azure inventory | +| Reader | Target resource groups | Read access to scoped resource groups | Lets the agent inspect explicitly targeted resources | +| Monitoring Reader | Target resource groups | Read access to Azure Monitor settings and telemetry | Lets the agent use monitoring context for investigations and health checks | +| Log Analytics Reader | Target resource groups | Read access to Log Analytics resources | Lets the agent query scoped workspace telemetry when configured | +| Contributor | Target resource groups when `accessLevel` is `High` | Resource-group write access | Lets remediation tools create or update approved alerts and budgets in targeted scopes | +| AllDatabasesViewer | Azure Data Explorer cluster | Viewer access across databases in the cluster | Lets the Kusto connector query FinOps hub cost data | +| SRE Agent Administrator | Agent resource | Administer the Azure SRE Agent resource | Lets the deploying principal manage the agent after deployment | + +With this default scope, the managed identity can read Azure resource metadata, monitoring context, and FinOps hub data. It can write approved remediation resources only in explicitly targeted resource groups when `accessLevel` is `High`, and it can send messages or email only through connectors you configure. + +
+ +## Data Explorer permissions + +The agent reads FinOps hub data through an Azure Data Explorer connector. When you provide the optional cluster name and cluster resource group parameters, the deployment assigns `AllDatabasesViewer` on the target Azure Data Explorer cluster to the system-assigned managed identity. + +This permission lets the agent query hub data, including cost, usage, commitment, allocation, anomaly, and forecast datasets exposed through the FinOps toolkit Kusto tools. It doesn't grant database administration permissions. + +> [!NOTE] +> If you don't grant `AllDatabasesViewer` during deployment, a cluster administrator can grant the equivalent viewer permission later. The Kusto connector won't return FinOps hub results until the managed identity has permission on the cluster. + +
+ +## Connector permissions + +The agent doesn't create Teams or Outlook notification connectors during deployment. You add them interactively in [sre.azure.com](https://sre.azure.com) after deployment. + +To configure a Teams or Outlook connector, the configuring user needs **Contributor** on the agent resource group, including these actions: + +| Permission | Why it's needed | +|------------|-----------------| +| `Microsoft.Web/connections/write` | Creates or updates the connector resource that stores the connection configuration | +| `Microsoft.Authorization/roleAssignments/write` | Assigns the selected managed identity permission to use the connector resource | + +Communication connectors use both OAuth and managed identity: + +1. You sign in with a Microsoft 365 account through OAuth. +2. You select the agent's managed identity. +3. The connector stores the OAuth token securely in the connector resource. +4. The agent uses the managed identity at runtime to access the connector resource and send messages or email. + +For Teams, the account that signs in must have access to the target channel and the channel's **Get link to channel** URL. The connector can post messages to the configured channel, reply to threads, and read channel messages for context. + +
+ +## Run modes + +Azure SRE Agent supports two run modes: + +| Mode | Security behavior | Use with the FinOps toolkit deployment | +|------|-------------------|---------------------------| +| Review | The agent proposes Azure infrastructure write actions, and an SRE Agent Administrator approves or denies them | Best for production response plans and any workflow that might change resources | +| Autonomous | The agent runs allowed actions without waiting for approval | Best for trusted recurring reports, health checks, and scheduled FinOps summaries | + +The template sets the agent action configuration to **Autonomous** so scheduled cost and capacity reports can run and post results without manual approval. + +> [!IMPORTANT] +> Run mode doesn't replace permissions. The agent can act only when its managed identity, connector, and data source permissions allow the action. Review mode adds an approval step for Azure infrastructure write actions, but other actions, such as querying data or posting to Teams, run based on available tools and permissions. + +Start with Review for workflows that could affect production resources. Use Autonomous for read-only reporting tasks after you confirm the prompts, tools, and destination channels are correct. + +
+ +## B2B tenant considerations + +In B2B environments, the Azure subscription and Azure SRE Agent resource can be in a different Microsoft Entra tenant than your Microsoft 365 home tenant. + +Use these checks when deployment, Azure MCP Server, or connector configuration fails: + +1. Confirm the active Azure CLI context points to the subscription that owns the SRE Agent resource. +2. Re-authenticate against the tenant that owns the subscription. +3. When using Azure MCP Server `sreagent` tools, pass the resource tenant, subscription, resource group, and agent name explicitly. +4. If Azure MCP Server returns `403` from its SRE Agent path, verify the same identity can read the ARM resource and data-plane endpoint before changing agent permissions. + +Browser access can succeed while a local tool returns `401`, `403`, or `Forbidden` if the token was issued for the wrong tenant. The deployment script sets the active subscription before deployment to reduce this risk. + +Connector setup can also cross identity boundaries. The Azure resource permissions come from the resource tenant, while Teams or Outlook OAuth uses the Microsoft 365 account that signs in to the connector. + +
+ +## Data flow + +The agent reads operational and cost data from these sources: + +- FinOps hub cost and usage data in Azure Data Explorer. +- Azure resource metadata through Reader permissions. +- Azure Monitor and Log Analytics context through target resource group reader permissions. +- Uploaded knowledge documents that describe FinOps toolkit tools, Teams notification patterns, report output style, and known issues. + +Scheduled reports and investigation summaries can be sent to: + +- The Azure SRE Agent chat experience. +- A configured Microsoft Teams channel. +- Outlook, if you add the Outlook connector. + +Don't save financial data to agent memory. Save only operational notes, such as tool errors, workarounds, and repeatable patterns. + +Data residency follows the Azure resources and Microsoft 365 services you connect. FinOps hub data stays in your Azure Data Explorer cluster until queried. Agent telemetry is written to the deployed Log Analytics and Application Insights resources. Teams or Outlook reports are delivered to the channel or mailbox you configure, and OAuth tokens are stored in the connector resource rather than in the agent prompt or knowledge files. + +
+ +## Least privilege checklist + +Use this checklist before you move from test to production: + +- Grant the deployment identity only the permissions needed for deployment. +- Keep the agent managed identity scoped to subscription Reader, target resource group reader/remediation permissions, and Azure Data Explorer viewer permissions unless your own workflows require more. +- Use Review mode for production workflows that can change Azure resources. +- Use Autonomous mode only for trusted reports, health checks, and read-only tasks. +- Configure Teams and Outlook connectors with accounts that are allowed to send to the target audience. +- Send reports only to channels or mailboxes approved for cost and capacity information. +- Review Data Explorer access when hub databases or clusters change. + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) +- [Usage optimization](../../framework/optimize/workloads.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Run modes in Azure SRE Agent](/azure/sre-agent/run-modes) +- [Azure Data Explorer](/azure/data-explorer/) +- [Azure Monitor](/azure/azure-monitor/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/template.md b/docs-mslearn/toolkit/sre-agent/template.md new file mode 100644 index 000000000..79e4c00a7 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/template.md @@ -0,0 +1,209 @@ +--- +title: Azure SRE Agent template reference (FinOps toolkit) +description: Review the FinOps toolkit's Azure SRE Agent deployment template, parameters, outputs, script flags, and Bicep module structure. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps hub admin, I want to understand the FinOps toolkit's Azure SRE Agent template so that I can deploy and customize it safely. +--- + +# Azure SRE Agent template reference (FinOps toolkit) + +This reference summarizes the [FinOps toolkit's Azure SRE Agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). Use it to review deployment prerequisites, Bicep parameters, script options, and module structure before you deploy or customize the template. + +
+ +## Prerequisites + +Ensure the following prerequisites are met before you deploy the template: + + +- You must have permissions to create the deployed resources and assign roles. + + | Task | Minimum permission | + | ---- | ------------------ | + | Deploy the subscription-scoped Bicep template and create the target resource group | [Contributor](/azure/role-based-access-control/built-in-roles#contributor) on the subscription | + | Assign subscription and target resource group roles to the agent managed identity | [Role Based Access Control Administrator](/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator), [User Access Administrator](/azure/role-based-access-control/built-in-roles#user-access-administrator), or [Owner](/azure/role-based-access-control/built-in-roles#owner) on the assignment scopes | + | Assign Azure Data Explorer access when cluster parameters are set | Permission to create `Microsoft.Kusto/clusters/principalAssignments` on the target cluster | + | Apply Azure SRE Agent objects with the portal deployment script or `bin/apply-extras.sh` | SRE Agent Administrator on the deployed Azure SRE Agent resource | + +- The `Microsoft.App` resource provider must be registered in the subscription. +- For local CLI deployments only: [Azure CLI](/cli/azure/install-azure-cli), `curl`, `jq`, Bash 3.2 or newer, and `python3` with PyYAML must be available locally. +- A FinOps hub with Azure Data Explorer is required when you want the agent to query hub data. + + +
+ +## Parameters + +Here are the parameters you can use to customize the deployment: + +| Parameter | Type | Default value | Allowed values | Description | +| --------- | ---- | ------------- | -------------- | ----------- | +| **resourceGroupName** | String | None | Any string | Required. Resource group that contains the SRE Agent resources. | +| **agentName** | String | None | Any string | Required. Azure SRE Agent name. | +| **location** | String | `eastus2` | `australiaeast`, `canadacentral`, `eastus2`, `francecentral`, `koreacentral`, `swedencentral`, `uksouth` | Optional. Primary location for all resources. | +| **targetResourceGroups** | Array | `[]` | Resource group names | Optional. Resource groups the agent can observe or act on. Defaults to the agent resource group. | +| **targetResourceGroupNames** | String | `""` | Comma-separated resource group names | Optional. Portal form input for target resource groups. Defaults to the agent resource group. | +| **accessLevel** | String | `High` | `Low`, `High` | Optional. Agent access level. | +| **actionMode** | String | `autonomous` | `review`, `autonomous`, `readOnly` | Optional. Agent action mode. | +| **upgradeChannel** | String | `Preview` | `Stable`, `Preview` | Optional. Agent upgrade channel. | +| **defaultModelProvider** | String | `MicrosoftFoundry` | `MicrosoftFoundry`, `Anthropic` | Optional. Parent SRE Agent model provider. `MicrosoftFoundry` maps to Azure OpenAI in the SRE Agent portal. | +| **defaultModelName** | String | `Automatic` | Any supported model name | Optional. Parent SRE Agent model name. Use `Automatic` so SRE Agent routes to the appropriate model inside the selected provider. | +| **monthlyAgentUnitLimit** | Int | `10000` | 1 or higher | Optional. Monthly agent unit limit. | +| **experimentalSettings** | Object | `{ "EnableSandboxGroup": true, "EnableWorkspaceTools": true }` | Object | Optional. Agent sandbox and workspace tool settings for the stable SRE Agent runtime. | +| **finopsHubKustoConnectorUri** | String | `""` | Database-qualified Kusto URI | Optional. Kusto connector URI for the FinOps hub database, such as `https://cluster.region.kusto.windows.net/Hub`. | +| **finopsHubKustoClusterResourceId** | String | `""` | Azure resource ID | Optional. Azure Data Explorer cluster resource ID for the FinOps hub role assignment. | +| **enableSubscriptionReaderRole** | Boolean | `true` | `true`, `false` | Optional. Assigns Reader at subscription scope to the agent managed identity. | +| **recipePackageUri** | String | Derived from the template URI | Public URI | Optional. URI for the packaged recipe assets used by the portal deployment script. | +| **forceUpdateTag** | String | Current deployment timestamp | Any string | Optional. Forces the portal deployment script to rerun during redeployment. | + +
+ +## Deployment values + +The portal template receives values from `createUiDefinition.json`, then runs a subscription-scoped ARM deployment directly from the published toolkit deploy artifacts. `bin/deploy.sh` writes a deployment parameter file under the local SRE Agent deployment cache, then runs `az deployment sub create` directly. Neither path uses Azure Developer CLI environments. + +| Value | Source | Description | +| ----- | ------ | ----------- | +| **subscription** | `--subscription` | Azure subscription ID. | +| **resourceGroupName** | `--resource-group` | Resource group that contains the SRE Agent resources. | +| **agentName** | `--name` | Azure SRE Agent name. | +| **location** | `--location` | Azure location for the deployment. | +| **targetResourceGroups** | `--target-resource-group` | Target resource group names. Defaults to the agent resource group. | +| **enableSubscriptionReaderRole** | Default, unless `--no-subscription-reader` is passed | Whether the deployment assigns subscription-scope Reader to the agent managed identity. | +| **defaultModelProvider** | `agent.json` | Parent SRE Agent model provider. The FinOps hub recipe defaults to Azure OpenAI provider-level routing with `MicrosoftFoundry`. | +| **defaultModelName** | `agent.json` | Parent SRE Agent model name. The FinOps hub recipe defaults to `Automatic` model routing. | +| **finopsHubKustoClusterResourceId** | `--cluster-resource-id` | Optional cluster resource ID used to assign `AllDatabasesViewer`. | +| **FinOps Hub Kusto connector URI** | `--cluster-uri` | Database-qualified Kusto URI, such as `https://cluster.region.kusto.windows.net/Hub`. | + +
+ +## Portal recipe configuration + +The Deploy to Azure path packages `azuredeploy.json`, `createUiDefinition.json`, and `sre-agent-recipe.zip` under `docs/deploy/sre-agent//`. The `recipePackageUri` parameter defaults to a file beside the linked template by using the ARM deployment template-link URI. The deployment script downloads that package, reads `extras.json`, and applies the same recipe objects as `bin/apply-extras.sh`. + +The deployment script uses a user-assigned managed identity. Bicep grants that identity SRE Agent Administrator on the agent resource before the script runs, then the script uses ARM for connectors and the SRE Agent data plane for built-in tools, knowledge, tools, skills, subagents, and scheduled tasks. + +
+ +## Azure Data Explorer network access + +When `--cluster-uri` points to an Azure Data Explorer cluster, the deployment inspects the cluster's network access setting before creating the agent. If `publicNetworkAccess` is `Disabled`, the deployment doesn't stop. It still deploys all resources, assigns the agent managed identity `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. + +The deployment prints a warning with the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations) because hosted Azure SRE Agent can't run direct KQL queries against private endpoint ADX clusters. The customer must decide whether to enable public query access for the cluster. Until public query access is enabled or Azure SRE Agent adds private endpoint ADX query support, the connector is expected to remain unhealthy. + +
+ +## Outputs + +Here are the outputs generated by the deployment: + +| Output | Type | Description | +| ------ | ---- | ----------- | +| **AZURE_RESOURCE_GROUP** | String | Name of the Azure resource group that contains the SRE Agent resources. | +| **AZURE_LOCATION** | String | Azure location used for the SRE Agent resources. | +| **SRE_AGENT_NAME** | String | Name of the deployed Azure SRE Agent resource. | +| **SRE_AGENT_ENDPOINT** | String | Endpoint of the deployed Azure SRE Agent resource. | + +
+ +## Script flags + +The template includes Bash scripts for one-shot deployment and extras configuration. + +### Deployment wrapper + +Use `bin/deploy.sh` to write deterministic ARM parameters, deploy `infra/main.bicep` with Azure CLI, and run `bin/apply-extras.sh`. + +Supporting resource names are deterministic for the subscription ID, agent resource group ID, and agent name. Rerunning the script with the same tuple updates the same Log Analytics workspace, Application Insights component, system-assigned managed identity RBAC assignments, and SRE Agent instead of creating timestamped duplicates. The optional `--deploy-name` only names the ARM deployment record and local build directory. + +| Bash flag | Required | Description | +| --------- | -------- | ----------- | +| `--recipe ` | Yes | Recipe directory. Use `recipes/finops-hub`. | +| `--subscription ` | Yes | Azure subscription ID. | +| `--resource-group ` | Yes | Resource group for SRE Agent resources. | +| `--name ` | Yes | Azure SRE Agent name. | +| `--location ` | Yes | Azure region. | +| `--target-resource-group ` | No | Repeatable target resource group. Defaults to `--resource-group`. | +| `--cluster-uri ` | No | Database-qualified FinOps hub Kusto URI, such as `https://cluster.region.kusto.windows.net/Hub`. | +| `--cluster-resource-id ` | Optional with `--cluster-uri` for real deployments; required for `--dry-run` | Kusto cluster ARM resource ID for `AllDatabasesViewer`. Real deployments resolve it from `--cluster-uri` when the cluster is in the target subscription. | +| `--no-subscription-reader` | No | Skips the default subscription-scope Reader assignment. Use only when equivalent read access is granted another way. | +| `--deploy-name ` | No | Deployment name override. Defaults to a deterministic name from subscription ID, resource group, and agent name. | +| `--dry-run` | No | Validate inputs and write parameters without Azure calls. | +| `--force`, `--no-telemetry` | No | Compatibility flags accepted by the wrapper. | +| `-h`, `--help` | No | Show script help. | + +### Extras configuration + +Use `bin/apply-extras.sh` to configure the Kusto connector through ARM when requested, upload KnowledgeFile sources, and apply custom agents, skills, tools, and scheduled tasks through the SRE Agent data plane. `bin/post-provision.sh` remains as a deprecated compatibility wrapper that forwards to `bin/apply-extras.sh`. + +| Bash flag | Required | Description | +| --------- | -------- | ----------- | +| `--endpoint ` | Yes | SRE Agent endpoint returned by deployment. | +| `--recipe ` | Yes | Recipe directory. | +| `--subscription ` | Yes | Azure subscription that contains the SRE Agent. | +| `--resource-group ` | Yes | Resource group that contains the SRE Agent. | +| `--name ` | Yes | SRE Agent name. | +| `--build-dir ` | Yes | Working directory for generated extras request and response files. | +| `--kusto-connector-uri ` | No | Database-qualified Kusto connector URI. | + +
+ +## Module structure + +The template uses a subscription-scoped entry point and resource group modules: + +| File | Scope | Deploys or configures | +| ---- | ----- | --------------------- | +| `infra/main.bicep` | Subscription | Creates the target resource group, calls the resource group deployment, assigns subscription and target resource group RBAC, and optionally assigns Azure Data Explorer roles. | +| `infra/resources.bicep` | Resource group | Orchestrates identity, monitoring, and Azure SRE Agent modules, then surfaces outputs to the subscription deployment. | +| `infra/modules/monitoring.bicep` | Resource group | Creates the Log Analytics workspace and workspace-based Application Insights component for telemetry. | +| `infra/modules/sre-agent.bicep` | Resource group | Creates the `Microsoft.App/agents@2026-01-01` resource, configures action mode, model provider, sandbox, and workspace tool settings, assigns SRE Agent Administrator to the deployer, and exposes the agent endpoint for `bin/apply-extras.sh`. | +| `infra/modules/resource-group-rbac.bicep` | Resource group | Assigns Reader, Monitoring Reader, Log Analytics Reader, and optionally Contributor to the agent system-assigned managed identity. | +| `infra/modules/kusto-all-databases-viewer-rbac.bicep` | Resource group | Assigns `AllDatabasesViewer` on an existing Azure Data Explorer cluster to the system-assigned managed identity when cluster parameters are provided. | + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/tools.md b/docs-mslearn/toolkit/sre-agent/tools.md new file mode 100644 index 000000000..429a08d50 --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/tools.md @@ -0,0 +1,186 @@ +--- +title: Tools shipped for Azure SRE Agent in the FinOps toolkit +description: Review the Kusto and Python tools the FinOps toolkit ships for Azure SRE Agent for cost analysis, anomaly detection, rate optimization, capacity management, and operations. +author: msbrett +ms.author: brettwil +ms.date: 06/01/2026 +ms.topic: reference +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to understand which tools the FinOps toolkit ships for Azure SRE Agent so that I can choose the right agent workflow for cost, capacity, and operations analysis. +--- + +# Tools shipped for Azure SRE Agent in the FinOps toolkit + +The FinOps toolkit deployment configures Azure SRE Agent with tools that ground agent responses in live Azure and FinOps hub data. [Kusto tools](kusto-tools.md) query the FinOps hub Azure Data Explorer database, and [Python tools](python-tools.md) call Azure APIs through the agent's managed identity. + +Use this article as a catalog of the tools included with the template. For deeper implementation details, review the [Kusto tools](kusto-tools.md) and [Python tools](python-tools.md) references. + +The template configures 50 tools: 37 Kusto query tools generated from the FinOps hub query catalog and 13 Python tools, as documented in the [Kusto tools](kusto-tools.md) and [Python tools](python-tools.md) references. All Kusto tools are assigned only to `ftk-database-query`; other agents request Kusto evidence from that specialist instead of querying FinOps hub directly. + +> [!NOTE] +> The agent list shows subagents that reference each tool in `recipes/finops-hub/config/subagents`. Tools marked "Not assigned" are included in the tool catalog, but aren't referenced by a subagent configuration. For agent roles and tool usage, see [agents and skills](agents.md). + +
+ +## AI cost management + +AI cost management tools help agents analyze Azure OpenAI spend, token usage, model efficiency, and application-level allocation, as described in [AI/ML costs](kusto-tools.md#aiml-costs). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `ai-cost-by-application` | `Kusto` | Breaks down Azure OpenAI costs by application, team, and environment tags for chargeback, showback, and allocation; see [ai-cost-by-application](kusto-tools.md#ai-cost-by-application). | `ftk-database-query` | +| `ai-daily-trend` | `Kusto` | Shows daily Azure OpenAI cost and token trends for AI cost anomaly detection and forecasting; see [ai-daily-trend](kusto-tools.md#ai-daily-trend). | `ftk-database-query` | +| `ai-model-cost-comparison` | `Kusto` | Compares Azure OpenAI model cost per 1,000 tokens to identify model efficiency opportunities; see [ai-model-cost-comparison](kusto-tools.md#ai-model-cost-comparison). | `ftk-database-query` | +| `ai-token-usage-breakdown` | `Kusto` | Breaks down Azure OpenAI token consumption by model version and input or output direction; see [ai-token-usage-breakdown](kusto-tools.md#ai-token-usage-breakdown). | `ftk-database-query` | + +
+ +## Cost analysis and reporting + +Cost analysis and reporting tools summarize FinOps hub cost data by service, region, resource group, financial hierarchy, transaction type, and time period, as described in [Cost analysis](kusto-tools.md#cost-analysis) and [Price analysis](kusto-tools.md#price-analysis). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `costs-enriched-base` | `Kusto` | Returns a guarded row-level enriched cost and usage sample for narrow drill-downs; see [costs-enriched-base](kusto-tools.md#costs-enriched-base). Use aggregate tools for full-month, fiscal-period, scheduled report, and tag-coverage rollup requests. | `ftk-database-query` | +| `cost-by-financial-hierarchy` | `Kusto` | Reports top costs across billing profile, invoice section, team, product, application, and environment; see [cost-by-financial-hierarchy](kusto-tools.md#cost-by-financial-hierarchy). | `ftk-database-query` | +| `cost-by-region-trend` | `Kusto` | Summarizes effective cost by Azure region to identify regional spend distribution and optimization opportunities; see [cost-by-region-trend](kusto-tools.md#cost-by-region-trend). | `ftk-database-query` | +| `monthly-cost-change-percentage` | `Kusto` | Calculates month-over-month billed and effective cost changes to spot spikes, drops, and volatility; see [monthly-cost-change-percentage](kusto-tools.md#monthly-cost-change-percentage). | `ftk-database-query` | +| `monthly-cost-trend` | `Kusto` | Returns billed and effective cost totals by month for trend review and budget analysis; see [monthly-cost-trend](kusto-tools.md#monthly-cost-trend). | `ftk-database-query` | +| `quarterly-cost-by-resource-group` | `Kusto` | Returns top resource-group cost rows by subscription and month for quarterly reporting windows; see [quarterly-cost-by-resource-group](kusto-tools.md#quarterly-cost-by-resource-group). | `ftk-database-query` | +| `top-other-transactions` | `Kusto` | Lists top non-usage, non-commitment purchase transactions, such as Marketplace or miscellaneous charges; see [top-other-transactions](kusto-tools.md#top-other-transactions). | `ftk-database-query` | +| `top-resource-groups-by-cost` | `Kusto` | Returns top resource groups by effective cost for focused reporting and optimization; see [top-resource-groups-by-cost](kusto-tools.md#top-resource-groups-by-cost). | `ftk-database-query` | +| `top-resource-types-by-cost` | `Kusto` | Returns top resource types by resource count and effective cost to identify costly categories; see [top-resource-types-by-cost](kusto-tools.md#top-resource-types-by-cost). | `ftk-database-query` | +| `top-services-by-cost` | `Kusto` | Returns top Azure services by effective cost to prioritize service-level optimization; see [top-services-by-cost](kusto-tools.md#top-services-by-cost). | `ftk-database-query` | + +
+ +## FinOps KPI scorecard + +FinOps KPI scorecard tools are generated from [`src/queries/catalog`](../../../src/queries/catalog/) and map directly to query links in [`src/queries/KPI.md`](../../../src/queries/KPI.md). Scheduled monthly, semiannual, health, anomaly, capacity, storage, monitoring, and benefit-review tasks request these tools through `ftk-database-query`. + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `allocation-accuracy-index` | `Kusto` | Measures directly attributed cost as a share of total effective cost. | `ftk-database-query` | +| `anomaly-detection-rate` | `Kusto` | Measures the share of spend in anomaly-flagged daily buckets. | `ftk-database-query` | +| `anomaly-variance-total` | `Kusto` | Quantifies unpredicted spend variance for detected anomaly events. | `ftk-database-query` | +| `commitment-discount-waste` | `Kusto` | Measures unused commitment value as a share of total commitment cost. | `ftk-database-query` | +| `commitment-utilization-score` | `Kusto` | Computes commitment utilization score by commitment and currency. | `ftk-database-query` | +| `compute-cost-per-core` | `Kusto` | Calculates effective and hourly compute cost per consumed vCPU core hour. | `ftk-database-query` | +| `compute-spend-commitment-coverage` | `Kusto` | Measures compute spend covered by commitment discounts. | `ftk-database-query` | +| `cost-optimization-index` | `Kusto` | Computes a cost optimization index from current recommendations and cost context. | `ftk-database-query` | +| `cost-per-gb-stored` | `Kusto` | Calculates storage cost per normalized GB-month. | `ftk-database-query` | +| `cost-visibility-delay` | `Kusto` | Measures cost data visibility delay for data-ingestion KPI reporting. | `ftk-database-query` | +| `data-update-frequency` | `Kusto` | Measures FinOps hub ingestion update cadence. | `ftk-database-query` | +| `macc-consumption-vs-commitment` | `Kusto` | Measures Microsoft Azure Consumption Commitment drawdown against commitment. | `ftk-database-query` | +| `percentage-unallocated-costs` | `Kusto` | Measures the share of cost missing required allocation evidence. | `ftk-database-query` | +| `percentage-untagged-costs` | `Kusto` | Measures the share of cost on resources with no tags. | `ftk-database-query` | +| `storage-tier-distribution` | `Kusto` | Summarizes storage cost and GB-month distribution by access-tier bucket. | `ftk-database-query` | +| `tagging-policy-compliance` | `Kusto` | Measures cost-weighted compliance with required tag keys. | `ftk-database-query` | + +
+ +## Anomaly detection and forecasting + +Anomaly detection and forecasting tools help agents identify unexpected cost changes, project future spend, and deploy alerting automation, as described in [Anomaly detection](kusto-tools.md#anomaly-detection), [Forecasting](kusto-tools.md#forecasting), and [Budget and alert deployment](python-tools.md#budget-and-alert-deployment). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `cost-anomaly-detection` | `Kusto` | Detects cost spikes and drops with time-series anomaly detection over a configurable history window; see [cost-anomaly-detection](kusto-tools.md#cost-anomaly-detection). | `ftk-database-query` | +| `cost-forecasting-model` | `Kusto` | Forecasts future effective cost from historical cost data for budgeting and trend projection; see [cost-forecasting-model](kusto-tools.md#cost-forecasting-model). | `ftk-database-query` | +| `deploy-anomaly-alert` | `Python` | Creates or updates a Cost Management scheduled action for anomaly detection in a subscription after explicit remediation approval; see [deploy-anomaly-alert](python-tools.md#deploy-anomaly-alert). | `finops-practitioner` | +| `deploy-bulk-anomaly-alerts` | `Python` | Discovers enabled subscriptions in a management group and deploys anomaly alert scheduled actions per subscription after explicit remediation approval; see [deploy-bulk-anomaly-alerts](python-tools.md#deploy-bulk-anomaly-alerts). | `finops-practitioner` | + +
+ +## Rate optimization + +Rate optimization tools help agents review reservations, savings plans, pricing benchmarks, commitment transactions, and Advisor recommendation suppression workflows, as described in [Commitment discounts](kusto-tools.md#commitment-discounts), [Price analysis](kusto-tools.md#price-analysis), [Resource analysis](python-tools.md#resource-analysis), and [Advisor](python-tools.md#advisor). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `benefit-recommendations` | `Python` | Gets Microsoft Cost Management benefit recommendations for savings plans and reserved instances at a billing scope; see [benefit-recommendations](python-tools.md#benefit-recommendations). | `finops-practitioner`, `azure-capacity-manager` | +| `commitment-discount-utilization` | `Kusto` | Analyzes consumed core hours by commitment discount type, including on-demand usage, for a reporting window; see [commitment-discount-utilization](kusto-tools.md#commitment-discount-utilization). | `ftk-database-query` | +| `reservation-recommendation-breakdown` | `Kusto` | Analyzes reservation recommendations, savings, break-even dates, normalized sizes, scope, and term details; see [reservation-recommendation-breakdown](kusto-tools.md#reservation-recommendation-breakdown). | `ftk-database-query` | +| `savings-summary-report` | `Kusto` | Summarizes list cost, effective cost, negotiated savings, commitment savings, total savings, and savings rate; see [savings-summary-report](kusto-tools.md#savings-summary-report). | `ftk-database-query` | +| `service-price-benchmarking` | `Kusto` | Benchmarks services by list cost, contracted cost, effective cost, negotiated savings, commitment savings, and total savings; see [service-price-benchmarking](kusto-tools.md#service-price-benchmarking). | `ftk-database-query` | +| `suppress-advisor-recommendations` | `Python` | Suppresses selected Azure Advisor recommendations across subscriptions under a management group with a time to live after explicit remediation approval; see [suppress-advisor-recommendations](python-tools.md#suppress-advisor-recommendations). | `finops-practitioner` | +| `top-commitment-transactions` | `Kusto` | Returns top non-usage commitment discount purchase transactions for reservation and savings plan review; see [top-commitment-transactions](kusto-tools.md#top-commitment-transactions). | `ftk-database-query` | + +
+ +## Capacity management + +Capacity management tools help agents inspect quota, capacity reservations, SKU availability, and non-compute service limits before planning or deployment, as described in [Capacity and quota](python-tools.md#capacity-and-quota) and the [azure-capacity-manager](agents.md#azure-capacity-manager) agent reference. + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `capacity-reservation-groups` | `Python` | Lists capacity reservation groups and compares reserved capacity with allocated virtual machines; see [capacity-reservation-groups](python-tools.md#capacity-reservation-groups). | `azure-capacity-manager` | +| `non-compute-quotas` | `Python` | Checks non-compute service quota usage with provider usage APIs and estimated Resource Graph fallbacks; see [non-compute-quotas](python-tools.md#non-compute-quotas). | `azure-capacity-manager` | +| `sku-availability` | `Python` | Lists Azure Compute or Azure Data Explorer SKU availability, zones, and regional restriction reasons before planning or deployment; see [sku-availability](python-tools.md#sku-availability). | `azure-capacity-manager`, `ftk-hubs-agent` | +| `vm-quota-usage` | `Python` | Reports VM family quota usage by region and flags families above 80% or 95% utilization; see [vm-quota-usage](python-tools.md#vm-quota-usage). | `azure-capacity-manager` | + +
+ +## Governance and automation + +Governance and automation tools help agents deploy budget guardrails and run Resource Graph queries for inventory, configuration, and operational checks, as described in [Budget and alert deployment](python-tools.md#budget-and-alert-deployment) and [Resource analysis](python-tools.md#resource-analysis). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `deploy-budget` | `Python` | Creates or updates a subscription-level Cost Management budget with notification contacts after explicit remediation approval; see [deploy-budget](python-tools.md#deploy-budget). | `finops-practitioner` | +| `deploy-bulk-budgets` | `Python` | Discovers enabled subscriptions in a management group and creates or updates a Cost Management budget in each subscription after explicit remediation approval; see [deploy-bulk-budgets](python-tools.md#deploy-bulk-budgets). | `finops-practitioner` | +| `resource-graph-query` | `Python` | Runs Azure Resource Graph KQL queries across subscriptions for inventory and configuration troubleshooting; see [resource-graph-query](python-tools.md#resource-graph-query). | `finops-practitioner`, `azure-capacity-manager`, `ftk-hubs-agent` | + +
+ +## Data ingestion and health + +Data ingestion and health tools help agents validate whether FinOps hub data is fresh enough to trust for analysis and reporting, as described in [Hub management](python-tools.md#hub-management). + +| Tool | Type | Description | Agents | +|------|------|-------------|--------| +| `data-freshness-check` | `Python` | Checks FinOps hub function data freshness through direct Azure Data Explorer REST queries. Treats `Costs()` as the authoritative freshness signal with a three-day threshold and supersedes conflicting stale-memory or raw-KQL conclusions; see [data-freshness-check](python-tools.md#data-freshness-check). | `ftk-hubs-agent` | + +
+ +## Give feedback + +Let us know how we're doing with a [quick review](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent). We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgent) + + +If you're looking for something specific, [vote for an existing or create a new idea](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc). Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) +- [Microsoft Cost Management](/azure/cost-management-billing/costs/) + +Related solutions: + +- [Azure SRE Agent in the FinOps toolkit](overview.md) +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) + +
diff --git a/docs-mslearn/toolkit/sre-agent/troubleshooting.md b/docs-mslearn/toolkit/sre-agent/troubleshooting.md new file mode 100644 index 000000000..4f029c16a --- /dev/null +++ b/docs-mslearn/toolkit/sre-agent/troubleshooting.md @@ -0,0 +1,252 @@ +--- +title: Troubleshoot Azure SRE Agent deployments from the FinOps toolkit +description: Resolve common deployment, tenant, connector, data, and query issues for Azure SRE Agent deployments from the FinOps toolkit. +author: msbrett +ms.author: brettwil +ms.date: 06/02/2026 +ms.topic: how-to +ms.service: finops +ms.subservice: finops-toolkit +ms.reviewer: brettwil +#customer intent: As a FinOps practitioner, I want to troubleshoot the FinOps toolkit's Azure SRE Agent deployment so that I can restore scheduled cost, capacity, and operations workflows. +--- + +# Troubleshoot Azure SRE Agent deployments from the FinOps toolkit + +Use this guide when the agent deploys, but Azure MCP Server `sreagent` commands, scheduled tasks, connectors, or data queries don't behave as expected. Start with tenant and deployment checks, then use the known issue sections to match the symptom, cause, and workaround. + +
+ +## Troubleshoot B2B tenant environments + +In B2B environments, the Azure subscription and Azure SRE Agent resource can live in a different Microsoft Entra tenant than your Microsoft 365 home tenant. If [sre.azure.com](https://sre.azure.com) shows the agent correctly but Azure MCP Server `sreagent` commands return `401`, `403`, `AccessDenied`, or `Forbidden`, treat the issue as tenant selection first. + +**Symptom:** Browser access works, but Azure MCP Server `sreagent_agents_list`, `sreagent_agents_get`, `sreagent_agents_tools_list`, or related SRE Agent commands fail with `401`, `403`, `AccessDenied`, or `Forbidden`. + +**Cause:** The tool token can be issued for the wrong tenant or the tool can route the SRE Agent discovery call through a tenant-scoped Resource Graph path. The browser session can use your Microsoft 365 home tenant, while the Azure SRE Agent resource belongs to a different tenant. + +**Workaround:** + +1. Confirm the active Azure CLI context points at the subscription that owns the Azure SRE Agent resource. +1. Re-authenticate Azure CLI against the tenant that owns the subscription and resource. +1. Pass the resource tenant, subscription, resource group, and agent name explicitly to Azure MCP Server `sreagent` commands. +1. Verify the same identity can read the ARM resource with `az resource show` and can call the SRE Agent data-plane endpoint with a token for `https://azuresre.dev`. +1. If ARM and direct data-plane calls work but Azure MCP Server `sreagent` commands still return `AccessDenied`, capture the timestamp and correlation ID from the tool response and route it as an Azure MCP Server or Azure SRE Agent B2B access issue. + +> [!TIP] +> Browser success with Azure MCP Server failure usually means the agent might be healthy, but the tool credential or SRE Agent discovery path needs tenant-specific verification. + +
+ +## Fix common deployment failures + +Use these checks after `bin/deploy.sh` or post-provisioning fails. + +### Unsupported region + +**Symptom:** The Bicep deployment fails during validation or resource creation. + +**Cause:** The template only supports `australiaeast`, `canadacentral`, `eastus2`, `francecentral`, `koreacentral`, `swedencentral`, and `uksouth`. + +**Workaround:** Redeploy in a supported region. + +### Resource provider not registered + +**Symptom:** Azure Resource Manager fails to create the Azure SRE Agent resource. + +**Cause:** The `Microsoft.App` resource provider isn't registered on the target subscription. + +**Workaround:** Register the provider, wait for registration to complete, and rerun deployment. + +```bash +az provider register --namespace Microsoft.App +``` + +### Missing deployment permissions + +**Symptom:** Deployment or role assignment steps fail with authorization errors. + +**Cause:** The deploying user doesn't have enough permissions to create resources or assign roles. + +**Workaround:** Use an account with permissions to create resources and assign roles at the affected scopes. Contributor can create the deployed resources; Role Based Access Control Administrator, User Access Administrator, or Owner can assign the required roles. If you configure notification connectors later, make sure the configuring user can write connections and role assignments in the agent resource group. + +### Zone mapping API returns 404 + +**Symptom:** Capacity or zone-mapping checks fail when the agent calls `checkZonePeers`. + +**Cause:** The `AvailabilityZonePeering` feature isn't registered for the subscription or management group scope. + +**Workaround:** Register the feature and re-register the resource provider. + +```bash +az feature register --namespace Microsoft.Resources --name AvailabilityZonePeering +az provider register --namespace Microsoft.Resources +``` + +### Post-provision hook fails + +**Symptom:** Azure resources deploy, but skills, agents, tools, scheduled tasks, knowledge documents, or the Kusto connector don't appear in [sre.azure.com](https://sre.azure.com). + +**Cause:** The post-provision step couldn't resolve the endpoint, get an SRE Agent data-plane token, configure the Kusto connector, or apply the SRE configuration through the supported ARM and data-plane APIs. + +**Workaround:** Check that Azure CLI, `python3`, `jq`, `curl`, and `bash` are available locally. Then rerun `bin/apply-extras.sh` from `src/templates/sre-agent`. + +### Connector setup is missing + +**Symptom:** Scheduled tasks run, but Teams or Outlook delivery doesn't work. + +**Cause:** `bin/deploy.sh` does not create notification connectors because Teams and Outlook require interactive OAuth setup. + +**Workaround:** Add the Teams or Outlook connector in [sre.azure.com](https://sre.azure.com), select the agent managed identity, and send a test message. + +### Kusto connector is unhealthy for a private endpoint cluster + +**Symptom:** The SRE Agent deployment succeeds and the `finops-hub-kusto` connector is created, but the connector doesn't become healthy. The deployment output may warn that the Azure Data Explorer cluster denies public query access. + +**Cause:** Hosted Azure SRE Agent runs outside your VNET. Azure SRE Agent can use ARM for resource discovery, health, metrics, and management operations, but direct KQL queries to private endpoint Azure Data Explorer clusters are a documented limitation when `publicNetworkAccess` is `Disabled`. + +**Workaround:** Review the [Azure SRE Agent VNET known limitations](https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations), then decide whether to enable public query access for the Azure Data Explorer cluster. The FinOps toolkit deployment doesn't change customer cluster networking automatically. Until public query access is enabled or Azure SRE Agent adds private endpoint ADX query support, Kusto tools that depend on `finops-hub-kusto` are expected to fail while ARM-based health and metrics operations continue to work. + +
+ +## Review known issues + +The following issues were observed during scheduled task testing. They don't always indicate a broken deployment. + +### Teams tool discovery + +**Symptom:** A subagent reports that `PostTeamsChannelMessage` isn't available or that it couldn't find the Teams posting function. + +**Cause:** Subagents invoked directly for manual testing might not inherit Teams connector tools. Connector tools are available to the base agent or when the platform triggers a scheduled task. + +**Workaround:** + +- Use the platform cron schedule for production scheduled tasks. +- For manual testing, invoke the base agent without the `--agent` flag, then delegate with `@subagent` in the prompt. +- Use the built-in `PostTeamsMessage` tool. Don't call Microsoft Graph or dynamic invoke endpoints directly because that path can return `403`. + +### Data pipeline staleness + +**Symptom:** Reports show incomplete or missing recent cost data, and forecasts look distorted. + +**Cause:** The FinOps hub data pipeline or Cost Management export may be stale, so the Azure Data Explorer cluster might not have current data. Older memory notes, raw KQL checks, or ingestion timestamp checks can also report stale data incorrectly after the pipeline has recovered. + +**Workaround:** + +- Run `data-freshness-check` or the hubs health check task to confirm freshness before escalating. Treat the direct REST `Costs()` result as the source of truth. +- If `Costs()` is 3 days old or newer, mark conflicting stale-memory, raw-KQL, or ingestion timestamp conclusions as superseded and don't report the hub as stale. +- If `Costs()` has no rows, has a query error, or is more than 3 days old, let reports call out stale data clearly and check Cost Management exports in the Azure portal and pipeline runs in Azure Data Factory. + +### Resource Graph failures + +**Symptom:** `az graph query` returns an unknown error, and Resource Graph-based analysis fails. + +**Cause:** The managed identity may not have Reader permissions at the right scope, or complex query expressions may fail in the code interpreter shell environment. + +**Workaround:** + +- Fall back to scoped `az resource list` queries against specific subscriptions. +- Confirm the agent managed identity has Reader at the management group or subscription scope. +- Simplify query expressions. + +### Quota CLI failures + +**Symptom:** `az quota usage list` or `az vm list-usage` fails in the agent execution environment. + +**Cause:** The `az quota` extension might be missing, or the managed identity might not have permission to read quota data. + +**Workaround:** + +- Use `az vm list-usage --location ` as a compute quota fallback. +- For broader quota checks, use Azure Resource Manager REST calls from code interpreter. +- Track persistent CLI failures so the quota tool can be updated. + +### JMESPath escaping + +**Symptom:** Azure CLI commands fail when `--query` uses backticks, brackets, or property names with dots. + +**Cause:** Shell escaping conflicts with JMESPath syntax in the code interpreter environment. + +**Workaround:** + +- Prefer `--output json`, then parse the result with Python. +- Use only simple JMESPath selections when you need `--query`. +- Avoid nested expressions that rely on backtick-escaped property names. + +### Memory file conflicts + +**Symptom:** A scheduled task returns `File write failed` and says a memory file already exists. + +**Cause:** A repeated task run tried to create the same memory file again. The memory system requires an edit operation for existing files. + +**Workaround:** + +- Use an edit operation for subsequent writes to the same memory file. +- Treat the first failure as recoverable. Agents can usually switch from create to edit and continue. + +### Kusto query errors + +**Symptom:** A tool returns `Error executing query on cluster`. + +**Cause:** A Kusto tool may reference a function, table, or column that doesn't exist in your FinOps hub version, or the query syntax may need a version-specific update. + +**Workaround:** + +- Try a simpler query. +- Check the FinOps hub version. +- Capture the failing tool name and query so the tool YAML can be fixed. + +
+ +## Get support + +If the workaround doesn't resolve the issue, [open a GitHub issue](https://github.com/microsoft/finops-toolkit/issues/new/choose) and include: + +- The deployment region and target subscription tenant +- The failing command, task, or tool name +- The exact error message +- Whether [sre.azure.com](https://sre.azure.com) can open the agent successfully +- Whether the issue affects deployment, Azure MCP Server `sreagent` commands, scheduled tasks, connectors, or FinOps hub data + +For product ideas or known gaps, [vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc). + +
+ +## Give feedback + +Let us know how we're doing with a quick review. We use these reviews to improve and expand FinOps tools and resources. + + +> [!div class="nextstepaction"] +> [Give feedback](https://portal.azure.com/#view/HubsExtension/InProductFeedbackBlade/extensionName/FinOpsToolkit/cesQuestion/How%20easy%20or%20hard%20is%20it%20to%20use%20the%20FinOps%20SRE%20Agent%3F/cvaQuestion/How%20valuable%20is%20the%20FinOps%20SRE%20Agent%3F/surveyId/FTK/bladeName/SREAgent/featureName/SREAgentTroubleshooting) + + +If you're looking for something specific, vote for an existing or create a new idea. Share ideas with others to get more votes. We focus on ideas with the most votes. + + +> [!div class="nextstepaction"] +> [Vote on or suggest ideas](https://github.com/microsoft/finops-toolkit/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22Tool%3A%20SRE%20Agent%22%20sort%3Areactions-%2B1-desc) + + +
+ +## Related content + +Related FinOps capabilities: + +- [Reporting and analytics](../../framework/understand/reporting.md) +- [Anomaly management](../../framework/understand/anomalies.md) +- [Rate optimization](../../framework/optimize/rates.md) + +Related products: + +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) + +Related solutions: + +- [Deploy Azure SRE Agent with the FinOps toolkit](deploy.md) +- [FinOps hubs](../hubs/finops-hubs-overview.md) +- [Azure SRE Agent template reference (FinOps toolkit)](template.md) + +
diff --git a/docs/deploy/sre-agent/14.0/azuredeploy.json b/docs/deploy/sre-agent/14.0/azuredeploy.json new file mode 100644 index 000000000..4b6a6d0eb --- /dev/null +++ b/docs/deploy/sre-agent/14.0/azuredeploy.json @@ -0,0 +1,1119 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "2403415415579441400" + } + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group that holds the SRE Agent resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "defaultValue": "eastus2", + "allowedValues": [ + "australiaeast", + "canadacentral", + "eastus2", + "francecentral", + "koreacentral", + "swedencentral", + "uksouth" + ], + "metadata": { + "description": "Primary location for all resources." + } + }, + "targetResourceGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Resource groups the agent can observe or act on. The agent resource group is always included." + } + }, + "targetResourceGroupNames": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Comma-separated resource groups the agent can observe or act on. Used by the Azure portal form." + } + }, + "finopsHubKustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified FinOps Hub Kusto connector URI. Example: https://..kusto.windows.net/Hub" + } + }, + "finopsHubKustoClusterResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment." + } + }, + "accessLevel": { + "type": "string", + "defaultValue": "High", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "defaultValue": "autonomous", + "allowedValues": [ + "review", + "autonomous", + "readOnly" + ], + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "defaultValue": "Preview", + "allowedValues": [ + "Stable", + "Preview" + ], + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "defaultValue": "MicrosoftFoundry", + "allowedValues": [ + "MicrosoftFoundry", + "Anthropic" + ], + "metadata": { + "description": "Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal." + } + }, + "defaultModelName": { + "type": "string", + "defaultValue": "Automatic", + "metadata": { + "description": "Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "defaultValue": 10000, + "minValue": 1, + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "defaultValue": { + "EnableSandboxGroup": true, + "EnableWorkspaceTools": true + }, + "metadata": { + "description": "Agent experimental settings." + } + }, + "enableSubscriptionReaderRole": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Assign Reader on the deployment subscription to the agent managed identity." + } + }, + "recipePackageUri": { + "type": "string", + "defaultValue": "[uri(deployment().properties.templateLink.uri, 'sre-agent-recipe.zip')]", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Forces the recipe deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": { + "finops-toolkit": "sre-agent", + "source": "microsoft-finops-toolkit" + }, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "copy": [ + { + "name": "targetRgIds", + "count": "[length(variables('targetRgs'))]", + "input": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex('targetRgIds')])]" + } + ], + "rawTargetResourceGroups": "[split(replace(parameters('targetResourceGroupNames'), ' ', ''), ',')]", + "parsedTargetResourceGroups": "[filter(variables('rawTargetResourceGroups'), lambda('rgName', not(empty(lambdaVariables('rgName')))))]", + "targetRgs": "[union(createArray(parameters('resourceGroupName')), parameters('targetResourceGroups'), variables('parsedTargetResourceGroups'))]", + "agentResourceGroupId": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "namingSeed": "[toLower(format('{0}|{1}|{2}', subscription().subscriptionId, variables('agentResourceGroupId'), parameters('agentName')))]", + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "hasKustoCluster": "[not(empty(parameters('finopsHubKustoClusterResourceId')))]", + "kustoClusterSubscriptionId": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[2], '')]", + "kustoClusterResourceGroupName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[4], '')]", + "kustoClusterName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[8], '')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2024-03-01", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "condition": "[parameters('enableSubscriptionReaderRole')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(subscription().id, variables('namingSeed'), variables('readerRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('readerRoleId'))]", + "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "resources-deployment", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "agentName": { + "value": "[parameters('agentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "namingSeed": { + "value": "[variables('namingSeed')]" + }, + "targetResourceGroupIds": { + "value": "[variables('targetRgIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11748842726639098374" + } + }, + "parameters": { + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location for all resources." + } + }, + "namingSeed": { + "type": "string", + "metadata": { + "description": "Deterministic naming seed built from subscription ID, agent resource group ID, and agent name." + } + }, + "targetResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs shown as managed resources in the SRE Agent." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "uniqueSuffix": "[uniqueString(parameters('namingSeed'))]", + "logAnalyticsName": "[format('law-{0}', variables('uniqueSuffix'))]", + "appInsightsName": "[format('appi-{0}', variables('uniqueSuffix'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "monitoring", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsName": { + "value": "[variables('logAnalyticsName')]" + }, + "appInsightsName": { + "value": "[variables('appInsightsName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "9164683275614055037" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources" + } + }, + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Log Analytics Workspace name" + } + }, + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Application Insights name" + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsName')]", + "location": "[parameters('location')]", + "properties": { + "sku": { + "name": "PerGB2018" + }, + "retentionInDays": 30 + } + }, + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('appInsightsName')]", + "location": "[parameters('location')]", + "kind": "web", + "properties": { + "Application_Type": "web", + "Request_Source": "IbizaAIExtension", + "WorkspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + ] + } + ], + "outputs": { + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "value": "[parameters('logAnalyticsName')]" + }, + "appInsightsId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/components', parameters('appInsightsName'))]" + }, + "appInsightsAppId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').AppId]" + }, + "appInsightsConnectionString": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').ConnectionString]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "sre-agent", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "appInsightsAppId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsAppId.value]" + }, + "appInsightsConnectionString": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsConnectionString.value]" + }, + "appInsightsId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsId.value]" + }, + "managedResourceGroupIds": { + "value": "[parameters('targetResourceGroupIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6562535881153200016" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "appInsightsAppId": { + "type": "string", + "metadata": { + "description": "Application Insights App ID." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "metadata": { + "description": "Application Insights connection string." + } + }, + "appInsightsId": { + "type": "string", + "metadata": { + "description": "Application Insights resource ID." + } + }, + "managedResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs to add as managed resources." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.App/agents", + "apiVersion": "2026-01-01", + "name": "[parameters('agentName')]", + "location": "[parameters('location')]", + "tags": "[union(parameters('tags'), createObject('hidden-link: /app-insights-resource-id', parameters('appInsightsId'), 'source', 'microsoft-sre-agent-starter-lab', 'finops-toolkit', 'sre-agent'))]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "knowledgeGraphConfiguration": { + "managedResources": "[parameters('managedResourceGroupIds')]", + "identity": "system" + }, + "actionConfiguration": { + "mode": "[parameters('actionMode')]", + "identity": "system", + "accessLevel": "[parameters('accessLevel')]" + }, + "upgradeChannel": "[parameters('upgradeChannel')]", + "defaultModel": { + "provider": "[parameters('defaultModelProvider')]", + "name": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": "[parameters('monthlyAgentUnitLimit')]", + "experimentalSettings": "[parameters('experimentalSettings')]", + "mcpServers": [], + "logConfiguration": { + "applicationInsightsConfiguration": { + "appId": "[parameters('appInsightsAppId')]", + "connectionString": "[parameters('appInsightsConnectionString')]" + } + } + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), deployer().objectId, variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[deployer().objectId]", + "principalType": "User" + }, + "dependsOn": [ + "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[parameters('agentName')]" + }, + "agentId": { + "type": "string", + "value": "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01').agentEndpoint]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[format('https://sre.azure.com/#/agent/{0}/{1}/{2}', subscription().subscriptionId, resourceGroup().name, parameters('agentName'))]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.principalId]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.tenantId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'monitoring')]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentName.value]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentTenantId.value]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]" + ] + }, + { + "copy": { + "name": "targetRbac", + "count": "[length(variables('targetRgs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('target-rbac-{0}', uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex()])), variables('namingSeed')))]", + "resourceGroup": "[variables('targetRgs')[copyIndex()]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6305641259472431615" + } + }, + "parameters": { + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity to assign roles to." + } + }, + "accessLevel": { + "type": "string", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + } + }, + "variables": { + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "monitoringReaderRoleId": "43d0d8ad-25c7-4714-9337-8ba259a9fe05", + "logAnalyticsReaderRoleId": "73c42c96-874c-492b-b04d-ab87d138a893", + "contributorRoleId": "b24988ac-6180-42a0-ab88-20f7382dd24c", + "roleIds": "[if(equals(parameters('accessLevel'), 'High'), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId'), variables('contributorRoleId')), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId')))]" + }, + "resources": [ + { + "copy": { + "name": "roleAssignments", + "count": "[length(variables('roleIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(resourceGroup().id, parameters('principalId'), variables('roleIds')[copyIndex()])]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleIds')[copyIndex()])]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "condition": "[variables('hasKustoCluster')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('kusto-rbac-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed')))]", + "subscriptionId": "[variables('kustoClusterSubscriptionId')]", + "resourceGroup": "[variables('kustoClusterResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "clusterName": { + "value": "[variables('kustoClusterName')]" + }, + "principalApplicationId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "principalTenantId": { + "value": "[tenant().tenantId]" + }, + "principalAssignmentName": { + "value": "[format('sre-agent-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed'), 'all-db-viewer'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15341408879505554256" + } + }, + "parameters": { + "clusterName": { + "type": "string", + "metadata": { + "description": "Kusto cluster name." + } + }, + "principalApplicationId": { + "type": "string", + "metadata": { + "description": "Microsoft Entra application/client ID to assign to the Kusto cluster." + } + }, + "principalTenantId": { + "type": "string", + "metadata": { + "description": "Principal tenant ID." + } + }, + "principalAssignmentName": { + "type": "string", + "metadata": { + "description": "Stable principal assignment name." + } + } + }, + "resources": [ + { + "type": "Microsoft.Kusto/clusters/principalAssignments", + "apiVersion": "2024-04-13", + "name": "[format('{0}/{1}', parameters('clusterName'), parameters('principalAssignmentName'))]", + "properties": { + "principalId": "[parameters('principalApplicationId')]", + "principalType": "App", + "role": "AllDatabasesViewer", + "tenantId": "[parameters('principalTenantId')]" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "apply-extras", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "agentEndpoint": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "subscriptionId": { + "value": "[subscription().subscriptionId]" + }, + "recipePackageUri": { + "value": "[parameters('recipePackageUri')]" + }, + "kustoConnectorUri": { + "value": "[parameters('finopsHubKustoConnectorUri')]" + }, + "forceUpdateTag": { + "value": "[parameters('forceUpdateTag')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "5168893811325309322" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for the deployment script resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "agentEndpoint": { + "type": "string", + "metadata": { + "description": "SRE Agent data-plane endpoint." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "Subscription that contains the SRE Agent." + } + }, + "recipePackageUri": { + "type": "string", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package." + } + }, + "kustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified Kusto connector URI." + } + }, + "forceUpdateTag": { + "type": "string", + "metadata": { + "description": "Forces the deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "$fxv#0": "# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n\n$ErrorActionPreference = 'Stop'\n\nfunction Get-RequiredEnv($Name) {\n $value = [Environment]::GetEnvironmentVariable($Name)\n if ([string]::IsNullOrWhiteSpace($value)) {\n throw \"Missing required environment variable: $Name\"\n }\n return $value\n}\n\nfunction Get-OptionalEnv($Name) {\n return [Environment]::GetEnvironmentVariable($Name)\n}\n\nfunction ConvertTo-BodyJson($Value) {\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\n}\n\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\n foreach ($name in $Names) {\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\n return $Object.$name\n }\n }\n return $Default\n}\n\nfunction Get-HttpStatusCode($Exception) {\n if ($Exception.Response -and $Exception.Response.StatusCode) {\n return [int]$Exception.Response.StatusCode\n }\n return $null\n}\n\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\n try {\n return & $Action\n }\n catch {\n $statusCode = Get-HttpStatusCode $_.Exception\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\n throw\n }\n if ($attempt -eq $MaxAttempts) {\n throw\n }\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\n Start-Sleep -Seconds $DelaySeconds\n }\n }\n}\n\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\n $headers = @{\n Authorization = \"Bearer $Token\"\n 'Content-Type' = 'application/json'\n }\n $parameters = @{\n Method = $Method\n Uri = $Uri\n Headers = $headers\n }\n if ($null -ne $Body) {\n $parameters.Body = ConvertTo-BodyJson $Body\n }\n return Invoke-RestMethod @parameters\n}\n\nfunction Get-KnowledgeSourceName([string]$FileName) {\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\n $name = $name -replace '-+', '-'\n return $name.Trim('-')\n}\n\nfunction Get-Collection($Value) {\n if ($null -eq $Value) {\n return @()\n }\n return @($Value)\n}\n\nfunction Convert-TokenToString($Token) {\n if ($Token -is [Security.SecureString]) {\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\n try {\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\n }\n finally {\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\n }\n }\n return [string]$Token\n}\n\nfunction Get-ArmAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\n}\n\nfunction Get-SreAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\n}\n\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\n$agentName = Get-RequiredEnv 'agentName'\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\n$armApiVersion = '2025-05-01-preview'\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\n\nWrite-Output 'Connecting with deployment script managed identity...'\nConnect-AzAccount -Identity | Out-Null\nSet-AzContext -Subscription $subscriptionId | Out-Null\n\n$workRoot = Join-Path $env:TEMP 'sre-agent-recipe'\n$zipPath = Join-Path $env:TEMP 'sre-agent-recipe.zip'\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\n\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\nInvoke-WithRetry -Label 'download recipe package' -Action {\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\n} | Out-Null\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\n\n$extrasPath = Join-Path $workRoot 'extras.json'\nif (-not (Test-Path $extrasPath)) {\n throw \"Recipe package did not contain extras.json\"\n}\n\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\nWrite-Output \"Loaded recipe package from $extrasPath\"\n\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\n $extras.connectors = @(\n Get-Collection $extras.connectors | Where-Object {\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\n $type -ine 'Kusto'\n }\n )\n}\nelse {\n foreach ($connector in Get-Collection $extras.connectors) {\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\n if ($type -ieq 'Kusto') {\n $connector.properties.dataSource = $kustoConnectorUri\n if (-not $connector.properties.PSObject.Properties['identity']) {\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n }\n }\n}\n\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\n } | Out-Null\n Write-Output \" ARM PUT connectors/${Name}: ok\"\n}\n\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\n $uri = \"$agentEndpoint$Path\"\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\n }\n}\n\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\n $encodedName = [Uri]::EscapeDataString($Name)\n $body = @{\n name = $Name\n type = $Type\n tags = @()\n properties = $Properties\n }\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\n Write-Output \" PUT $Kind/${Name}: ok\"\n}\n\nWrite-Output 'Step 1/7: Applying connectors...'\nforeach ($connector in Get-Collection $extras.connectors) {\n $name = [string]$connector.name\n $properties = $connector.properties\n if (-not $properties.PSObject.Properties['identity']) {\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\n}\n\nWrite-Output 'Step 2/7: Configuring built-in tools...'\n$overrides = Get-Collection $extras.builtInTools.overrides\nif ($overrides.Count -gt 0) {\n $body = @{\n overrides = @($overrides | ForEach-Object {\n @{\n name = $_.name\n enabled = [bool]$_.enabled\n }\n })\n }\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\n}\n\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\nforeach ($item in Get-Collection $extras.knowledgeItems) {\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\n $body = @{\n properties = @{\n dataConnectorType = 'KnowledgeFile'\n dataSource = $sourceName\n extendedProperties = @{\n displayName = [string]$item.name\n fileName = [string]$item.name\n fileContent = [Convert]::ToBase64String($bytes)\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\n }\n }\n }\n Invoke-ArmPutConnector -Name $sourceName -Body $body\n Start-Sleep -Seconds 5\n}\n\nWrite-Output 'Step 4/7: Applying tools...'\nforeach ($tool in Get-Collection $extras.tools) {\n $name = [string]$tool.metadata.name\n $properties = $tool.spec\n if ($properties.type -eq 'PythonTool') {\n $properties.type = 'PythonFunctionTool'\n }\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\n}\n\nWrite-Output 'Step 5/7: Applying skills...'\nforeach ($skill in Get-Collection $extras.skills) {\n $name = [string]$skill.metadata.name\n $tools = @()\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\n $tools = Get-Collection $skill.metadata.spec.tools\n }\n $properties = @{\n name = $name\n description = [string](Get-PropertyValue $skill.metadata @('description'))\n tools = $tools\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\n additionalFiles = @()\n }\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\n}\n\nWrite-Output 'Step 6/7: Applying subagents...'\nforeach ($subagent in Get-Collection $extras.subagents) {\n $name = [string]$subagent.metadata.name\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\n}\n\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\n$scheduledTasks = Get-Collection $extras.scheduledTasks\nif ($scheduledTasks.Count -gt 0) {\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\n if ($match.id) {\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\n Write-Output \" deleted existing scheduledtasks/$name\"\n }\n }\n }\n\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n $spec = $task.spec\n $properties = @{\n name = [string](Get-PropertyValue $spec @('name') $name)\n description = [string](Get-PropertyValue $spec @('description'))\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\n agent = [string](Get-PropertyValue $spec @('agent'))\n }\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\n }\n}\n\nWrite-Output 'SRE Agent extras complete.'\n", + "identityName": "[format('id-sre-apply-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "scriptName": "[format('apply-sre-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('scriptName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AzurePowerShell", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')))]": {} + } + }, + "properties": { + "azPowerShellVersion": "11.0", + "retentionInterval": "PT1H", + "cleanupPreference": "OnSuccess", + "timeout": "PT2H", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "scriptContent": "[variables('$fxv#0')]", + "environmentVariables": [ + { + "name": "subscriptionId", + "value": "[parameters('subscriptionId')]" + }, + { + "name": "resourceGroupName", + "value": "[resourceGroup().name]" + }, + { + "name": "agentName", + "value": "[parameters('agentName')]" + }, + { + "name": "agentEndpoint", + "value": "[parameters('agentEndpoint')]" + }, + { + "name": "recipePackageUri", + "value": "[parameters('recipePackageUri')]" + }, + { + "name": "kustoConnectorUri", + "value": "[parameters('kustoConnectorUri')]" + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]", + "[extensionResourceId(resourceId('Microsoft.App/agents', parameters('agentName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId')))]" + ] + } + ], + "outputs": { + "identityName": { + "type": "string", + "value": "[variables('identityName')]" + }, + "scriptName": { + "type": "string", + "value": "[variables('scriptName')]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "targetRbac" + ] + } + ], + "outputs": { + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[parameters('resourceGroupName')]" + }, + "AZURE_LOCATION": { + "type": "string", + "value": "[parameters('location')]" + }, + "SRE_AGENT_NAME": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentName.value]" + }, + "SRE_AGENT_ENDPOINT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "AGENT_PORTAL_URL": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "SYSTEM_MANAGED_IDENTITY_TENANT_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentTenantId.value]" + }, + "LOG_ANALYTICS_WORKSPACE_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + }, + "APPLY_EXTRAS_SCRIPT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'apply-extras'), '2025-04-01').outputs.scriptName.value]" + } + } +} \ No newline at end of file diff --git a/docs/deploy/sre-agent/14.0/createUiDefinition.json b/docs/deploy/sre-agent/14.0/createUiDefinition.json new file mode 100644 index 000000000..87e82bcaa --- /dev/null +++ b/docs/deploy/sre-agent/14.0/createUiDefinition.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "basics": { + "description": "Deploy Azure SRE Agent with the FinOps toolkit recipe for FinOps hub analysis, capacity monitoring, scheduled tasks, and specialist agents.", + "location": { + "label": "Location", + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ] + } + } + }, + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ], + "basics": [ + { + "name": "resourceGroupName", + "type": "Microsoft.Common.TextBox", + "label": "Agent resource group", + "defaultValue": "finops-hub-sre", + "toolTip": "Resource group that will contain the Azure SRE Agent, monitoring resources, and deployment script identity.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9._()\\-]{1,90}$", + "validationMessage": "Enter a valid Azure resource group name." + }, + "visible": true + }, + { + "name": "agentName", + "type": "Microsoft.Common.TextBox", + "label": "Agent name", + "defaultValue": "finops-hub-sre", + "toolTip": "Name of the Azure SRE Agent resource.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,61}[a-zA-Z0-9]$", + "validationMessage": "Name must be 3-63 characters and can contain letters, numbers, and hyphens. The first and last characters must be alphanumeric." + }, + "visible": true + } + ], + "steps": [ + { + "name": "configuration", + "label": "Configuration", + "elements": [ + { + "name": "finopsHubKustoConnectorUri", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto URI", + "defaultValue": "", + "toolTip": "Optional database-qualified Azure Data Explorer URI for the FinOps hub. Example: https://cluster.region.kusto.windows.net/Hub", + "constraints": { + "required": false, + "regex": "^$|^https://.+\\.kusto\\.windows\\.net/.+", + "validationMessage": "Enter a database-qualified Kusto URI such as https://cluster.region.kusto.windows.net/Hub, or leave blank." + }, + "visible": true + }, + { + "name": "finopsHubKustoClusterResourceId", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto cluster resource ID", + "defaultValue": "", + "toolTip": "Optional Azure Data Explorer cluster resource ID. Provide this to assign the agent managed identity AllDatabasesViewer on the cluster.", + "constraints": { + "required": false, + "regex": "^$|^/subscriptions/.+/resourceGroups/.+/providers/Microsoft\\.Kusto/clusters/.+", + "validationMessage": "Enter a valid Microsoft.Kusto/clusters resource ID, or leave blank." + }, + "visible": true + }, + { + "name": "targetResourceGroups", + "type": "Microsoft.Common.TextBox", + "label": "Additional target resource groups", + "defaultValue": "", + "toolTip": "Optional comma-separated resource group names the agent can observe or act on. The agent resource group is always included.", + "constraints": { + "required": false, + "regex": "^$|^[A-Za-z0-9_.()\\-]+(\\s*,\\s*[A-Za-z0-9_.()\\-]+)*$", + "validationMessage": "Enter a comma-separated list of resource group names without blank entries or trailing commas." + }, + "visible": true + }, + { + "name": "accessLevel", + "type": "Microsoft.Common.OptionsGroup", + "label": "Access level", + "defaultValue": "High", + "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "constraints": { + "allowedValues": [ + { + "label": "High", + "value": "High" + }, + { + "label": "Low", + "value": "Low" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "actionMode", + "type": "Microsoft.Common.OptionsGroup", + "label": "Action mode", + "defaultValue": "autonomous", + "toolTip": "Review requires approval before write actions. Autonomous lets the agent run enabled actions within its assigned access.", + "constraints": { + "allowedValues": [ + { + "label": "Autonomous", + "value": "autonomous" + }, + { + "label": "Review", + "value": "review" + }, + { + "label": "Read only", + "value": "readOnly" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "enableSubscriptionReaderRole", + "type": "Microsoft.Common.CheckBox", + "label": "Grant subscription Reader to the agent", + "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", + "defaultValue": true, + "visible": true + } + ] + } + ], + "outputs": { + "resourceGroupName": "[basics('resourceGroupName')]", + "agentName": "[basics('agentName')]", + "location": "[location()]", + "targetResourceGroupNames": "[steps('configuration').targetResourceGroups]", + "finopsHubKustoConnectorUri": "[steps('configuration').finopsHubKustoConnectorUri]", + "finopsHubKustoClusterResourceId": "[steps('configuration').finopsHubKustoClusterResourceId]", + "accessLevel": "[steps('configuration').accessLevel]", + "actionMode": "[steps('configuration').actionMode]", + "enableSubscriptionReaderRole": "[steps('configuration').enableSubscriptionReaderRole]" + } + } +} diff --git a/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip b/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip new file mode 100644 index 0000000000000000000000000000000000000000..159ae7454137f5096b46f48672aeefb4b3f4c11f GIT binary patch literal 346636 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%0A)e)d3rs&)|sg|KHplPj~#pU_9+m5qE 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 z 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%0D6D`-ZdASrQP9OimVrY6mqmXI2owz@k-Eo#;# zn03z$MGL%}xoN4r#kD&o?ARbJOcm6l*Yyv%Pi3QoYdGurPYU_*V2V2!Z|poUCi-Gj!oZZ=xoA zsFgY8BHDsDHvzurS7>@ysuL4AUa6NxWG!2ZnF_XbtWc@;HLt2|X+s37T&?n&Bcu;T zmYRM9=qpo``5gA^QqvC+y$v;7V#|)SAJFqJ!Bh>%eoIsVxt8gPSFLxYn#D^ysIg5p zEz}k9Z`OfFUzM7Ug}O2|{Rq+<<(p+p(@og6Le%K(bxi@a1i0l5gaWmw*`#cCQzH?p zH{dX9coH4{^fuJE+%m?rzB%uF2aNUAskyPZtqvsYt5dV9k992?PYZy$rQLCZ$kDJH zDo-mTyMu47EKp$8NA3 z+kTse`@aw30fv*az`@nJbOs>`2?}gZ_cGPc7Unt#JFanQc;L>{a^VojZ4E z@m$Q#_6ae&CBtl=>ats!%l1huyCtw}AB4PH0CM0CzaC@~WPvRpU4n74aavFM@ql}P zFcW!9=}Kies$>S}>-K@I4foX*gIc!_65TC8bo=nn-9kUN5A576sB`;}&E3K^Lsw?M z%-iS2oW#=anm1ZIPUJgXJB~=dYx!GbaBfwDvj+NODrTFmhRb|er-Fe`#(7t14~F}$ za≺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 z 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 aZcs}F1^@s6009620672v0KG{C0002qu>Iu# literal 0 HcmV?d00001 diff --git a/src/scripts/Build-SreAgentTemplate.ps1 b/src/scripts/Build-SreAgentTemplate.ps1 new file mode 100644 index 000000000..8c2c2a5e2 --- /dev/null +++ b/src/scripts/Build-SreAgentTemplate.ps1 @@ -0,0 +1,47 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +<# + .SYNOPSIS + Builds the SRE Agent recipe package used by the portal deployment template. + + .PARAMETER DestDir + Release directory for the copied sre-agent template. +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)][string]$DestDir +) + +$templateRoot = Resolve-Path "$PSScriptRoot/../templates/sre-agent" +$recipeDir = Join-Path $templateRoot "recipes/finops-hub" +$builder = Join-Path $templateRoot "bin/build-extras.py" +$assetsDir = Join-Path $DestDir "assets" +$workDir = Join-Path $assetsDir "sre-agent-recipe" +$extrasPath = Join-Path $workDir "extras.json" +$packagePath = Join-Path $assetsDir "sre-agent-recipe.zip" +$placeholderKustoUri = "https://placeholder.eastus2.kusto.windows.net/Hub" + +if (-not (Get-Command python3 -ErrorAction SilentlyContinue)) +{ + throw "python3 is required to build the SRE Agent recipe package." +} + +& "$PSScriptRoot/New-Directory.ps1" $assetsDir +Remove-Item $workDir -Recurse -Force -ErrorAction SilentlyContinue +& "$PSScriptRoot/New-Directory.ps1" $workDir + +Write-Host " Building SRE Agent recipe package..." +$summary = python3 $builder --recipe $recipeDir --output $extrasPath --kusto-connector-uri $placeholderKustoUri +if (-not $?) +{ + throw "Failed to build SRE Agent extras manifest." +} + +Write-Verbose " SRE Agent extras summary: $summary" +Remove-Item $packagePath -Force -ErrorAction SilentlyContinue +Compress-Archive -Path "$workDir/*" -DestinationPath $packagePath -Force +Remove-Item $workDir -Recurse -Force + +Write-Host " Created assets/sre-agent-recipe.zip" diff --git a/src/scripts/Build-Toolkit.ps1 b/src/scripts/Build-Toolkit.ps1 index cfa992eb6..dfd7e336e 100644 --- a/src/scripts/Build-Toolkit.ps1 +++ b/src/scripts/Build-Toolkit.ps1 @@ -193,17 +193,15 @@ $templates | ForEach-Object { # Create target directory $destDir = "$outdir/$templateName" Write-Verbose " Creating target directory: $destDir" - Remove-Item $destDir -Recurse -ErrorAction SilentlyContinue + Remove-Item $destDir -Recurse -Force -ErrorAction SilentlyContinue & "$PSScriptRoot/New-Directory.ps1" $destDir # Copy required files Write-Host " Copying files..." - $sourceFiles = Get-ChildItem $srcDir -Force | Where-Object { $_.Name -notin @(".build.config", ".buildignore", "scaffold.json") } + $sourceFiles = Get-ChildItem $srcDir | Where-Object { $_.Name -notin @(".build.config", ".buildignore", "scaffold.json") } Write-Verbose " Copying $($sourceFiles.Count) items from source to destination" $sourceFiles | Copy-Item -Destination $destDir -Recurse - Get-ChildItem $destDir -Force -Recurse -Filter ".DS_Store" | Remove-Item -Force - # Run custom build scripts after copying files (operates on release copy, not source) if ($buildConfig.scripts.Count -gt 0) { diff --git a/src/templates/sre-agent/.build.config b/src/templates/sre-agent/.build.config new file mode 100644 index 000000000..ac067ed9b --- /dev/null +++ b/src/templates/sre-agent/.build.config @@ -0,0 +1,9 @@ +{ + "scripts": [ + "Build-SreAgentTemplate.ps1" + ], + "ignore": [ + "bin/__pycache__", + "submodules" + ] +} diff --git a/src/templates/sre-agent/bin/apply-extras.sh b/src/templates/sre-agent/bin/apply-extras.sh new file mode 100755 index 000000000..c90365b0c --- /dev/null +++ b/src/templates/sre-agent/bin/apply-extras.sh @@ -0,0 +1,581 @@ +#!/usr/bin/env bash +# ============================================================================= +# apply-extras.sh - Apply non-Bicep SRE Agent recipe assets +# +# Follows the microsoft/sre-agent template pattern: Bicep deploys the ARM +# resource, then this script applies connectors, KnowledgeFile sources, skills, +# subagents, tools, and scheduled tasks through the supported ARM/data-plane +# surfaces. +# ============================================================================= + +set -euo pipefail + +usage() { + cat < --subscription --resource-group --name --recipe

--build-dir [options] + +Required: + --endpoint SRE Agent endpoint + --subscription Azure subscription that contains the SRE Agent + --resource-group Resource group that contains the SRE Agent + --name SRE Agent name + --recipe Recipe directory + --build-dir Working directory for generated extras and request files + +Optional: + --kusto-connector-uri Database-qualified Kusto connector URI + --dry-run Build extras and request payloads without Azure calls + -h, --help Show this help +EOF + exit "${1:-0}" +} + +fail() { + echo "$1" >&2 + exit "${2:-1}" +} + +require_value() { + local flag="$1" + local value="${2:-}" + if [[ -z "$value" || "$value" == -* ]]; then + fail "Error: flag ${flag} requires a value" 2 + fi +} + +safe_name() { + printf '%s' "$1" | tr '/:' '__' | tr -cd 'A-Za-z0-9._-' +} + +urlencode() { + printf '%s' "$1" | jq -sRr @uri +} + +knowledge_source_name() { + basename "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' +} + +get_sre_token() { + az account get-access-token --resource https://azuresre.dev --query accessToken -o tsv 2>/dev/null +} + +ENDPOINT="" +SUBSCRIPTION_ID="" +RESOURCE_GROUP="" +AGENT_NAME="" +RECIPE_DIR="" +BUILD_DIR="" +KUSTO_CONNECTOR_URI="" +DRY_RUN="" +ARM_API_VERSION="2025-05-01-preview" +REQUEST_DELAY_SECONDS="${SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS:-15}" +RETRY_DELAY_SECONDS="${SRE_AGENT_APPLY_RETRY_DELAY_SECONDS:-15}" + +while [[ $# -gt 0 ]]; do + case "$1" in + --endpoint) + require_value "--endpoint" "${2:-}" + ENDPOINT="$2" + shift 2 + ;; + --subscription) + require_value "--subscription" "${2:-}" + SUBSCRIPTION_ID="$2" + shift 2 + ;; + --resource-group) + require_value "--resource-group" "${2:-}" + RESOURCE_GROUP="$2" + shift 2 + ;; + --name) + require_value "--name" "${2:-}" + AGENT_NAME="$2" + shift 2 + ;; + --recipe) + require_value "--recipe" "${2:-}" + RECIPE_DIR="$2" + shift 2 + ;; + --build-dir) + require_value "--build-dir" "${2:-}" + BUILD_DIR="$2" + shift 2 + ;; + --kusto-connector-uri) + require_value "--kusto-connector-uri" "${2:-}" + KUSTO_CONNECTOR_URI="$2" + shift 2 + ;; + --dry-run) + DRY_RUN="true" + shift + ;; + -h|--help) + usage 0 + ;; + *) + fail "Error: unknown argument '$1'" 2 + ;; + esac +done + +[[ -n "$ENDPOINT" ]] || fail "Error: --endpoint is required" 2 +[[ -n "$SUBSCRIPTION_ID" ]] || fail "Error: --subscription is required" 2 +[[ -n "$RESOURCE_GROUP" ]] || fail "Error: --resource-group is required" 2 +[[ -n "$AGENT_NAME" ]] || fail "Error: --name is required" 2 +[[ -n "$RECIPE_DIR" ]] || fail "Error: --recipe is required" 2 +[[ -n "$BUILD_DIR" ]] || fail "Error: --build-dir is required" 2 +[[ -d "$RECIPE_DIR" ]] || fail "Error: recipe directory not found: $RECIPE_DIR" 1 + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +RECIPE_DIR="$(cd "$RECIPE_DIR" && pwd)" +mkdir -p "$BUILD_DIR" +BUILD_DIR="$(cd "$BUILD_DIR" && pwd)" +EXTRAS_FILE="${BUILD_DIR}/extras.json" +REQUEST_DIR="${BUILD_DIR}/requests" +RESPONSE_DIR="${BUILD_DIR}/responses" +ARM_BASE="https://management.azure.com/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.App/agents/${AGENT_NAME}" + +command -v jq >/dev/null || fail "jq is required" 1 +command -v base64 >/dev/null || fail "base64 is required" 1 + +PYTHON_CMD="" +if command -v python3 >/dev/null; then + PYTHON_CMD="python3" +elif command -v python >/dev/null && python --version 2>&1 | grep -q "Python 3"; then + PYTHON_CMD="python" +else + fail "Python 3 is required" 1 +fi + +"$PYTHON_CMD" -c "import yaml" 2>/dev/null || fail "PyYAML is required to build extras. Install with: pip install pyyaml" 1 + +mkdir -p "$REQUEST_DIR" "$RESPONSE_DIR" + +echo "" +echo "=============================================" +echo " SRE Agent - Apply Extras" +echo "=============================================" +echo "" +echo "Agent endpoint: $ENDPOINT" +echo "Recipe: $RECIPE_DIR" +echo "Build dir: $BUILD_DIR" +echo "" + +echo "Step 1/8: Building extras manifest..." +SUMMARY_JSON="$("$PYTHON_CMD" "${SCRIPT_DIR}/build-extras.py" \ + --recipe "$RECIPE_DIR" \ + --output "$EXTRAS_FILE" \ + --kusto-connector-uri "$KUSTO_CONNECTOR_URI")" +echo " extras: $EXTRAS_FILE" +echo " summary: $SUMMARY_JSON" +echo "" + +if [[ -z "$DRY_RUN" ]]; then + command -v az >/dev/null || fail "az is required to apply extras" 1 + command -v curl >/dev/null || fail "curl is required to apply extras" 1 + az account set --subscription "$SUBSCRIPTION_ID" >/dev/null + DP_TOKEN="$(get_sre_token)" + [[ -n "$DP_TOKEN" ]] || fail "Error: failed to get Azure SRE Agent bearer token. Run: az login --scope https://azuresre.dev/.default" 1 +else + DP_TOKEN="dry-run" + echo "Dry run enabled. Azure control-plane and data-plane calls will be skipped." + echo "" +fi + +arm_put_connector() { + local name="$1" + local body_json="$2" + local safe + local body_file + local response_file + local result + + safe="$(safe_name "$name")" + body_file="${REQUEST_DIR}/arm-connectors/${safe}.json" + response_file="${RESPONSE_DIR}/arm-connectors/${safe}.json" + mkdir -p "$(dirname "$body_file")" "$(dirname "$response_file")" + printf '%s\n' "$body_json" > "$body_file" + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run ARM PUT connectors/${name} -> $body_file" + return 0 + fi + + for attempt in 1 2 3 4 5; do + if result="$(az rest -m PUT \ + --url "${ARM_BASE}/connectors/${name}?api-version=${ARM_API_VERSION}" \ + --body "@${body_file}" \ + --headers "Content-Type=application/json" \ + -o json 2>&1)"; then + printf '%s\n' "$result" > "$response_file" + echo " ARM PUT connectors/${name}: ok" + return 0 + fi + + printf '%s\n' "$result" > "$response_file" + echo " ARM PUT connectors/${name}: attempt ${attempt}/5 failed" + [[ "$attempt" != "5" ]] && sleep "$RETRY_DELAY_SECONDS" + done + + sed -n '1,120p' "$response_file" >&2 || true + fail "Failed to apply connector ${name}" 1 +} + +dataplane_put_extended() { + local kind="$1" + local name="$2" + local type="$3" + local tags_json="$4" + local props_json="$5" + local safe + local body_file + local response_file + local body + local http_code + local encoded_name + + safe="$(safe_name "$name")" + body_file="${REQUEST_DIR}/dataplane-${kind}/${safe}.json" + response_file="${RESPONSE_DIR}/dataplane-${kind}/${safe}.json" + mkdir -p "$(dirname "$body_file")" "$(dirname "$response_file")" + body="$(jq -nc --arg name "$name" --arg type "$type" --argjson tags "$tags_json" --argjson properties "$props_json" \ + '{name: $name, type: $type, tags: $tags, properties: $properties}')" + printf '%s\n' "$body" > "$body_file" + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run PUT ${kind}/${name} -> $body_file" + return 0 + fi + + encoded_name="$(urlencode "$name")" + for attempt in 1 2 3 4 5; do + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + -X PUT "${ENDPOINT}/api/v2/extendedAgent/${kind}/${encoded_name}" \ + -H "Authorization: Bearer ${DP_TOKEN}" \ + -H "Content-Type: application/json" \ + --data-binary "@${body_file}")"; then + : + else + http_code="000" + fi + + case "$http_code" in + 200|201|202|204) + echo " PUT ${kind}/${name}: ok" + return 0 + ;; + esac + + echo " PUT ${kind}/${name}: attempt ${attempt}/5 returned HTTP ${http_code}" + [[ "$attempt" != "5" ]] && sleep "$RETRY_DELAY_SECONDS" + done + + sed -n '1,120p' "$response_file" >&2 || true + fail "Failed to apply ${kind}/${name}" 1 +} + +apply_built_in_tools_config() { + local config_json + local override_count + local body_file="${REQUEST_DIR}/built-in-tools/configure.json" + local response_file="${RESPONSE_DIR}/built-in-tools/configure.json" + local http_code + + config_json="$(jq -c '.builtInTools // {"overrides":[]}' "$EXTRAS_FILE")" + override_count="$(jq -r '.overrides | length' <<< "$config_json")" + [[ "$override_count" != "0" ]] || { + echo " built-in tools: no overrides" + return 0 + } + + mkdir -p "$(dirname "$body_file")" "$(dirname "$response_file")" + jq '{overrides: [.overrides[] | {name, enabled}]}' <<< "$config_json" > "$body_file" + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run POST agent/tools/configure -> $body_file" + return 0 + fi + + for attempt in 1 2 3 4 5; do + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + -X POST "${ENDPOINT}/api/v2/agent/tools/configure" \ + -H "Authorization: Bearer ${DP_TOKEN}" \ + -H "Content-Type: application/json" \ + --data-binary "@${body_file}")"; then + : + else + http_code="000" + fi + + case "$http_code" in + 200|201|202|204) + echo " built-in tools configured: ${override_count} overrides" + return 0 + ;; + esac + + echo " built-in tools: attempt ${attempt}/5 returned HTTP ${http_code}" + [[ "$attempt" != "5" ]] && sleep "$RETRY_DELAY_SECONDS" + done + + sed -n '1,120p' "$response_file" >&2 || true + fail "Failed to configure built-in tools" 1 +} + +delete_existing_scheduled_tasks() { + local count + local response_file="${RESPONSE_DIR}/scheduledtasks.existing.json" + local name + local ids + local id + local http_code + local deleted=0 + + count="$(jq '.scheduledTasks // [] | length' "$EXTRAS_FILE")" + [[ "$count" -gt 0 ]] || return 0 + + if [[ -n "$DRY_RUN" ]]; then + echo " dry-run scheduled-task cleanup: ${count} task name(s)" + return 0 + fi + + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + "${ENDPOINT}/api/v1/scheduledtasks" \ + -H "Authorization: Bearer ${DP_TOKEN}")"; then + : + else + http_code="000" + fi + [[ "$http_code" == "200" ]] || fail "Failed to list existing scheduled tasks before apply (HTTP ${http_code})" 1 + + for i in $(seq 0 $((count - 1))); do + name="$(jq -r --argjson index "$i" '.scheduledTasks[$index].metadata.name' "$EXTRAS_FILE")" + ids="$(jq -r --arg name "$name" '.[]? | select(.name == $name) | .id // empty' "$response_file" 2>/dev/null || true)" + while IFS= read -r id; do + [[ -n "$id" ]] || continue + if curl -sS -o /dev/null -X DELETE "${ENDPOINT}/api/v1/scheduledtasks/${id}" -H "Authorization: Bearer ${DP_TOKEN}"; then + echo " deleted existing scheduled-task ${name} (${id})" + deleted=$((deleted + 1)) + else + fail "Failed to delete existing scheduled-task ${name} (${id})" 1 + fi + done <<< "$ids" + done + + [[ "$deleted" -eq 0 ]] || echo " scheduled-task cleanup: ${deleted} existing deleted" +} + +verify_knowledge_docs() { + local expected_docs=("$@") + local response_file="${RESPONSE_DIR}/knowledge-sources/list.json" + local detail_file + local doc + local source_name + local entry + local indexed + local reason + local missing + local unindexed + local http_code + + [[ "${#expected_docs[@]}" -gt 0 ]] || return 0 + [[ -z "$DRY_RUN" ]] || { + echo " dry-run knowledge verification skipped" + return 0 + } + + mkdir -p "$(dirname "$response_file")" + echo " waiting for knowledge sources to index..." + for attempt in $(seq 1 20); do + if http_code="$(curl -sS -o "$response_file" -w "%{http_code}" \ + "${ENDPOINT}/api/v2/extendedAgent/connectors" \ + -H "Authorization: Bearer ${DP_TOKEN}")"; then + : + else + http_code="000" + fi + + missing=0 + unindexed=0 + if [[ "$http_code" == "200" ]]; then + for doc in "${expected_docs[@]}"; do + source_name="$(knowledge_source_name "$doc")" + entry="$(jq -c --arg name "$source_name" '[.value[]? | select(.name == $name and .properties.dataConnectorType == "KnowledgeFile")][0] // empty' "$response_file" 2>/dev/null || true)" + if [[ -z "$entry" ]]; then + missing=$((missing + 1)) + continue + fi + + detail_file="${RESPONSE_DIR}/knowledge-sources/${source_name}.json" + if http_code="$(curl -sS -o "$detail_file" -w "%{http_code}" \ + "${ENDPOINT}/api/v2/extendedAgent/connectors/${source_name}" \ + -H "Authorization: Bearer ${DP_TOKEN}")"; then + : + else + http_code="000" + fi + + indexed="$(jq -r '.properties.extendedProperties.createdAt // empty' "$detail_file" 2>/dev/null || true)" + [[ -n "$indexed" ]] || unindexed=$((unindexed + 1)) + done + + if [[ "$missing" -eq 0 && "$unindexed" -eq 0 ]]; then + echo " knowledge sources indexed: ${#expected_docs[@]} docs" + return 0 + fi + + echo " knowledge indexing attempt ${attempt}/20: ${missing} missing, ${unindexed} not indexed" + else + echo " knowledge indexing attempt ${attempt}/20: connectors returned HTTP ${http_code}" + fi + + [[ "$attempt" -lt 20 ]] && sleep "$RETRY_DELAY_SECONDS" + done + + echo " knowledge source status:" >&2 + for doc in "${expected_docs[@]}"; do + source_name="$(knowledge_source_name "$doc")" + detail_file="${RESPONSE_DIR}/knowledge-sources/${source_name}.json" + entry="$(jq -c --arg name "$source_name" '[.value[]? | select(.name == $name and .properties.dataConnectorType == "KnowledgeFile")][0] // empty' "$response_file" 2>/dev/null || true)" + if [[ -z "$entry" ]]; then + echo " ${doc}: missing" >&2 + else + indexed="$(jq -r '.properties.extendedProperties.createdAt // empty' "$detail_file" 2>/dev/null || true)" + reason="$(jq -r '.properties.extendedProperties.errorReason // ""' "$detail_file" 2>/dev/null || true)" + echo " ${doc}: indexed=${indexed}${reason:+ reason=${reason}}" >&2 + fi + done + fail "Knowledge sources failed to index" 1 +} + +echo "Step 2/8: Applying connectors..." +CONNECTOR_COUNT="$(jq '.connectors // [] | length' "$EXTRAS_FILE")" +if [[ "$CONNECTOR_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((CONNECTOR_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.connectors[$index].name' "$EXTRAS_FILE")" + connector_type="$(jq -r --argjson index "$i" '.connectors[$index].properties.dataConnectorType // .connectors[$index].properties.type // ""' "$EXTRAS_FILE")" + connector_type_lower="$(printf '%s' "$connector_type" | tr '[:upper:]' '[:lower:]')" + if [[ "$connector_type_lower" == "mcp" ]]; then + jq -e --argjson index "$i" '.connectors[$index].properties.extendedProperties.type == "http" and (.connectors[$index].properties.extendedProperties.endpoint // "") != ""' "$EXTRAS_FILE" >/dev/null \ + || fail "Error: MCP connector ${name} must use properties.extendedProperties.type and endpoint" 1 + jq -e --argjson index "$i" '(.connectors[$index].properties.extendedProperties.headers? | type) != "object"' "$EXTRAS_FILE" >/dev/null \ + || fail "Error: MCP connector ${name} must flatten custom headers into properties.extendedProperties" 1 + fi + body="$(jq -c --argjson index "$i" '{properties: (.connectors[$index].properties | if (.identity // "") == "" then . + {identity: "system"} else . end)}' "$EXTRAS_FILE")" + arm_put_connector "$name" "$body" + done +else + echo " connectors: none" +fi +echo "" + +echo "Step 3/8: Configuring built-in tools..." +apply_built_in_tools_config +echo "" + +echo "Step 4/8: Uploading knowledge sources..." +KNOWLEDGE_COUNT="$(jq '.knowledgeItems // [] | length' "$EXTRAS_FILE")" +KNOWLEDGE_DOC_NAMES=() +if [[ "$KNOWLEDGE_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((KNOWLEDGE_COUNT - 1))); do + fname="$(jq -r --argjson index "$i" '.knowledgeItems[$index].name' "$EXTRAS_FILE")" + content_type="$(jq -r --argjson index "$i" '.knowledgeItems[$index].contentType // "application/octet-stream"' "$EXTRAS_FILE")" + source_name="$(knowledge_source_name "$fname")" + content_b64="$(jq -rj --argjson index "$i" '.knowledgeItems[$index].content' "$EXTRAS_FILE" | base64 | tr -d '\n')" + KNOWLEDGE_DOC_NAMES+=("$fname") + body="$(jq -nc \ + --arg dataSource "$source_name" \ + --arg displayName "$fname" \ + --arg fileName "$fname" \ + --arg fileContent "$content_b64" \ + --arg contentType "$content_type" \ + '{properties:{dataConnectorType:"KnowledgeFile",dataSource:$dataSource,extendedProperties:{displayName:$displayName,fileName:$fileName,fileContent:$fileContent,contentType:$contentType}}}')" + arm_put_connector "$source_name" "$body" + [[ -z "$DRY_RUN" && "$i" -lt $((KNOWLEDGE_COUNT - 1)) ]] && sleep "$REQUEST_DELAY_SECONDS" + done + verify_knowledge_docs "${KNOWLEDGE_DOC_NAMES[@]}" +else + echo " knowledge sources: none" +fi +echo "" + +echo "Step 5/8: Applying tools..." +TOOL_COUNT="$(jq '.tools // [] | length' "$EXTRAS_FILE")" +if [[ "$TOOL_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((TOOL_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.tools[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" ' + .tools[$index].spec + | if (.type // "") == "PythonTool" then .type = "PythonFunctionTool" else . end + ' "$EXTRAS_FILE")" + dataplane_put_extended "tools" "$name" "ExtendedAgentTool" "[]" "$props" + done +else + echo " tools: none" +fi +echo "" + +echo "Step 6/8: Applying skills..." +SKILL_COUNT="$(jq '.skills // [] | length' "$EXTRAS_FILE")" +if [[ "$SKILL_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((SKILL_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.skills[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" ' + { + name: .skills[$index].metadata.name, + description: (.skills[$index].metadata.description // ""), + tools: (.skills[$index].metadata.spec.tools // []), + skillContent: (.skills[$index].skillContent // ""), + additionalFiles: [] + }' "$EXTRAS_FILE")" + dataplane_put_extended "skills" "$name" "Skill" "[]" "$props" + done +else + echo " skills: none" +fi +echo "" + +echo "Step 7/8: Applying subagents..." +SUBAGENT_COUNT="$(jq '.subagents // [] | length' "$EXTRAS_FILE")" +if [[ "$SUBAGENT_COUNT" -gt 0 ]]; then + for i in $(seq 0 $((SUBAGENT_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.subagents[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" '.subagents[$index].spec' "$EXTRAS_FILE")" + dataplane_put_extended "agents" "$name" "ExtendedAgent" "[]" "$props" + done +else + echo " subagents: none" +fi +echo "" + +echo "Step 8/8: Applying scheduled tasks..." +TASK_COUNT="$(jq '.scheduledTasks // [] | length' "$EXTRAS_FILE")" +if [[ "$TASK_COUNT" -gt 0 ]]; then + delete_existing_scheduled_tasks + for i in $(seq 0 $((TASK_COUNT - 1))); do + name="$(jq -r --argjson index "$i" '.scheduledTasks[$index].metadata.name' "$EXTRAS_FILE")" + props="$(jq -c --argjson index "$i" ' + .scheduledTasks[$index].spec as $spec | + { + name: ($spec.name // .scheduledTasks[$index].metadata.name // ""), + description: ($spec.description // ""), + cronExpression: ($spec.schedule // $spec.cronExpression // $spec.cron_expression // ""), + agentPrompt: ($spec.prompt // $spec.agentPrompt // $spec.agent_prompt // ""), + agentMode: ($spec.mode // $spec.agentMode // $spec.agent_mode // "Review"), + isEnabled: ($spec.enabled // true), + agent: ($spec.agent // "") + }' "$EXTRAS_FILE")" + dataplane_put_extended "scheduledtasks" "$name" "ScheduledTask" "[]" "$props" + done +else + echo " scheduled tasks: none" +fi +echo "" + +echo "=============================================" +echo " SRE Agent extras complete" +echo "=============================================" +echo "" diff --git a/src/templates/sre-agent/bin/check-prerequisites.sh b/src/templates/sre-agent/bin/check-prerequisites.sh new file mode 100755 index 000000000..2dd6b2566 --- /dev/null +++ b/src/templates/sre-agent/bin/check-prerequisites.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# check-prerequisites.sh — verify required tools are installed + +usage() { + cat <] + +Options: + --subscription Subscription to scope Azure CLI checks + -h, --help Show this help +EOF + exit "${1:-0}" +} + +check_prerequisites() { + local missing=0 + + for cmd in az curl git jq; do + if ! command -v "$cmd" &>/dev/null; then + echo " ❌ Missing: $cmd" >&2 + missing=$((missing + 1)) + fi + done + + if ! command -v python3 &>/dev/null && ! command -v python &>/dev/null; then + echo " ❌ Missing: python3 (needed for YAML processing)" >&2 + missing=$((missing + 1)) + else + local py=$(command -v python3 || command -v python) + if ! "$py" -c "import yaml" 2>/dev/null; then + echo " ❌ Missing: PyYAML — install: pip install pyyaml" >&2 + missing=$((missing + 1)) + fi + fi + + if [[ $missing -gt 0 ]]; then + echo " $missing prerequisite(s) missing. See README for install guide." >&2 + return 1 + fi + return 0 +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + SUBSCRIPTION_ID="" + while [[ $# -gt 0 ]]; do + case "$1" in + --subscription) + [[ -n "${2:-}" && "${2:-}" != -* ]] || { echo "Error: flag --subscription requires a value" >&2; exit 2; } + SUBSCRIPTION_ID="$2" + shift 2 + ;; + -h|--help) + usage 0 + ;; + *) + echo "Error: unexpected argument '$1'" >&2 + usage 2 + ;; + esac + done + + if [[ -n "$SUBSCRIPTION_ID" ]]; then + export AZURE_SUBSCRIPTION_ID="$SUBSCRIPTION_ID" + fi + + check_prerequisites +fi diff --git a/src/templates/sre-agent/bin/deploy.sh b/src/templates/sre-agent/bin/deploy.sh new file mode 100755 index 000000000..3b9a5f53c --- /dev/null +++ b/src/templates/sre-agent/bin/deploy.sh @@ -0,0 +1,558 @@ +#!/usr/bin/env bash +# ============================================================================= +# deploy.sh - FinOps Toolkit SRE Agent setup +# +# Copied from microsoft/sre-agent labs/starter-lab/scripts/setup.sh and updated +# for this template: +# - uses Azure CLI + Bicep directly, not azd +# - deploys the FinOps SRE Agent infrastructure only, not the Grubify lab app +# - applies non-Bicep recipe assets with apply-extras after ARM succeeds +# ============================================================================= + +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +INFRA_DIR="${PROJECT_DIR}/infra" + +usage() { + cat < [options] + +Required: + --recipe Recipe directory + --subscription Azure subscription + -g, --resource-group Resource group for the agent + -n, --name Agent name + -l, --location Azure region + +Optional: + --target-resource-group Repeatable target resource group. The agent resource group is always included. + --cluster-uri Kusto connector URI, including database name. + Example: https://..kusto.windows.net/Hub + --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. + --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deploy-name Deployment name override. Defaults to a deterministic name. + --dry-run Validate inputs and write parameters without Azure calls. + --force Accepted for compatibility. + --no-telemetry Accepted for compatibility. + -h, --help Show this help. +EOF + exit "${1:-0}" +} + +fail() { + echo -e "${RED}$1${NC}" >&2 + exit "${2:-1}" +} + +require_value() { + local flag="$1" + local value="${2:-}" + if [[ -z "$value" || "$value" == -* ]]; then + fail "Error: flag ${flag} requires a value" 2 + fi +} + +recipe_value() { + local file="$1" + local path="$2" + jq -r "$path // empty | if . == null or . == \"null\" then \"\" else . end" "$file" +} + +deterministic_deploy_name() { + "$PYTHON_CMD" - "$SUBSCRIPTION_ID" "$RESOURCE_GROUP" "$AGENT_NAME" <<'PY' +import hashlib +import re +import sys + +subscription_id, resource_group, agent_name = sys.argv[1:4] +resource_group_id = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group}" +seed = f"{subscription_id}|{resource_group_id}|{agent_name}".lower() +slug = re.sub(r"[^a-z0-9-]+", "-", agent_name.lower()).strip("-") or "agent" +digest = hashlib.sha256(seed.encode("utf-8")).hexdigest()[:12] +name = f"sre-agent-{slug}-{digest}" +print(name[:64].rstrip("-")) +PY +} + +deployment_output_value() { + local file="$1" + local key="$2" + local default="${3:-}" + jq -r \ + --arg key "$key" \ + --arg default "$default" \ + '(.properties.outputs // {}) + | to_entries + | map(select((.key | ascii_upcase) == ($key | ascii_upcase)) | .value.value) + | first // $default' \ + "$file" +} + +normalize_action_mode() { + case "$1" in + Autonomous|autonomous|Automatic|automatic) printf 'autonomous' ;; + Review|review) printf 'review' ;; + ReadOnly|readOnly|readonly) printf 'readOnly' ;; + *) fail "Error: unsupported action mode '$1'" 2 ;; + esac +} + +validate_kusto_uri() { + local uri="$1" + [[ -z "$uri" ]] && return 0 + if [[ "$uri" != https://*.kusto.windows.net/* ]]; then + fail "Error: --cluster-uri must be a database-qualified Kusto URI. Example: https://..kusto.windows.net/Hub" 2 + fi + local path="${uri#https://}" + if [[ "$path" != */* || -z "${path#*/}" ]]; then + fail "Error: --cluster-uri must include the Kusto database name. Example: https://..kusto.windows.net/Hub" 2 + fi +} + +parse_kusto_cluster_name() { + local uri="$1" + local host + host="${uri#https://}" + host="${host%%/*}" + printf '%s\n' "${host%%.*}" +} + +parse_kusto_database_name() { + local uri="$1" + local path + path="${uri#https://}" + path="${path#*/}" + path="${path%%\?*}" + path="${path%%#*}" + printf '%s\n' "${path%%/*}" +} + +to_lower() { + printf '%s\n' "$1" | tr '[:upper:]' '[:lower:]' +} + +append_target_rg() { + local rg="$1" + local existing + [[ -n "$rg" ]] || return 0 + if [[ "${#TARGET_RGS[@]}" -gt 0 ]]; then + for existing in "${TARGET_RGS[@]}"; do + if [[ "$(to_lower "$existing")" == "$(to_lower "$rg")" ]]; then + return 0 + fi + done + fi + TARGET_RGS+=("$rg") +} + +resource_id_subscription() { + local resource_id="$1" + printf '%s\n' "$resource_id" | awk -F/ '{print $3}' +} + +resource_id_resource_group() { + local resource_id="$1" + printf '%s\n' "$resource_id" | awk -F/ '{print $5}' +} + +resolve_kusto_cluster_resource_id() { + local uri="$1" + local cluster_name + local cluster_uri + local resource_id + local graph_result_count + + cluster_name="$(parse_kusto_cluster_name "$uri")" + [[ -n "$cluster_name" ]] || fail "Error: could not parse Kusto cluster name from --cluster-uri" 2 + cluster_uri="${uri%/*}" + + resource_id="$(az resource list \ + --subscription "$SUBSCRIPTION_ID" \ + --resource-type Microsoft.Kusto/clusters \ + --query "[?name=='${cluster_name}'].id | [0]" \ + -o tsv 2>/dev/null || true)" + + if [[ -n "$resource_id" && "$resource_id" != "null" ]]; then + printf '%s\n' "$resource_id" + return 0 + fi + + resource_id="$(az graph query \ + -q "Resources | where type =~ 'microsoft.kusto/clusters' | where name =~ '${cluster_name}' or tostring(properties.uri) =~ '${cluster_uri}' | project id | limit 2" \ + -o json 2>/dev/null | jq -r '.data[].id' 2>/dev/null || true)" + graph_result_count="$(printf '%s\n' "$resource_id" | sed '/^$/d' | wc -l | tr -d ' ')" + + if [[ "$graph_result_count" == "1" ]]; then + printf '%s\n' "$resource_id" + return 0 + fi + + if [[ -z "$resource_id" || "$resource_id" == "null" ]]; then + fail "Error: could not resolve Kusto cluster '${cluster_name}'. Pass --cluster-resource-id so deployment can assign AllDatabasesViewer before creating the connector." 2 + fi + + fail "Error: Kusto cluster '${cluster_name}' resolved to multiple resources. Pass --cluster-resource-id explicitly so deployment assigns AllDatabasesViewer to the intended cluster." 2 +} + +warn_kusto_private_query_limitation() { + local cluster_id="$1" + local cluster_json + local public_network_access + local private_endpoint_count + local cluster_uri + local docs_url="https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations" + + [[ -n "$cluster_id" ]] || return 0 + + cluster_json="$(az resource show --ids "$cluster_id" --api-version 2023-08-15 -o json 2>/dev/null || true)" + if [[ -z "$cluster_json" ]]; then + echo -e "${YELLOW}Warning: Could not inspect Kusto cluster network access. Deployment will continue.${NC}" + echo " Cluster: $cluster_id" + echo " Review SRE Agent private endpoint limitations: $docs_url" + echo "" + return 0 + fi + + public_network_access="$(echo "$cluster_json" | jq -r '.properties.publicNetworkAccess // .publicNetworkAccess // ""' 2>/dev/null || true)" + private_endpoint_count="$(echo "$cluster_json" | jq -r '((.properties.privateEndpointConnections // .privateEndpointConnections // []) | length)' 2>/dev/null || echo 0)" + cluster_uri="$(echo "$cluster_json" | jq -r '.properties.uri // .uri // empty' 2>/dev/null || true)" + + if [[ "$public_network_access" == "Disabled" ]]; then + echo -e "${YELLOW}Warning: The Kusto cluster denies public query access.${NC}" + echo " Cluster: ${cluster_uri:-$cluster_id}" + echo " publicNetworkAccess: ${public_network_access}" + echo " private endpoint connections: ${private_endpoint_count}" + echo " SRE Agent will still be deployed and the finops-hub-kusto connector will still be created." + echo " Per the SRE Agent known limitations, private endpoint ADX blocks direct KQL queries." + echo " The customer can enable public query access if they want the Kusto connector to become healthy:" + echo " $docs_url" + echo "" + fi +} + +RECIPE_DIR="" +SUBSCRIPTION_ID="" +RESOURCE_GROUP="" +AGENT_NAME="" +LOCATION="" +CLUSTER_URI="" +CLUSTER_RESOURCE_ID="" +DEPLOY_NAME="" +DRY_RUN="" +ENABLE_SUBSCRIPTION_READER="true" +TARGET_RGS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --recipe) + require_value "--recipe" "${2:-}" + RECIPE_DIR="$2" + shift 2 + ;; + --subscription) + require_value "--subscription" "${2:-}" + SUBSCRIPTION_ID="$2" + shift 2 + ;; + -g|--resource-group) + require_value "--resource-group / -g" "${2:-}" + RESOURCE_GROUP="$2" + shift 2 + ;; + -n|--name) + require_value "--name / -n" "${2:-}" + AGENT_NAME="$2" + shift 2 + ;; + -l|--location) + require_value "--location / -l" "${2:-}" + LOCATION="$2" + shift 2 + ;; + --target-resource-group) + require_value "--target-resource-group" "${2:-}" + TARGET_RGS+=("$2") + shift 2 + ;; + --cluster-uri) + require_value "--cluster-uri" "${2:-}" + CLUSTER_URI="$2" + shift 2 + ;; + --cluster-resource-id) + require_value "--cluster-resource-id" "${2:-}" + CLUSTER_RESOURCE_ID="$2" + shift 2 + ;; + --subscription-reader) + ENABLE_SUBSCRIPTION_READER="true" + shift + ;; + --no-subscription-reader) + ENABLE_SUBSCRIPTION_READER="false" + shift + ;; + --deploy-name) + require_value "--deploy-name" "${2:-}" + DEPLOY_NAME="$2" + shift 2 + ;; + --dry-run) + DRY_RUN="true" + shift + ;; + --force|--no-telemetry) + shift + ;; + -h|--help) + usage 0 + ;; + -*) + fail "Error: unknown flag '$1'" 2 + ;; + *) + fail "Error: unknown argument '$1'" 2 + ;; + esac +done + +[[ -n "$RECIPE_DIR" ]] || fail "Error: --recipe is required" 2 +[[ -d "$RECIPE_DIR" ]] || fail "Error: recipe directory not found: $RECIPE_DIR" 1 +[[ -f "${RECIPE_DIR}/agent.json" ]] || fail "Error: recipe agent.json not found: ${RECIPE_DIR}/agent.json" 1 +[[ -n "$SUBSCRIPTION_ID" ]] || fail "Error: --subscription is required" 2 +[[ -n "$RESOURCE_GROUP" ]] || fail "Error: --resource-group is required" 2 +[[ -n "$AGENT_NAME" ]] || fail "Error: --name is required" 2 +[[ -n "$LOCATION" ]] || fail "Error: --location is required" 2 +validate_kusto_uri "$CLUSTER_URI" +if [[ -n "$CLUSTER_URI" ]]; then + [[ -n "$(parse_kusto_database_name "$CLUSTER_URI")" ]] || fail "Error: could not parse Kusto database name from --cluster-uri" 2 +fi + +append_target_rg "$RESOURCE_GROUP" + +command -v az >/dev/null || fail "Azure CLI (az) is required" 1 +command -v jq >/dev/null || fail "jq is required" 1 +command -v git >/dev/null || fail "git is required" 1 + +PYTHON_CMD="" +if command -v python3 >/dev/null; then + PYTHON_CMD="python3" +elif command -v python >/dev/null && python --version 2>&1 | grep -q "Python 3"; then + PYTHON_CMD="python" +else + fail "Python 3 is required" 1 +fi + +if [[ -n "$CLUSTER_URI" && -z "$CLUSTER_RESOURCE_ID" ]]; then + if [[ -n "$DRY_RUN" ]]; then + fail "Error: --cluster-resource-id is required with --cluster-uri for --dry-run because dry-run makes no Azure calls. Real deployments can resolve it from the Kusto URI." 2 + fi + + echo "Resolving Kusto cluster resource ID from --cluster-uri..." + az account show --subscription "$SUBSCRIPTION_ID" >/dev/null + az account set --subscription "$SUBSCRIPTION_ID" + CLUSTER_RESOURCE_ID="$(resolve_kusto_cluster_resource_id "$CLUSTER_URI")" + echo " Kusto cluster: $CLUSTER_RESOURCE_ID" +fi + +if [[ -n "$CLUSTER_RESOURCE_ID" && -z "$DRY_RUN" ]]; then + warn_kusto_private_query_limitation "$CLUSTER_RESOURCE_ID" +fi + +if [[ -n "$CLUSTER_RESOURCE_ID" ]]; then + CLUSTER_SUBSCRIPTION_ID="$(resource_id_subscription "$CLUSTER_RESOURCE_ID")" + CLUSTER_RESOURCE_GROUP="$(resource_id_resource_group "$CLUSTER_RESOURCE_ID")" + if [[ "$(to_lower "$CLUSTER_SUBSCRIPTION_ID")" == "$(to_lower "$SUBSCRIPTION_ID")" ]]; then + append_target_rg "$CLUSTER_RESOURCE_GROUP" + else + echo -e "${YELLOW}Warning: FinOps Hub cluster is in subscription ${CLUSTER_SUBSCRIPTION_ID}; add agent managed-resource scope and resource-group RBAC for ${CLUSTER_RESOURCE_GROUP} separately.${NC}" >&2 + fi +fi + +ACCESS_LEVEL="$(recipe_value "${RECIPE_DIR}/agent.json" '.access.accessLevel')" +[[ -n "$ACCESS_LEVEL" ]] || ACCESS_LEVEL="Low" +ACTION_MODE_RAW="$(recipe_value "${RECIPE_DIR}/agent.json" '.access.actionMode')" +[[ -n "$ACTION_MODE_RAW" ]] || ACTION_MODE_RAW="Review" +ACTION_MODE="$(normalize_action_mode "$ACTION_MODE_RAW")" +UPGRADE_CHANNEL="$(recipe_value "${RECIPE_DIR}/agent.json" '.upgradeChannel')" +[[ -n "$UPGRADE_CHANNEL" ]] || UPGRADE_CHANNEL="Preview" +DEFAULT_MODEL_PROVIDER="$(recipe_value "${RECIPE_DIR}/agent.json" '.defaultModelProvider')" +[[ -n "$DEFAULT_MODEL_PROVIDER" ]] || DEFAULT_MODEL_PROVIDER="MicrosoftFoundry" +DEFAULT_MODEL_NAME="$(recipe_value "${RECIPE_DIR}/agent.json" '.defaultModelName')" +[[ -n "$DEFAULT_MODEL_NAME" ]] || DEFAULT_MODEL_NAME="Automatic" +MONTHLY_AGENT_UNIT_LIMIT="$(recipe_value "${RECIPE_DIR}/agent.json" '.monthlyAgentUnitLimit')" +[[ -n "$MONTHLY_AGENT_UNIT_LIMIT" ]] || MONTHLY_AGENT_UNIT_LIMIT="10000" +EXPERIMENTAL_SETTINGS="$(jq -c '.experimentalSettings // {"EnableSandboxGroup": true, "EnableWorkspaceTools": true}' "${RECIPE_DIR}/agent.json")" +TAGS="$(jq -c '.tags // {"finops-toolkit":"sre-agent","source":"microsoft-finops-toolkit"}' "${RECIPE_DIR}/agent.json")" +TARGET_RGS_JSON="$(printf '%s\n' "${TARGET_RGS[@]}" | jq -R . | jq -sc '.')" + +[[ -n "$DEPLOY_NAME" ]] || DEPLOY_NAME="$(deterministic_deploy_name)" +BUILD_ROOT="${SRE_AGENT_DEPLOY_DIR:-${HOME}/.cache/finops-toolkit/sre-agent}" +BUILD_DIR="${BUILD_ROOT}/${AGENT_NAME}-${DEPLOY_NAME}" +mkdir -p "$BUILD_DIR" + +PARAMETERS_FILE="${BUILD_DIR}/deploy.parameters.json" +RESULT_FILE="${BUILD_DIR}/deployment-result.json" + +jq -n \ + --arg resourceGroupName "$RESOURCE_GROUP" \ + --arg agentName "$AGENT_NAME" \ + --arg location "$LOCATION" \ + --arg accessLevel "$ACCESS_LEVEL" \ + --arg actionMode "$ACTION_MODE" \ + --arg upgradeChannel "$UPGRADE_CHANNEL" \ + --arg defaultModelProvider "$DEFAULT_MODEL_PROVIDER" \ + --arg defaultModelName "$DEFAULT_MODEL_NAME" \ + --argjson monthlyAgentUnitLimit "$MONTHLY_AGENT_UNIT_LIMIT" \ + --arg kustoClusterId "$CLUSTER_RESOURCE_ID" \ + --argjson enableSubscriptionReaderRole "$ENABLE_SUBSCRIPTION_READER" \ + --argjson targetResourceGroups "$TARGET_RGS_JSON" \ + --argjson experimentalSettings "$EXPERIMENTAL_SETTINGS" \ + --argjson tags "$TAGS" \ + '{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { "value": $resourceGroupName }, + "agentName": { "value": $agentName }, + "location": { "value": $location }, + "targetResourceGroups": { "value": $targetResourceGroups }, + "accessLevel": { "value": $accessLevel }, + "actionMode": { "value": $actionMode }, + "upgradeChannel": { "value": $upgradeChannel }, + "defaultModelProvider": { "value": $defaultModelProvider }, + "defaultModelName": { "value": $defaultModelName }, + "monthlyAgentUnitLimit": { "value": $monthlyAgentUnitLimit }, + "experimentalSettings": { "value": $experimentalSettings }, + "tags": { "value": $tags }, + "finopsHubKustoClusterResourceId": { "value": $kustoClusterId }, + "enableSubscriptionReaderRole": { "value": $enableSubscriptionReaderRole } + } + }' > "$PARAMETERS_FILE" + +echo "" +echo -e "${BLUE}============================================================${NC}" +echo -e "${BLUE} Azure SRE Agent - FinOps Toolkit Setup${NC}" +echo -e "${BLUE}============================================================${NC}" +echo "" +echo -e "${YELLOW}[1/4] Checking prerequisites...${NC}" +echo " az: $(az version --query '\"azure-cli\"' -o tsv 2>/dev/null || echo found)" +echo " jq: $(jq --version)" +echo " python: $($PYTHON_CMD --version 2>&1)" +echo " azd: not used" +echo "" + +if [[ -n "$DRY_RUN" ]]; then + echo -e "${YELLOW}[2/4] Planned deployment...${NC}" + echo " Subscription: $SUBSCRIPTION_ID" + echo " Resource group: $RESOURCE_GROUP" + echo " Agent: $AGENT_NAME" + echo " Region: $LOCATION" + echo " Target resource groups: ${TARGET_RGS[*]}" + echo " Subscription Reader: $ENABLE_SUBSCRIPTION_READER" + echo " Parameters: $PARAMETERS_FILE" + echo "" + echo "Dry run complete. No Azure calls were made." + exit 0 +fi + +echo -e "${YELLOW}[2/4] Checking Azure account...${NC}" +az account show --subscription "$SUBSCRIPTION_ID" --query "{subscription:name, id:id}" -o table >/dev/null +az account set --subscription "$SUBSCRIPTION_ID" +echo " Subscription: $SUBSCRIPTION_ID" +echo " Resource group: $RESOURCE_GROUP" +echo " Agent: $AGENT_NAME" +echo " Region: $LOCATION" +echo " Target resource groups: ${TARGET_RGS[*]}" +echo " Subscription Reader: $ENABLE_SUBSCRIPTION_READER" +echo " Parameters: $PARAMETERS_FILE" +echo "" + +echo -e "${YELLOW}[3/4] Deploying infrastructure with Azure CLI + Bicep...${NC}" +echo " Registering Microsoft.App provider..." +az provider register -n Microsoft.App --wait --output none + +echo " Starting deployment: $DEPLOY_NAME" +az deployment sub create \ + --subscription "$SUBSCRIPTION_ID" \ + --location "$LOCATION" \ + --name "$DEPLOY_NAME" \ + --template-file "${INFRA_DIR}/main.bicep" \ + --parameters "@${PARAMETERS_FILE}" \ + --no-wait \ + --output none + +echo " Waiting for deployment to complete..." +DEPLOYMENT_START="$(date +%s)" +DEPLOYMENT_JSON="{}" +STATE="" +while true; do + DEPLOYMENT_JSON="$(az deployment sub show \ + --subscription "$SUBSCRIPTION_ID" \ + --name "$DEPLOY_NAME" \ + --output json 2>/dev/null || echo "{}")" + STATE="$(echo "$DEPLOYMENT_JSON" | jq -r '.properties.provisioningState // "Accepted"' 2>/dev/null)" + + case "$STATE" in + Succeeded|Failed|Canceled) + break + ;; + *) + NOW="$(date +%s)" + echo " Deployment state: ${STATE} ($((NOW - DEPLOYMENT_START))s elapsed)" + sleep 10 + ;; + esac +done + +printf '%s\n' "$DEPLOYMENT_JSON" > "$RESULT_FILE" + +STATE="$(jq -r '.properties.provisioningState // "Failed"' "$RESULT_FILE")" +if [[ "$STATE" != "Succeeded" ]]; then + echo "" + echo "Deployment failed. Diagnostic command:" + echo " az deployment operation sub list --subscription ${SUBSCRIPTION_ID} -n ${DEPLOY_NAME} -o table" + exit 1 +fi + +AGENT_ENDPOINT="$(deployment_output_value "$RESULT_FILE" "SRE_AGENT_ENDPOINT")" +SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID="$(deployment_output_value "$RESULT_FILE" "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID")" +AGENT_PORTAL_URL="$(deployment_output_value "$RESULT_FILE" "AGENT_PORTAL_URL" "https://sre.azure.com")" + +[[ -n "$AGENT_ENDPOINT" ]] || fail "Deployment succeeded but did not return SRE_AGENT_ENDPOINT" 1 +[[ -n "$SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID" ]] || fail "Deployment succeeded but did not return SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID" 1 + +echo "" +echo -e "${YELLOW}[4/4] Applying SRE Agent extras...${NC}" +APPLY_EXTRAS_ARGS=( + --endpoint "$AGENT_ENDPOINT" + --subscription "$SUBSCRIPTION_ID" + --resource-group "$RESOURCE_GROUP" + --name "$AGENT_NAME" + --recipe "$RECIPE_DIR" + --build-dir "${BUILD_DIR}/extras" +) + +if [[ -n "$CLUSTER_URI" ]]; then + APPLY_EXTRAS_ARGS+=(--kusto-connector-uri "$CLUSTER_URI") +fi + +bash "${SCRIPT_DIR}/apply-extras.sh" \ + "${APPLY_EXTRAS_ARGS[@]}" + +echo "" +echo -e "${BLUE}============================================================${NC}" +echo -e "${GREEN} SRE Agent ready${NC}" +echo -e "${BLUE}============================================================${NC}" +echo " Agent portal: $AGENT_PORTAL_URL" +echo " Endpoint: $AGENT_ENDPOINT" +echo " Build dir: $BUILD_DIR" +echo "" diff --git a/src/templates/sre-agent/bin/post-provision.sh b/src/templates/sre-agent/bin/post-provision.sh new file mode 100755 index 000000000..4bf44af9f --- /dev/null +++ b/src/templates/sre-agent/bin/post-provision.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Compatibility wrapper. The SRE Agent recipe now follows the upstream +# Bicep + apply-extras pattern for post-provisioning. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +echo "bin/post-provision.sh is deprecated; forwarding to bin/apply-extras.sh" >&2 +exec bash "${SCRIPT_DIR}/apply-extras.sh" "$@" diff --git a/src/templates/sre-agent/bin/telemetry.sh b/src/templates/sre-agent/bin/telemetry.sh new file mode 100755 index 000000000..97aa3a02a --- /dev/null +++ b/src/templates/sre-agent/bin/telemetry.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# telemetry.sh — anonymous usage tracking for recipe popularity. +# +# Sends a single custom event to App Insights. Non-blocking, best-effort. +# No PII is collected — only recipe name, action, region, OS, and coarse booleans. +# +# Usage (sourced by other scripts): +# source "$(dirname "$0")/telemetry.sh" +# send_telemetry "deploy" "finops-hub" "westus3" "true" "false" "true" "false" "deploy" + +_TELEMETRY_IKEY="f10eff7f-b995-4c41-8347-90f0f55d5969" +_TELEMETRY_ENDPOINT="https://eastus2-3.in.applicationinsights.azure.com/v2/track" + +send_telemetry() { + [[ "${_NO_TELEMETRY:-}" == "true" ]] && return 0 + + local action="${1:-unknown}" + local recipe="${2:-unknown}" + local region="${3:-unknown}" + local used_recipe_flag="${4:-false}" + local used_legacy_positional="${5:-false}" + local has_cluster_uri="${6:-false}" + local has_cluster_resource_id="${7:-false}" + local mode="${8:-deploy}" + local os_type + os_type="$(uname -s 2>/dev/null || echo unknown)" + + # Fire and forget — never block or fail the main script + (curl -s -o /dev/null -m 5 -X POST "$_TELEMETRY_ENDPOINT" \ + -H "Content-Type: application/json" \ + -d "[{ + \"name\": \"Microsoft.ApplicationInsights.Event\", + \"time\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\", + \"iKey\": \"${_TELEMETRY_IKEY}\", + \"data\": { + \"baseType\": \"EventData\", + \"baseData\": { + \"name\": \"recipe-usage\", + \"properties\": { + \"action\": \"${action}\", + \"recipe\": \"${recipe}\", + \"region\": \"${region}\", + \"os\": \"${os_type}\", + \"used_recipe_flag\": \"${used_recipe_flag}\", + \"used_legacy_positional\": \"${used_legacy_positional}\", + \"has_cluster_uri\": \"${has_cluster_uri}\", + \"has_cluster_resource_id\": \"${has_cluster_resource_id}\", + \"mode\": \"${mode}\" + } + } + } + }]" 2>/dev/null &) 2>/dev/null +} diff --git a/src/templates/sre-agent/createUiDefinition.json b/src/templates/sre-agent/createUiDefinition.json new file mode 100644 index 000000000..87e82bcaa --- /dev/null +++ b/src/templates/sre-agent/createUiDefinition.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "basics": { + "description": "Deploy Azure SRE Agent with the FinOps toolkit recipe for FinOps hub analysis, capacity monitoring, scheduled tasks, and specialist agents.", + "location": { + "label": "Location", + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ] + } + } + }, + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ], + "basics": [ + { + "name": "resourceGroupName", + "type": "Microsoft.Common.TextBox", + "label": "Agent resource group", + "defaultValue": "finops-hub-sre", + "toolTip": "Resource group that will contain the Azure SRE Agent, monitoring resources, and deployment script identity.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9._()\\-]{1,90}$", + "validationMessage": "Enter a valid Azure resource group name." + }, + "visible": true + }, + { + "name": "agentName", + "type": "Microsoft.Common.TextBox", + "label": "Agent name", + "defaultValue": "finops-hub-sre", + "toolTip": "Name of the Azure SRE Agent resource.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,61}[a-zA-Z0-9]$", + "validationMessage": "Name must be 3-63 characters and can contain letters, numbers, and hyphens. The first and last characters must be alphanumeric." + }, + "visible": true + } + ], + "steps": [ + { + "name": "configuration", + "label": "Configuration", + "elements": [ + { + "name": "finopsHubKustoConnectorUri", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto URI", + "defaultValue": "", + "toolTip": "Optional database-qualified Azure Data Explorer URI for the FinOps hub. Example: https://cluster.region.kusto.windows.net/Hub", + "constraints": { + "required": false, + "regex": "^$|^https://.+\\.kusto\\.windows\\.net/.+", + "validationMessage": "Enter a database-qualified Kusto URI such as https://cluster.region.kusto.windows.net/Hub, or leave blank." + }, + "visible": true + }, + { + "name": "finopsHubKustoClusterResourceId", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto cluster resource ID", + "defaultValue": "", + "toolTip": "Optional Azure Data Explorer cluster resource ID. Provide this to assign the agent managed identity AllDatabasesViewer on the cluster.", + "constraints": { + "required": false, + "regex": "^$|^/subscriptions/.+/resourceGroups/.+/providers/Microsoft\\.Kusto/clusters/.+", + "validationMessage": "Enter a valid Microsoft.Kusto/clusters resource ID, or leave blank." + }, + "visible": true + }, + { + "name": "targetResourceGroups", + "type": "Microsoft.Common.TextBox", + "label": "Additional target resource groups", + "defaultValue": "", + "toolTip": "Optional comma-separated resource group names the agent can observe or act on. The agent resource group is always included.", + "constraints": { + "required": false, + "regex": "^$|^[A-Za-z0-9_.()\\-]+(\\s*,\\s*[A-Za-z0-9_.()\\-]+)*$", + "validationMessage": "Enter a comma-separated list of resource group names without blank entries or trailing commas." + }, + "visible": true + }, + { + "name": "accessLevel", + "type": "Microsoft.Common.OptionsGroup", + "label": "Access level", + "defaultValue": "High", + "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "constraints": { + "allowedValues": [ + { + "label": "High", + "value": "High" + }, + { + "label": "Low", + "value": "Low" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "actionMode", + "type": "Microsoft.Common.OptionsGroup", + "label": "Action mode", + "defaultValue": "autonomous", + "toolTip": "Review requires approval before write actions. Autonomous lets the agent run enabled actions within its assigned access.", + "constraints": { + "allowedValues": [ + { + "label": "Autonomous", + "value": "autonomous" + }, + { + "label": "Review", + "value": "review" + }, + { + "label": "Read only", + "value": "readOnly" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "enableSubscriptionReaderRole", + "type": "Microsoft.Common.CheckBox", + "label": "Grant subscription Reader to the agent", + "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", + "defaultValue": true, + "visible": true + } + ] + } + ], + "outputs": { + "resourceGroupName": "[basics('resourceGroupName')]", + "agentName": "[basics('agentName')]", + "location": "[location()]", + "targetResourceGroupNames": "[steps('configuration').targetResourceGroups]", + "finopsHubKustoConnectorUri": "[steps('configuration').finopsHubKustoConnectorUri]", + "finopsHubKustoClusterResourceId": "[steps('configuration').finopsHubKustoClusterResourceId]", + "accessLevel": "[steps('configuration').accessLevel]", + "actionMode": "[steps('configuration').actionMode]", + "enableSubscriptionReaderRole": "[steps('configuration').enableSubscriptionReaderRole]" + } + } +} diff --git a/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml new file mode 100644 index 000000000..afa74e4e7 --- /dev/null +++ b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml @@ -0,0 +1,32 @@ +name: Deploy FinOps SRE Agent + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + - name: Deploy FinOps SRE Agent + working-directory: src/templates/sre-agent + env: + CLUSTER_URI: ${{ secrets.SRE_AGENT_CLUSTER_URI }} + run: > + bash bin/deploy.sh + --recipe recipes/finops-hub + --resource-group ${{ vars.SRE_AGENT_RESOURCE_GROUP }} + --name ${{ vars.SRE_AGENT_NAME }} + --location ${{ vars.SRE_AGENT_LOCATION }} + --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + --cluster-uri "$CLUSTER_URI" + --force diff --git a/src/templates/sre-agent/infra/main.bicep b/src/templates/sre-agent/infra/main.bicep new file mode 100644 index 000000000..ff49374b9 --- /dev/null +++ b/src/templates/sre-agent/infra/main.bicep @@ -0,0 +1,132 @@ +// Copied from microsoft/sre-agent labs/starter-lab/infra/main.bicep and +// updated for the FinOps Toolkit SRE Agent template: +// - no azd environment dependency +// - no Grubify sample application +// - resource-group scoped target access + +targetScope = 'subscription' + +@description('Resource group that holds the SRE Agent resources.') +param resourceGroupName string + +@description('SRE Agent name.') +param agentName string + +@description('Primary location for all resources.') +@allowed(['australiaeast', 'canadacentral', 'eastus2', 'francecentral', 'koreacentral', 'swedencentral', 'uksouth']) +param location string = 'eastus2' + +@description('Resource groups the agent can observe or act on.') +param targetResourceGroups array = [] + +@description('Agent access level.') +@allowed(['Low', 'High']) +param accessLevel string = 'Low' + +@description('Agent action mode.') +@allowed(['review', 'autonomous', 'readOnly']) +param actionMode string = 'review' + +@description('Agent upgrade channel.') +@allowed(['Stable', 'Preview']) +param upgradeChannel string = 'Preview' + +@description('Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal.') +@allowed(['MicrosoftFoundry', 'Anthropic']) +param defaultModelProvider string = 'MicrosoftFoundry' + +@description('Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider.') +param defaultModelName string = 'Automatic' + +@description('Monthly agent unit limit.') +@minValue(1) +param monthlyAgentUnitLimit int = 10000 + +@description('Agent experimental settings.') +param experimentalSettings object = { + EnableSandboxGroup: true + EnableWorkspaceTools: true +} + +@description('Azure resource tags.') +param tags object = {} + +@description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') +param finopsHubKustoClusterResourceId string = '' + +@description('Assign Reader on the deployment subscription to the agent managed identity.') +param enableSubscriptionReaderRole bool = true + +var targetRgs = empty(targetResourceGroups) ? [resourceGroupName] : targetResourceGroups +var agentResourceGroupId = subscriptionResourceId('Microsoft.Resources/resourceGroups', resourceGroupName) +var targetRgIds = [for rgName in targetRgs: subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)] +var namingSeed = toLower('${subscription().subscriptionId}|${agentResourceGroupId}|${agentName}') +var readerRoleId = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + +resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: location + tags: tags +} + +module resources 'resources.bicep' = { + name: 'resources-deployment' + scope: rg + params: { + agentName: agentName + location: location + namingSeed: namingSeed + targetResourceGroupIds: targetRgIds + accessLevel: accessLevel + actionMode: actionMode + upgradeChannel: upgradeChannel + defaultModelProvider: defaultModelProvider + defaultModelName: defaultModelName + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + tags: tags + } +} + +module targetRbac 'modules/resource-group-rbac.bicep' = [for rgName in targetRgs: { + name: 'target-rbac-${uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)), namingSeed)}' + scope: resourceGroup(rgName) + params: { + principalId: resources.outputs.agentPrincipalId + accessLevel: accessLevel + } +}] + +resource subscriptionReaderRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableSubscriptionReaderRole) { + name: guid(subscription().id, namingSeed, readerRoleId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', readerRoleId) + principalId: resources.outputs.agentPrincipalId + principalType: 'ServicePrincipal' + } +} + +var hasKustoCluster = !empty(finopsHubKustoClusterResourceId) +var kustoClusterSubscriptionId = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[2] : '' +var kustoClusterResourceGroupName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[4] : '' +var kustoClusterName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[8] : '' + +module finopsHubKustoAllDatabasesViewerRbac 'modules/kusto-all-databases-viewer-rbac.bicep' = if (hasKustoCluster) { + name: 'kusto-rbac-${uniqueString(finopsHubKustoClusterResourceId, namingSeed)}' + scope: resourceGroup(kustoClusterSubscriptionId, kustoClusterResourceGroupName) + params: { + clusterName: kustoClusterName + principalApplicationId: resources.outputs.agentPrincipalId + principalTenantId: tenant().tenantId + principalAssignmentName: 'sre-agent-${uniqueString(finopsHubKustoClusterResourceId, namingSeed, 'all-db-viewer')}' + } +} + +output AZURE_RESOURCE_GROUP string = rg.name +output AZURE_LOCATION string = location +output SRE_AGENT_NAME string = resources.outputs.agentName +output SRE_AGENT_ENDPOINT string = resources.outputs.agentEndpoint +output AGENT_PORTAL_URL string = resources.outputs.agentPortalUrl +output SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID string = resources.outputs.agentPrincipalId +output SYSTEM_MANAGED_IDENTITY_TENANT_ID string = resources.outputs.agentTenantId +output LOG_ANALYTICS_WORKSPACE_ID string = resources.outputs.logAnalyticsWorkspaceId diff --git a/src/templates/sre-agent/infra/modules/apply-extras.bicep b/src/templates/sre-agent/infra/modules/apply-extras.bicep new file mode 100644 index 000000000..4adbe17a8 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/apply-extras.bicep @@ -0,0 +1,103 @@ +targetScope = 'resourceGroup' + +@description('Location for the deployment script resources.') +param location string + +@description('SRE Agent name.') +param agentName string + +@description('SRE Agent data-plane endpoint.') +param agentEndpoint string + +@description('Subscription that contains the SRE Agent.') +param subscriptionId string + +@description('Public URI for the generated SRE Agent recipe package.') +param recipePackageUri string + +@description('Optional database-qualified Kusto connector URI.') +param kustoConnectorUri string = '' + +@description('Forces the deployment script to run when the template is redeployed.') +param forceUpdateTag string + +@description('Azure resource tags.') +param tags object = {} + +var identityName = 'id-sre-apply-${uniqueString(resourceGroup().id, agentName)}' +var scriptName = 'apply-sre-${uniqueString(resourceGroup().id, agentName)}' +var sreAgentAdminRoleId = 'e79298df-d852-4c6d-84f9-5d13249d1e55' + +#disable-next-line BCP081 +resource sreAgent 'Microsoft.App/agents@2026-01-01' existing = { + name: agentName +} + +resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: identityName + location: location + tags: tags +} + +resource sreAgentAdminRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(sreAgent.id, identity.id, sreAgentAdminRoleId) + scope: sreAgent + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', sreAgentAdminRoleId) + principalId: identity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +resource applyExtras 'Microsoft.Resources/deploymentScripts@2023-08-01' = { + name: scriptName + location: location + tags: tags + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${identity.id}': {} + } + } + properties: { + azPowerShellVersion: '11.0' + retentionInterval: 'PT1H' + cleanupPreference: 'OnSuccess' + timeout: 'PT2H' + forceUpdateTag: forceUpdateTag + scriptContent: loadTextContent('../scripts/Apply-SreAgentExtras.ps1') + environmentVariables: [ + { + name: 'subscriptionId' + value: subscriptionId + } + { + name: 'resourceGroupName' + value: resourceGroup().name + } + { + name: 'agentName' + value: agentName + } + { + name: 'agentEndpoint' + value: agentEndpoint + } + { + name: 'recipePackageUri' + value: recipePackageUri + } + { + name: 'kustoConnectorUri' + value: kustoConnectorUri + } + ] + } + dependsOn: [ + sreAgentAdminRoleAssignment + ] +} + +output identityName string = identity.name +output scriptName string = applyExtras.name diff --git a/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep b/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep new file mode 100644 index 000000000..61baa4c44 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/kusto-all-databases-viewer-rbac.bicep @@ -0,0 +1,26 @@ +@description('Kusto cluster name.') +param clusterName string + +@description('Microsoft Entra application/client ID to assign to the Kusto cluster.') +param principalApplicationId string + +@description('Principal tenant ID.') +param principalTenantId string + +@description('Stable principal assignment name.') +param principalAssignmentName string + +resource cluster 'Microsoft.Kusto/clusters@2024-04-13' existing = { + name: clusterName +} + +resource allDatabasesViewer 'Microsoft.Kusto/clusters/principalAssignments@2024-04-13' = { + parent: cluster + name: principalAssignmentName + properties: { + principalId: principalApplicationId + principalType: 'App' + role: 'AllDatabasesViewer' + tenantId: principalTenantId + } +} diff --git a/src/templates/sre-agent/infra/modules/monitoring.bicep b/src/templates/sre-agent/infra/modules/monitoring.bicep new file mode 100644 index 000000000..6a0102df1 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/monitoring.bicep @@ -0,0 +1,39 @@ +@description('Location for resources') +param location string + +@description('Log Analytics Workspace name') +param logAnalyticsName string + +@description('Application Insights name') +param appInsightsName string + +// Log Analytics Workspace +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { + name: logAnalyticsName + location: location + properties: { + sku: { + name: 'PerGB2018' + } + retentionInDays: 30 + } +} + +// Application Insights (linked to Log Analytics) +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightsName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + Request_Source: 'IbizaAIExtension' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +// Outputs +output logAnalyticsWorkspaceId string = logAnalyticsWorkspace.id +output logAnalyticsWorkspaceName string = logAnalyticsWorkspace.name +output appInsightsId string = applicationInsights.id +output appInsightsAppId string = applicationInsights.properties.AppId +output appInsightsConnectionString string = applicationInsights.properties.ConnectionString diff --git a/src/templates/sre-agent/infra/modules/resource-group-rbac.bicep b/src/templates/sre-agent/infra/modules/resource-group-rbac.bicep new file mode 100644 index 000000000..15ede6c34 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/resource-group-rbac.bicep @@ -0,0 +1,33 @@ +@description('Principal ID of the managed identity to assign roles to.') +param principalId string + +@description('Agent access level.') +@allowed(['Low', 'High']) +param accessLevel string + +var readerRoleId = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' +var monitoringReaderRoleId = '43d0d8ad-25c7-4714-9337-8ba259a9fe05' +var logAnalyticsReaderRoleId = '73c42c96-874c-492b-b04d-ab87d138a893' +var contributorRoleId = 'b24988ac-6180-42a0-ab88-20f7382dd24c' + +var roleIds = accessLevel == 'High' + ? [ + readerRoleId + monitoringReaderRoleId + logAnalyticsReaderRoleId + contributorRoleId + ] + : [ + readerRoleId + monitoringReaderRoleId + logAnalyticsReaderRoleId + ] + +resource roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for roleId in roleIds: { + name: guid(resourceGroup().id, principalId, roleId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId) + principalId: principalId + principalType: 'ServicePrincipal' + } +}] diff --git a/src/templates/sre-agent/infra/modules/sre-agent.bicep b/src/templates/sre-agent/infra/modules/sre-agent.bicep new file mode 100644 index 000000000..4eb264822 --- /dev/null +++ b/src/templates/sre-agent/infra/modules/sre-agent.bicep @@ -0,0 +1,103 @@ +// Copied from microsoft/sre-agent labs/starter-lab/infra/modules/sre-agent.bicep +// and updated for the FinOps Toolkit SRE Agent template. + +@description('Location for resources.') +param location string + +@description('SRE Agent name.') +param agentName string + +@description('Application Insights App ID.') +param appInsightsAppId string + +@description('Application Insights connection string.') +@secure() +param appInsightsConnectionString string + +@description('Application Insights resource ID.') +param appInsightsId string + +@description('Resource group IDs to add as managed resources.') +param managedResourceGroupIds array + +@description('Agent access level.') +param accessLevel string + +@description('Agent action mode.') +param actionMode string + +@description('Agent upgrade channel.') +param upgradeChannel string + +@description('Default SRE Agent model provider.') +param defaultModelProvider string + +@description('Default SRE Agent model name.') +param defaultModelName string + +@description('Monthly agent unit limit.') +param monthlyAgentUnitLimit int + +@description('Agent experimental settings.') +param experimentalSettings object + +@description('Azure resource tags.') +param tags object = {} + +var sreAgentAdminRoleId = 'e79298df-d852-4c6d-84f9-5d13249d1e55' + +#disable-next-line BCP081 +resource sreAgent 'Microsoft.App/agents@2026-01-01' = { + name: agentName + location: location + tags: union(tags, { + 'hidden-link: /app-insights-resource-id': appInsightsId + source: 'microsoft-sre-agent-starter-lab' + 'finops-toolkit': 'sre-agent' + }) + identity: { + type: 'SystemAssigned' + } + properties: { + knowledgeGraphConfiguration: { + managedResources: managedResourceGroupIds + identity: 'system' + } + actionConfiguration: { + mode: actionMode + identity: 'system' + accessLevel: accessLevel + } + upgradeChannel: upgradeChannel + defaultModel: { + provider: defaultModelProvider + name: defaultModelName + } + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + mcpServers: [] + logConfiguration: { + applicationInsightsConfiguration: { + appId: appInsightsAppId + connectionString: appInsightsConnectionString + } + } + } +} + +resource sreAgentAdminRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(sreAgent.id, deployer().objectId, sreAgentAdminRoleId) + scope: sreAgent + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', sreAgentAdminRoleId) + principalId: deployer().objectId + principalType: 'User' + } +} + +output agentName string = sreAgent.name +output agentId string = sreAgent.id +output agentEndpoint string = sreAgent.properties.agentEndpoint +output agentPortalUrl string = 'https://sre.azure.com/#/agent/${subscription().subscriptionId}/${resourceGroup().name}/${sreAgent.name}' +output agentPrincipalId string = sreAgent.identity.principalId +output agentTenantId string = sreAgent.identity.tenantId diff --git a/src/templates/sre-agent/infra/resources.bicep b/src/templates/sre-agent/infra/resources.bicep new file mode 100644 index 000000000..1fd023349 --- /dev/null +++ b/src/templates/sre-agent/infra/resources.bicep @@ -0,0 +1,78 @@ +// Copied from microsoft/sre-agent labs/starter-lab/infra/resources.bicep and +// updated for the FinOps Toolkit SRE Agent template. + +@description('SRE Agent name.') +param agentName string + +@description('Location for all resources.') +param location string + +@description('Deterministic naming seed built from subscription ID, agent resource group ID, and agent name.') +param namingSeed string + +@description('Resource group IDs shown as managed resources in the SRE Agent.') +param targetResourceGroupIds array + +@description('Agent access level.') +param accessLevel string + +@description('Agent action mode.') +param actionMode string + +@description('Agent upgrade channel.') +param upgradeChannel string + +@description('Default SRE Agent model provider.') +param defaultModelProvider string + +@description('Default SRE Agent model name.') +param defaultModelName string + +@description('Monthly agent unit limit.') +param monthlyAgentUnitLimit int + +@description('Agent experimental settings.') +param experimentalSettings object + +@description('Azure resource tags.') +param tags object = {} + +var uniqueSuffix = uniqueString(namingSeed) +var logAnalyticsName = 'law-${uniqueSuffix}' +var appInsightsName = 'appi-${uniqueSuffix}' + +module monitoring 'modules/monitoring.bicep' = { + name: 'monitoring' + params: { + location: location + logAnalyticsName: logAnalyticsName + appInsightsName: appInsightsName + } +} + +module sreAgent 'modules/sre-agent.bicep' = { + name: 'sre-agent' + params: { + location: location + agentName: agentName + appInsightsAppId: monitoring.outputs.appInsightsAppId + appInsightsConnectionString: monitoring.outputs.appInsightsConnectionString + appInsightsId: monitoring.outputs.appInsightsId + managedResourceGroupIds: targetResourceGroupIds + accessLevel: accessLevel + actionMode: actionMode + upgradeChannel: upgradeChannel + defaultModelProvider: defaultModelProvider + defaultModelName: defaultModelName + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + tags: tags + } +} + +output agentName string = sreAgent.outputs.agentName +output agentEndpoint string = sreAgent.outputs.agentEndpoint +output agentPortalUrl string = sreAgent.outputs.agentPortalUrl +output agentPrincipalId string = sreAgent.outputs.agentPrincipalId +output agentTenantId string = sreAgent.outputs.agentTenantId +output logAnalyticsWorkspaceId string = monitoring.outputs.logAnalyticsWorkspaceId diff --git a/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 new file mode 100644 index 000000000..7a8db80ef --- /dev/null +++ b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 @@ -0,0 +1,306 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$ErrorActionPreference = 'Stop' + +function Get-RequiredEnv($Name) { + $value = [Environment]::GetEnvironmentVariable($Name) + if ([string]::IsNullOrWhiteSpace($value)) { + throw "Missing required environment variable: $Name" + } + return $value +} + +function Get-OptionalEnv($Name) { + return [Environment]::GetEnvironmentVariable($Name) +} + +function Get-TempRoot() { + $tempRoot = [System.IO.Path]::GetTempPath() + if ([string]::IsNullOrWhiteSpace($tempRoot)) { + $tempRoot = Get-OptionalEnv 'AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY' + } + if ([string]::IsNullOrWhiteSpace($tempRoot)) { + $tempRoot = (Get-Location).Path + } + return $tempRoot.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) +} + +function ConvertTo-BodyJson($Value) { + return ($Value | ConvertTo-Json -Depth 100 -Compress) +} + +function Get-PropertyValue($Object, [string[]]$Names, $Default = '') { + foreach ($name in $Names) { + if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) { + return $Object.$name + } + } + return $Default +} + +function Get-HttpStatusCode($Exception) { + if ($Exception.Response -and $Exception.Response.StatusCode) { + return [int]$Exception.Response.StatusCode + } + return $null +} + +function Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) { + for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) { + try { + return & $Action + } + catch { + $statusCode = Get-HttpStatusCode $_.Exception + if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) { + throw + } + if ($attempt -eq $MaxAttempts) { + throw + } + Write-Output "$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)" + Start-Sleep -Seconds $DelaySeconds + } + } +} + +function Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) { + $headers = @{ + Authorization = "Bearer $Token" + 'Content-Type' = 'application/json' + } + $parameters = @{ + Method = $Method + Uri = $Uri + Headers = $headers + } + if ($null -ne $Body) { + $parameters.Body = ConvertTo-BodyJson $Body + } + return Invoke-RestMethod @parameters +} + +function Get-KnowledgeSourceName([string]$FileName) { + $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-' + $name = $name -replace '-+', '-' + return $name.Trim('-') +} + +function Get-Collection($Value) { + if ($null -eq $Value) { + return @() + } + return @($Value) +} + +function Convert-TokenToString($Token) { + if ($Token -is [Security.SecureString]) { + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token) + try { + return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) + } + finally { + [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) + } + } + return [string]$Token +} + +function Get-ArmAccessTokenString() { + return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token +} + +function Get-SreAccessTokenString() { + return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token +} + +$subscriptionId = Get-RequiredEnv 'subscriptionId' +$resourceGroupName = Get-RequiredEnv 'resourceGroupName' +$agentName = Get-RequiredEnv 'agentName' +$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/') +$recipePackageUri = Get-RequiredEnv 'recipePackageUri' +$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri' +$armApiVersion = '2025-05-01-preview' +$armBase = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName" + +Write-Output 'Connecting with deployment script managed identity...' +Connect-AzAccount -Identity | Out-Null +Set-AzContext -Subscription $subscriptionId | Out-Null + +$tempRoot = Get-TempRoot +$workRoot = Join-Path $tempRoot 'sre-agent-recipe' +$zipPath = Join-Path $tempRoot 'sre-agent-recipe.zip' +Remove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue +New-Item -Path $workRoot -ItemType Directory -Force | Out-Null + +Write-Output "Downloading SRE Agent recipe package: $recipePackageUri" +Invoke-WithRetry -Label 'download recipe package' -Action { + Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath +} | Out-Null +Expand-Archive -Path $zipPath -DestinationPath $workRoot -Force + +$extrasPath = Join-Path $workRoot 'extras.json' +if (-not (Test-Path $extrasPath)) { + throw "Recipe package did not contain extras.json" +} + +$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100 +Write-Output "Loaded recipe package from $extrasPath" + +if ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) { + $extras.connectors = @( + Get-Collection $extras.connectors | Where-Object { + $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type') + $type -ine 'Kusto' + } + ) +} +else { + foreach ($connector in Get-Collection $extras.connectors) { + $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type') + if ($type -ieq 'Kusto') { + $connector.properties.dataSource = $kustoConnectorUri + if (-not $connector.properties.PSObject.Properties['identity']) { + $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system' + } + } + } +} + +function Invoke-ArmPutConnector([string]$Name, $Body) { + $uri = "$armBase/connectors/$Name`?api-version=$armApiVersion" + Invoke-WithRetry -Label "ARM PUT connector $Name" -Action { + Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body + } | Out-Null + Write-Output " ARM PUT connectors/${Name}: ok" +} + +function Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) { + $uri = "$agentEndpoint$Path" + return Invoke-WithRetry -Label "$Method $Path" -MaxAttempts 21 -DelaySeconds 30 -Action { + Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body + } +} + +function Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) { + $encodedName = [Uri]::EscapeDataString($Name) + $body = @{ + name = $Name + type = $Type + tags = @() + properties = $Properties + } + Invoke-SreApi -Method PUT -Path "/api/v2/extendedAgent/$Kind/$encodedName" -Body $body | Out-Null + Write-Output " PUT $Kind/${Name}: ok" +} + +Write-Output 'Step 1/7: Applying connectors...' +foreach ($connector in Get-Collection $extras.connectors) { + $name = [string]$connector.name + $properties = $connector.properties + if (-not $properties.PSObject.Properties['identity']) { + $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system' + } + Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties } +} + +Write-Output 'Step 2/7: Configuring built-in tools...' +$overrides = Get-Collection $extras.builtInTools.overrides +if ($overrides.Count -gt 0) { + $body = @{ + overrides = @($overrides | ForEach-Object { + @{ + name = $_.name + enabled = [bool]$_.enabled + } + }) + } + Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null + Write-Output " built-in tools configured: $($overrides.Count) overrides" +} + +Write-Output 'Step 3/7: Uploading knowledge sources...' +foreach ($item in Get-Collection $extras.knowledgeItems) { + $sourceName = Get-KnowledgeSourceName ([string]$item.name) + $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content) + $body = @{ + properties = @{ + dataConnectorType = 'KnowledgeFile' + dataSource = $sourceName + extendedProperties = @{ + displayName = [string]$item.name + fileName = [string]$item.name + fileContent = [Convert]::ToBase64String($bytes) + contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream') + } + } + } + Invoke-ArmPutConnector -Name $sourceName -Body $body + Start-Sleep -Seconds 5 +} + +Write-Output 'Step 4/7: Applying tools...' +foreach ($tool in Get-Collection $extras.tools) { + $name = [string]$tool.metadata.name + $properties = $tool.spec + if ($properties.type -eq 'PythonTool') { + $properties.type = 'PythonFunctionTool' + } + Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties +} + +Write-Output 'Step 5/7: Applying skills...' +foreach ($skill in Get-Collection $extras.skills) { + $name = [string]$skill.metadata.name + $tools = @() + if ($skill.metadata.spec -and $skill.metadata.spec.tools) { + $tools = Get-Collection $skill.metadata.spec.tools + } + $properties = @{ + name = $name + description = [string](Get-PropertyValue $skill.metadata @('description')) + tools = $tools + skillContent = [string](Get-PropertyValue $skill @('skillContent')) + additionalFiles = @() + } + Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties +} + +Write-Output 'Step 6/7: Applying subagents...' +foreach ($subagent in Get-Collection $extras.subagents) { + $name = [string]$subagent.metadata.name + Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec +} + +Write-Output 'Step 7/7: Applying scheduled tasks...' +$scheduledTasks = Get-Collection $extras.scheduledTasks +if ($scheduledTasks.Count -gt 0) { + $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks' + foreach ($task in $scheduledTasks) { + $name = [string]$task.metadata.name + foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) { + if ($match.id) { + Invoke-SreApi -Method DELETE -Path "/api/v1/scheduledtasks/$($match.id)" | Out-Null + Write-Output " deleted existing scheduledtasks/$name" + } + } + } + + foreach ($task in $scheduledTasks) { + $name = [string]$task.metadata.name + $spec = $task.spec + $properties = @{ + name = [string](Get-PropertyValue $spec @('name') $name) + description = [string](Get-PropertyValue $spec @('description')) + cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression')) + agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt')) + agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review') + isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true) + agent = [string](Get-PropertyValue $spec @('agent')) + } + Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties + } +} + +Write-Output 'SRE Agent extras complete.' diff --git a/src/templates/sre-agent/main.bicep b/src/templates/sre-agent/main.bicep new file mode 100644 index 000000000..fd4632140 --- /dev/null +++ b/src/templates/sre-agent/main.bicep @@ -0,0 +1,164 @@ +// One-click portal entry point for the FinOps Toolkit SRE Agent. +// The CLI path keeps using infra/main.bicep directly. + +targetScope = 'subscription' + +@description('Resource group that holds the SRE Agent resources.') +param resourceGroupName string + +@description('SRE Agent name.') +param agentName string + +@description('Primary location for all resources.') +@allowed(['australiaeast', 'canadacentral', 'eastus2', 'francecentral', 'koreacentral', 'swedencentral', 'uksouth']) +param location string = 'eastus2' + +@description('Resource groups the agent can observe or act on. The agent resource group is always included.') +param targetResourceGroups array = [] + +@description('Comma-separated resource groups the agent can observe or act on. Used by the Azure portal form.') +param targetResourceGroupNames string = '' + +@description('Optional database-qualified FinOps Hub Kusto connector URI. Example: https://..kusto.windows.net/Hub') +param finopsHubKustoConnectorUri string = '' + +@description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') +param finopsHubKustoClusterResourceId string = '' + +@description('Agent access level.') +@allowed(['Low', 'High']) +param accessLevel string = 'High' + +@description('Agent action mode.') +@allowed(['review', 'autonomous', 'readOnly']) +param actionMode string = 'autonomous' + +@description('Agent upgrade channel.') +@allowed(['Stable', 'Preview']) +param upgradeChannel string = 'Preview' + +@description('Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal.') +@allowed(['MicrosoftFoundry', 'Anthropic']) +param defaultModelProvider string = 'MicrosoftFoundry' + +@description('Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider.') +param defaultModelName string = 'Automatic' + +@description('Monthly agent unit limit.') +@minValue(1) +param monthlyAgentUnitLimit int = 10000 + +@description('Agent experimental settings.') +param experimentalSettings object = { + EnableSandboxGroup: true + EnableWorkspaceTools: true +} + +@description('Assign Reader on the deployment subscription to the agent managed identity.') +param enableSubscriptionReaderRole bool = true + +@description('Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI.') +param recipePackageUri string = uri(any(deployment()).properties.templateLink.uri, 'sre-agent-recipe.zip') + +@description('Forces the recipe deployment script to run when the template is redeployed.') +param forceUpdateTag string = utcNow() + +@description('Azure resource tags.') +param tags object = { + 'finops-toolkit': 'sre-agent' + source: 'microsoft-finops-toolkit' +} + +var rawTargetResourceGroups = split(replace(targetResourceGroupNames, ' ', ''), ',') +var parsedTargetResourceGroups = filter(rawTargetResourceGroups, rgName => !empty(rgName)) +var targetRgs = union([resourceGroupName], targetResourceGroups, parsedTargetResourceGroups) +var agentResourceGroupId = subscriptionResourceId('Microsoft.Resources/resourceGroups', resourceGroupName) +var targetRgIds = [for rgName in targetRgs: subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)] +var namingSeed = toLower('${subscription().subscriptionId}|${agentResourceGroupId}|${agentName}') +var readerRoleId = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' +var hasKustoCluster = !empty(finopsHubKustoClusterResourceId) +var kustoClusterSubscriptionId = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[2] : '' +var kustoClusterResourceGroupName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[4] : '' +var kustoClusterName = hasKustoCluster ? split(finopsHubKustoClusterResourceId, '/')[8] : '' + +resource rg 'Microsoft.Resources/resourceGroups@2024-03-01' = { + name: resourceGroupName + location: location + tags: tags +} + +module resources 'infra/resources.bicep' = { + name: 'resources-deployment' + scope: rg + params: { + agentName: agentName + location: location + namingSeed: namingSeed + targetResourceGroupIds: targetRgIds + accessLevel: accessLevel + actionMode: actionMode + upgradeChannel: upgradeChannel + defaultModelProvider: defaultModelProvider + defaultModelName: defaultModelName + monthlyAgentUnitLimit: monthlyAgentUnitLimit + experimentalSettings: experimentalSettings + tags: tags + } +} + +module targetRbac 'infra/modules/resource-group-rbac.bicep' = [for rgName in targetRgs: { + name: 'target-rbac-${uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)), namingSeed)}' + scope: resourceGroup(rgName) + params: { + principalId: resources.outputs.agentPrincipalId + accessLevel: accessLevel + } +}] + +resource subscriptionReaderRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableSubscriptionReaderRole) { + name: guid(subscription().id, namingSeed, readerRoleId) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', readerRoleId) + principalId: resources.outputs.agentPrincipalId + principalType: 'ServicePrincipal' + } +} + +module finopsHubKustoAllDatabasesViewerRbac 'infra/modules/kusto-all-databases-viewer-rbac.bicep' = if (hasKustoCluster) { + name: 'kusto-rbac-${uniqueString(finopsHubKustoClusterResourceId, namingSeed)}' + scope: resourceGroup(kustoClusterSubscriptionId, kustoClusterResourceGroupName) + params: { + clusterName: kustoClusterName + principalApplicationId: resources.outputs.agentPrincipalId + principalTenantId: tenant().tenantId + principalAssignmentName: 'sre-agent-${uniqueString(finopsHubKustoClusterResourceId, namingSeed, 'all-db-viewer')}' + } +} + +module applyExtras 'infra/modules/apply-extras.bicep' = { + name: 'apply-extras' + scope: rg + params: { + location: location + agentName: agentName + agentEndpoint: resources.outputs.agentEndpoint + subscriptionId: subscription().subscriptionId + recipePackageUri: recipePackageUri + kustoConnectorUri: finopsHubKustoConnectorUri + forceUpdateTag: forceUpdateTag + tags: tags + } + dependsOn: [ + targetRbac + ] +} + +output AZURE_RESOURCE_GROUP string = rg.name +output AZURE_LOCATION string = location +output SRE_AGENT_NAME string = resources.outputs.agentName +output SRE_AGENT_ENDPOINT string = resources.outputs.agentEndpoint +output AGENT_PORTAL_URL string = resources.outputs.agentPortalUrl +output SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID string = resources.outputs.agentPrincipalId +output SYSTEM_MANAGED_IDENTITY_TENANT_ID string = resources.outputs.agentTenantId +output LOG_ANALYTICS_WORKSPACE_ID string = resources.outputs.logAnalyticsWorkspaceId +output APPLY_EXTRAS_SCRIPT string = applyExtras.outputs.scriptName diff --git a/src/templates/sre-agent/package-manifest.json b/src/templates/sre-agent/package-manifest.json new file mode 100644 index 000000000..b3bde6c79 --- /dev/null +++ b/src/templates/sre-agent/package-manifest.json @@ -0,0 +1,21 @@ +{ + "deployment": { + "Files": [ + { + "sourceFolder": ".", + "source": "azuredeploy.json", + "destination": "azuredeploy.json" + }, + { + "sourceFolder": ".", + "source": "createUiDefinition.json", + "destination": "createUiDefinition.json" + }, + { + "sourceFolder": "assets", + "source": "sre-agent-recipe.zip", + "destination": "sre-agent-recipe.zip" + } + ] + } +} From a1f70086ec68190ee89de90093c157d628975739 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 07:53:07 -0700 Subject: [PATCH 04/19] fix(queries): remove markdown trailing whitespace --- src/queries/finops-hub-database-guide.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/queries/finops-hub-database-guide.md b/src/queries/finops-hub-database-guide.md index aebefa758..811513028 100644 --- a/src/queries/finops-hub-database-guide.md +++ b/src/queries/finops-hub-database-guide.md @@ -94,10 +94,10 @@ The FinOps hubs database is designed to support advanced cost and usage analytic - **Prefer scenario-specific aggregate queries first:** Use the query catalog to find the narrowest query that answers the question. Use [`costs-enriched-base`](./catalog/costs-enriched-base.kql) when you need scoped row-level enrichment or repeated drill-downs. -- **Use KQL (Kusto Query Language):** +- **Use KQL (Kusto Query Language):** All queries should be written in KQL for compatibility with Azure Data Explorer. -- **Leverage Enrichment Columns:** +- **Leverage Enrichment Columns:** Columns prefixed with `x_` provide additional context and enrichment for FinOps analysis. --- @@ -359,10 +359,10 @@ Costs() ## Table reference -> **Note:** +> **Note:** > All columns prefixed with `x_` are toolkit enrichment columns, providing additional context for FinOps analysis. -> **Numeric column types — live Hub behavior:** +> **Numeric column types — live Hub behavior:** > Columns documented below as `real` are exposed by the live Hub as `real` (a 64-bit floating-point type, equivalent to KQL `double` / .NET `System.Double`). Earlier versions of this guide listed numeric columns as `decimal`, but the deployed Hub schemas across `Costs()`, `Prices()`, and `Recommendations()` use `real`. When writing literal numeric defaults in KQL queries (for example the `false`-branch of an `iff(...)` aggregate), use `real(0)` — not `decimal(0)` — to avoid `SEM0019` arithmetic type-mismatch errors. Below are the column definitions for the main analytic tables in the FinOps hubs database. These definitions are based on Microsoft Learn, FinOps best practices, and common cloud cost management terminology. @@ -593,7 +593,7 @@ The following table lists the columns produced in the `All available columns` qu ### Recommendations() -> **Sparsely-populated columns:** +> **Sparsely-populated columns:** > The `Recommendations()` function is sourced from upstream optimization recommenders (for example, Azure Advisor reservation recommendations). Many string identifier columns below (`ResourceId`, `ResourceName`, `SubAccountId`, `SubAccountName`, `x_RecommendationId`, `x_RecommendationDescription`, `x_ResourceGroupName`) may be empty strings in practice if the source recommender does not surface them. Verify population with `Recommendations() | summarize count() by isnotempty()` before relying on a column as a join key or filter. | Column Name | Data Type | Description | From a01953052134bb13a0894a29f143c4cac838a815 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 07:54:46 -0700 Subject: [PATCH 05/19] fix(sre-agent): remove recipe whitespace --- .../scheduled-tasks/advisor-suppression-review.yaml | 1 - .../automations/scheduled-tasks/alert-coverage-audit.yaml | 1 - .../scheduled-tasks/benefit-recommendation-review.yaml | 1 - .../automations/scheduled-tasks/budget-coverage-audit.yaml | 1 - .../scheduled-tasks/compute-utilization-trend.yaml | 1 - .../scheduled-tasks/monitoring-scope-validation.yaml | 1 - .../references/Get-BenefitRecommendations.ps1 | 6 +++--- .../azure-cost-management/references/azure-advisor.md | 1 - .../references/azure-anomaly-alerts.md | 1 - .../finops-toolkit/references/tag-coverage-analysis.md | 2 +- 10 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml index 2f29f7102..573266364 100644 --- a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/advisor-suppression-review.yaml @@ -77,4 +77,3 @@ spec: Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a suppression status chart and a stale suppression age chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' - diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml index 88899f971..f9b6482f5 100644 --- a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/alert-coverage-audit.yaml @@ -81,4 +81,3 @@ spec: Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum an anomaly alert coverage chart and a missing alert count by owner or environment chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' - diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml index 2835091fe..85c40c48d 100644 --- a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/benefit-recommendation-review.yaml @@ -81,4 +81,3 @@ spec: Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a savings by recommendation type chart and a cost versus savings chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' - diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml index 50a856902..cd35b3dd9 100644 --- a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/budget-coverage-audit.yaml @@ -77,4 +77,3 @@ spec: Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a budget coverage by portfolio chart and a missing-budget count by environment chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' - diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml index 9e77d3005..0d4b69a2a 100644 --- a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/compute-utilization-trend.yaml @@ -81,4 +81,3 @@ spec: Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a utilization trend chart and a current headroom comparison chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' - diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml index 2ce1741f0..a0c6c92c9 100644 --- a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/monitoring-scope-validation.yaml @@ -85,4 +85,3 @@ spec: Before delivery, ask the selected delivery specialist to generate charts for key findings using `PlotBarChart`, `PlotPieChart`, or `PlotAreaChartWithCorrelation` when those visualization tools fit the data. Use `ExecutePythonCode` or matplotlib/seaborn via the code interpreter only when the visualization tools are unavailable or cannot express the required chart. Include at minimum a monitored versus unmonitored subscription chart and a data staleness chart where the data supports it. Verify each generated chart non-visually before embedding by checking the output file exists, has non-zero size, opens as an image, and reports expected dimensions and metadata through code interpreter filesystem or image-library checks. Do not use visual inspection as the verification gate; regenerate or omit any chart that fails these checks and state why. Embed chart images inline in the Teams message and attach or embed them in the Outlook email alongside the text tables.' - diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 index 95b45b9e6..6a0f890bd 100644 --- a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/Get-BenefitRecommendations.ps1 @@ -28,17 +28,17 @@ .EXAMPLE .\Get-BenefitRecommendations.ps1 -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" - + Gets 3-year savings plan recommendations for a subscription based on last 7 days usage. .EXAMPLE .\Get-BenefitRecommendations.ps1 -BillingScope "providers/Microsoft.Billing/billingAccounts/12345678" -LookBackPeriod "Last30Days" -Term "P1Y" - + Gets 1-year savings plan recommendations for a billing account based on last 30 days usage. .NOTES Requires Azure PowerShell module and Cost Management Reader permissions on the specified scope. - + To find your billing account: Get-AzBillingAccount To find subscriptions: Get-AzSubscription #> diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md index 4735c55e1..ba1d5ae48 100644 --- a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-advisor.md @@ -256,4 +256,3 @@ $recommendations | - [Cost recommendations](https://learn.microsoft.com/azure/advisor/advisor-cost-recommendations) - [Suppress recommendations](https://learn.microsoft.com/azure/advisor/view-recommendations#dismissing-and-postponing-recommendations) - [Advisor REST API](https://learn.microsoft.com/rest/api/advisor/) - diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md index 8aa95b594..0ef4bcaae 100644 --- a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-cost-management/references/azure-anomaly-alerts.md @@ -289,4 +289,3 @@ if ($confirm -eq 'y') { - [Cost anomaly alerts](https://learn.microsoft.com/azure/cost-management-billing/understand/analyze-unexpected-charges) - [Scheduled actions API](https://learn.microsoft.com/rest/api/cost-management/scheduled-actions) - diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md index bb740a7d7..1852f098b 100644 --- a/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/finops-toolkit/references/tag-coverage-analysis.md @@ -95,7 +95,7 @@ base | extend UntaggedCost = TotalCost - TaggedCost, TagCoverage = TaggedCost / TotalCost ``` - + Repeat the same pattern for any observed tag or field that matters to the business, such as `Tags['team']`, `Tags['application']`, `x_CostCenter`, or `x_Project`. If populated coverage is weak, say so directly. Blank values are an important finding. From c044e750cd1dd2246e49921b893973cfbc50469e Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 09:15:23 -0700 Subject: [PATCH 06/19] test(sre-agent): keep deployment tests with deploy slice --- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 1056 ----------------- 1 file changed, 1056 deletions(-) delete mode 100644 src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 deleted file mode 100644 index 6874aac05..000000000 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ /dev/null @@ -1,1056 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. - -Describe 'SRE Agent deploy template' { - BeforeAll { - $script:RepoRoot = (Get-Item -Path $PSScriptRoot).Parent.Parent.Parent.Parent.FullName - $script:DeployScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/deploy.sh' - $script:ApplyExtrasScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh' - $script:PostProvisionScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/post-provision.sh' - $script:VerifyScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh' - $script:RecipeDir = Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub' - $script:ScheduledTaskDir = Join-Path $script:RecipeDir 'automations/scheduled-tasks' - $script:OutputStylePath = Join-Path $script:RepoRoot 'src/templates/claude-plugin/output-styles/ftk-output-style.md' - $script:ReadmePath = Join-Path $script:RepoRoot 'src/templates/sre-agent/README.md' - $script:DocsPath = Join-Path $script:RepoRoot 'docs-mslearn/toolkit/sre-agent/deploy.md' - $script:AgentJsonPath = Join-Path $script:RecipeDir 'agent.json' - $script:SkipBash = -not (Get-Command bash -ErrorAction SilentlyContinue) - - function Invoke-BashCommand { - param( - [Parameter(Mandatory)] - [string] $Command - ) - - Push-Location $script:RepoRoot - try { - $output = & bash -lc $Command 2>&1 - [pscustomobject]@{ - ExitCode = $LASTEXITCODE - Output = ($output -join "`n") - } - } - finally { - Pop-Location - } - } - - function Invoke-BashCommandWithPath { - param( - [Parameter(Mandatory)] - [string] $Command, - - [Parameter(Mandatory)] - [string] $PathPrefix - ) - - Push-Location $script:RepoRoot - try { - $originalPath = $env:PATH - $env:PATH = "${PathPrefix}:$originalPath" - $output = & bash -c $Command 2>&1 - [pscustomobject]@{ - ExitCode = $LASTEXITCODE - Output = ($output -join "`n") - } - } - finally { - $env:PATH = $originalPath - Pop-Location - } - } - - function Set-BashStub { - param( - [Parameter(Mandatory)] - [string] $Path, - - [Parameter(Mandatory)] - [string] $Content - ) - - $utf8NoBom = [System.Text.UTF8Encoding]::new($false) - [System.IO.File]::WriteAllText($Path, ($Content -replace "`r`n", "`n"), $utf8NoBom) - & chmod +x $Path - } - } - - Context 'bash availability' { - It 'has bash available for hermetic tests' { - if ($script:SkipBash) { - Set-ItResult -Skipped -Because 'bash is unavailable' - } - $true | Should -BeTrue - } - } - - Context 'help and parsing' { - It 'prints help with portal labels and required flags' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:DeployScript' --help" - $result.ExitCode | Should -Be 0 - $result.Output | Should -Match 'Resource group' - $result.Output | Should -Match 'Agent name' - $result.Output | Should -Match 'Region' - $result.Output | Should -Match 'Subscription' - $result.Output | Should -Match '--cluster-uri' - } - - It 'documents the same help lines in README and docs' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $help = Invoke-BashCommand "bash '$script:DeployScript' --help" - $help.ExitCode | Should -Be 0 - $readme = Get-Content -Path $script:ReadmePath -Raw - $docs = Get-Content -Path $script:DocsPath -Raw - - @( - '--recipe ', - '--resource-group ', - '--name ', - '--location ', - '--subscription ', - '--cluster-uri ', - '--cluster-resource-id ', - '--deploy-name ' - ) | ForEach-Object { - $escaped = [regex]::Escape($_) - $help.Output | Should -Match $escaped - $readme | Should -Match $escaped - $docs | Should -Match $escaped - } - } - - It 'errors for each missing required recipe flag' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - - $cases = @( - @{ - Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --dry-run" - Match = 'subscription' - } - @{ - Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 --dry-run" - Match = 'resource-group' - } - @{ - Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x --dry-run" - Match = 'name' - } - @{ - Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x -n a --dry-run" - Match = 'location' - } - ) - - foreach ($case in $cases) { - $result = Invoke-BashCommand $case.Command - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match $case.Match - } - } - - It 'errors on unknown flags' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:DeployScript' --recipes '$script:RecipeDir' --dry-run" - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match 'unknown flag' - } - - It 'errors when a value-taking flag is missing its value' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' -g -n foo --dry-run" - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match 'requires a value' - } - - It 'errors when verify-agent expected config is missing its value' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --expected" - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match 'flag --expected requires a value' - $result.Output | Should -Not -Match 'unbound variable' - } - - It 'rejects unknown verify-agent arguments before Azure calls' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --bogus" - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match "unknown argument '--bogus'" - $result.Output | Should -Not -Match 'Could not resolve agent endpoint' - } - - It 'rejects the positional footgun' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:DeployScript' --dry-run rg-test" - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match 'unknown argument' - } - - It 'shows customer values and not maintainer defaults on happy-path dry-run' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" - $result.ExitCode | Should -Be 0 - $result.Output | Should -Match 'rg-test-customer' - $result.Output | Should -Match 'customer-sre-agent' - $result.Output | Should -Match 'westus3' - $result.Output | Should -Not -Match 'rg-finops-sre-agent|finops-sre-agent|eastus2' - } - - It 'uses a deterministic default deployment name across dry-runs' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - - $deployRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-deploy-name-" + [guid]::NewGuid().ToString('N')) - try { - $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" - $first = Invoke-BashCommand $command - $second = Invoke-BashCommand $command - - $first.ExitCode | Should -Be 0 - $second.ExitCode | Should -Be 0 - $firstPath = [regex]::Match($first.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() - $secondPath = [regex]::Match($second.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() - - $firstPath | Should -Be $secondPath - $firstPath | Should -Match 'sre-agent-customer-sre-agent-[a-f0-9]{12}' - - $parameters = Get-Content -Path $firstPath -Raw | ConvertFrom-Json - $parameters.parameters.upgradeChannel.value | Should -Be 'Preview' - $parameters.parameters.experimentalSettings.value.EnableSandboxGroup | Should -BeTrue - $parameters.parameters.experimentalSettings.value.EnableWorkspaceTools | Should -BeTrue - $parameters.parameters.monthlyAgentUnitLimit.value | Should -Be 10000 - } - finally { - Remove-Item -Path $deployRoot -Recurse -Force -ErrorAction SilentlyContinue - } - } - - It 'requires cluster resource ID for dry-run when a Kusto URI is provided' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - - $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --dry-run" - - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match '--cluster-resource-id is required with --cluster-uri for --dry-run' - } - - It 'auto-resolves the Kusto cluster resource ID before deployment' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - - $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-resolve-" + [guid]::NewGuid().ToString('N')) - $binDir = Join-Path $tempRoot 'bin' - $deployRoot = Join-Path $tempRoot 'deploy' - New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null - - $fakeAz = Join-Path $binDir 'az' - Set-BashStub -Path $fakeAz -Content @' -#!/usr/bin/env bash -set -euo pipefail - -if [[ "$*" == *"account get-access-token"* ]]; then - echo "fake-token" - exit 0 -fi - -if [[ "${1:-}" == "rest" ]]; then - echo "{}" - exit 0 -fi - -if [[ "$*" == *"resource list"* ]]; then - exit 0 -fi - -if [[ "$*" == *"graph query"* ]]; then - cat <<'JSON' -{ - "data": [ - { - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example" - } - ] -} -JSON - exit 0 -fi - -if [[ "$*" == *"deployment sub show"* ]]; then - cat <<'JSON' -{ - "properties": { - "provisioningState": "Succeeded", - "outputs": { - "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, - "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, - "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } - } - } -} -JSON - exit 0 -fi - -if [[ "$*" == *"deployment sub create"* ]]; then - cat <<'JSON' -{ - "properties": { - "provisioningState": "Succeeded", - "outputs": { - "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, - "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, - "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } - } - } -} -JSON - exit 0 -fi - -case "$*" in - *"account show"*|*"account set"*|*"provider register"*|*"version"*) - exit 0 - ;; -esac - -exit 0 -'@ - - $fakeCurl = Join-Path $binDir 'curl' - Set-BashStub -Path $fakeCurl -Content @' -#!/usr/bin/env bash -set -euo pipefail - -out="" -url="" -method="GET" -while [[ $# -gt 0 ]]; do - case "$1" in - -o) - out="$2" - shift 2 - ;; - -w) - shift 2 - ;; - -X) - method="$2" - shift 2 - ;; - -H|--data-binary) - shift 2 - ;; - http*) - url="$1" - shift - ;; - *) - shift - ;; - esac -done - -if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then - cat > "$out" <<'JSON' -{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} -JSON - printf "201" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then - cat > "$out" <<'JSON' -{ - "value": [ - { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } - ] -} -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then - cat > "$out" <<'JSON' -{ - "properties": { - "dataConnectorType": "KnowledgeFile", - "extendedProperties": { - "createdAt": "2026-05-25T19:57:31Z", - "lastModifiedAt": "2026-05-25T19:57:31Z" - } - } -} -JSON - if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi - exit 0 -fi - -if [[ "$url" == */api/v2/agent/tools/configure ]]; then - cat > "$out" <<'JSON' -{} -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v1/scheduledtasks ]]; then - cat > "$out" <<'JSON' -[] -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then - [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" - cat > "$out" <<'JSON' -{ - "type": "ExtendedAgent", - "properties": { - "provisioningState": "Succeeded" - } -} -JSON - printf "201" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then - cat > "$out" <<'JSON' -{ - "properties": { - "provisioningState": "Succeeded" - } -} -JSON - printf "201" - exit 0 -fi - -cat > "$out" <<'JSON' -{ - "files": [ - { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, - { "name": "document-index-md", "isIndexed": true, "errorReason": null }, - { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, - { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, - { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, - { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } - ], - "continuationToken": "" -} -JSON -printf "200" -'@ - - Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' -#!/usr/bin/env bash -exit 0 -'@ - - try { - $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://example.westus3.kusto.windows.net/Hub" - $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 - $result.Output | Should -Match 'Resolving Kusto cluster resource ID from --cluster-uri' - $result.Output | Should -Match '/providers/Microsoft\.Kusto/clusters/example' - - $parametersFile = (Get-ChildItem -Path $deployRoot -Recurse -Filter 'deploy.parameters.json' | Select-Object -First 1).FullName - $parametersFile | Should -Not -BeNullOrEmpty - $parameters = Get-Content -Path $parametersFile -Raw | ConvertFrom-Json - $parameters.parameters.finopsHubKustoClusterResourceId.value | Should -Be '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example' - } - finally { - Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue - } - } - - It 'warns but continues when the Kusto cluster denies public query access' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - - $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-private-" + [guid]::NewGuid().ToString('N')) - $binDir = Join-Path $tempRoot 'bin' - $deployRoot = Join-Path $tempRoot 'deploy' - New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null - - $fakeAz = Join-Path $binDir 'az' - Set-BashStub -Path $fakeAz -Content @' -#!/usr/bin/env bash -set -euo pipefail - -if [[ "$*" == *"account get-access-token"* ]]; then - echo "fake-token" - exit 0 -fi - -if [[ "${1:-}" == "rest" ]]; then - echo "{}" - exit 0 -fi - -if [[ "$*" == *"resource show"* ]]; then - cat <<'JSON' -{ - "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx", - "properties": { - "uri": "https://privateadx.westus.kusto.windows.net", - "publicNetworkAccess": "Disabled", - "privateEndpointConnections": [ - { - "name": "privateadx-ep", - "properties": { - "privateLinkServiceConnectionState": { - "status": "Approved" - } - } - } - ] - } -} -JSON - exit 0 -fi - -if [[ "$*" == *"deployment sub show"* ]]; then - cat <<'JSON' -{ - "properties": { - "provisioningState": "Succeeded", - "outputs": { - "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, - "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, - "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } - } - } -} -JSON - exit 0 -fi - -if [[ "$*" == *"deployment sub create"* ]]; then - cat <<'JSON' -{ - "properties": { - "provisioningState": "Succeeded", - "outputs": { - "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, - "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, - "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } - } - } -} -JSON - exit 0 -fi - -case "$*" in - *"account show"*|*"account set"*|*"provider register"*|*"version"*) - exit 0 - ;; -esac - -exit 0 -'@ - - $fakeCurl = Join-Path $binDir 'curl' - Set-BashStub -Path $fakeCurl -Content @' -#!/usr/bin/env bash -set -euo pipefail - -out="" -url="" -method="GET" -while [[ $# -gt 0 ]]; do - case "$1" in - -o) - out="$2" - shift 2 - ;; - -w) - shift 2 - ;; - -X) - method="$2" - shift 2 - ;; - -H|--data-binary) - shift 2 - ;; - http*) - url="$1" - shift - ;; - *) - shift - ;; - esac -done - -if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then - cat > "$out" <<'JSON' -{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} -JSON - printf "201" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then - cat > "$out" <<'JSON' -{ - "value": [ - { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } - ] -} -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then - cat > "$out" <<'JSON' -{ - "properties": { - "dataConnectorType": "KnowledgeFile", - "extendedProperties": { - "createdAt": "2026-05-25T19:57:31Z", - "lastModifiedAt": "2026-05-25T19:57:31Z" - } - } -} -JSON - if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi - exit 0 -fi - -if [[ "$url" == */api/v1/scheduledtasks ]]; then - cat > "$out" <<'JSON' -[] -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v2/agent/tools/configure ]]; then - cat > "$out" <<'JSON' -{} -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/agents/* || "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then - cat > "$out" <<'JSON' -{ - "properties": { - "provisioningState": "Succeeded" - } -} -JSON - printf "201" - exit 0 -fi - -cat > "$out" <<'JSON' -{} -JSON -printf "200" -'@ - - Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' -#!/usr/bin/env bash -exit 0 -'@ - - try { - $clusterId = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx' - $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://privateadx.westus.kusto.windows.net/Hub --cluster-resource-id $clusterId" - $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 - $result.Output | Should -Match 'Warning: The Kusto cluster denies public query access' - $result.Output | Should -Match 'private endpoint ADX blocks direct KQL queries' - $result.Output | Should -Match 'https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations' - $result.Output | Should -Match 'SRE Agent ready' - } - finally { - Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue - } - } - - It 'routes deploy through the copied starter-lab infra and apply-extras path' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - - $deployContent = Get-Content -Path $script:DeployScript -Raw - $deployContent | Should -Match 'INFRA_DIR=.*infra' - $deployContent | Should -Match '\$\{INFRA_DIR\}/main\.bicep' - $deployContent | Should -Match 'apply-extras\.sh' - $deployContent | Should -Not -Match 'bicep/assemble-agent|hydrate-extensions' - - Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') | Should -BeTrue - Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh') | Should -BeTrue - } - } - - Context 'repo invariants' { - It 'removes shipped recipe identity defaults' { - $agentJson = Get-Content -Path $script:AgentJsonPath -Raw - $agentJson | Should -Not -Match '"identity"' - } - - It 'uses the current SRE Agent API, model provider, and sandbox configuration' { - $agentJson = Get-Content -Path $script:AgentJsonPath -Raw | ConvertFrom-Json - $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw - $sreAgentBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/modules/sre-agent.bicep') -Raw - $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw - - $agentJson.upgradeChannel | Should -Be 'Preview' - $agentJson.defaultModelProvider | Should -Be 'MicrosoftFoundry' - $agentJson.defaultModelName | Should -Be 'Automatic' - $agentJson.experimentalSettings.EnableSandboxGroup | Should -BeTrue - $agentJson.experimentalSettings.EnableWorkspaceTools | Should -BeTrue - $sreAgentBicep | Should -Match 'Microsoft\.App/agents@2026-01-01' - $sreAgentBicep | Should -Not -Match 'Microsoft\.App/agents@2025-05-01-preview' - $sreAgentBicep | Should -Match 'defaultModel:' - $sreAgentBicep | Should -Match 'provider: defaultModelProvider' - $sreAgentBicep | Should -Match 'name: defaultModelName' - $sreAgentBicep | Should -Match 'upgradeChannel: upgradeChannel' - $mainBicep | Should -Match 'defaultModelProvider' - $mainBicep | Should -Match 'defaultModelName' - $mainBicep | Should -Match 'EnableSandboxGroup' - $mainBicep | Should -Match 'EnableWorkspaceTools' - $verifyScript | Should -Match 'API_VERSION="2026-01-01"' - } - - It 'limits legacy config env-var references to the allowlist' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" - $result.ExitCode | Should -Be 0 - - $paths = $result.Output -split "`n" | - Where-Object { $_ } | - ForEach-Object { ($_ -split ':', 2)[0] } | - Sort-Object -Unique - - $paths | Should -Be @( - 'docs-mslearn/toolkit/sre-agent/deploy.md', - 'src/templates/sre-agent/bin/build-extras.py', - 'src/templates/sre-agent/README.md', - 'src/templates/sre-agent/recipes/finops-hub/connectors.json' - ) - } - - It 'keeps connectors.secrets.env out of scripts' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "git grep -nE 'connectors\.secrets\.env' -- src/templates/sre-agent/bin src/templates/sre-agent/infra" - $result.ExitCode | Should -Be 1 - } - - It 'removes the legacy custom bicep deployment surface' { - Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bicep') | Should -BeFalse - Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/hydrate-extensions.sh') | Should -BeFalse - } - - It 'uses deterministic subscription and resource group identity for support resource names' { - $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw - $resourcesBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/resources.bicep') -Raw - - $mainBicep | Should -Match "agentResourceGroupId = subscriptionResourceId\('Microsoft\.Resources/resourceGroups', resourceGroupName\)" - $mainBicep | Should -Match 'namingSeed = toLower' - $mainBicep | Should -Match 'subscription\(\)\.subscriptionId' - $mainBicep | Should -Match 'agentResourceGroupId' - $mainBicep | Should -Match 'agentName' - - $resourcesBicep | Should -Match 'param namingSeed string' - $resourcesBicep | Should -Match 'uniqueSuffix = uniqueString\(namingSeed\)' - $resourcesBicep | Should -Not -Match 'resourceGroup\(\)\.id|deployment\(\)\.name' - } - - It 'applies subagents after their local handoff targets' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - - $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-post-provision-" + [guid]::NewGuid().ToString('N')) - $binDir = Join-Path $tempRoot 'bin' - $buildDir = Join-Path $tempRoot 'build' - $logPath = Join-Path $tempRoot 'agent-apply.log' - New-Item -ItemType Directory -Force -Path $binDir, $buildDir | Out-Null - - $fakeAz = Join-Path $binDir 'az' - Set-BashStub -Path $fakeAz -Content @' -#!/usr/bin/env bash -set -euo pipefail - -if [[ "$*" == *"account get-access-token"* ]]; then - echo "fake-token" - exit 0 -fi - -if [[ "${1:-}" == "rest" ]]; then - echo "{}" - exit 0 -fi - -case "$*" in - *"account show"*|*"account set"*|*"version"*) - exit 0 - ;; -esac - -exit 1 -'@ - - $fakeCurl = Join-Path $binDir 'curl' - Set-BashStub -Path $fakeCurl -Content @' -#!/usr/bin/env bash -set -euo pipefail - -out="" -url="" -method="GET" -while [[ $# -gt 0 ]]; do - case "$1" in - -o) - out="$2" - shift 2 - ;; - -w) - shift 2 - ;; - -X) - method="$2" - shift 2 - ;; - -H|--data-binary) - shift 2 - ;; - http*) - url="$1" - shift - ;; - *) - shift - ;; - esac -done - -if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then - cat > "$out" <<'JSON' -{ - "value": [ - { "name": "chart-artifact-verification-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "document-index-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "ftk-output-style-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "known-issues-and-workarounds-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "onboarding-recommendations-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, - { "name": "teams-notification-guide-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } - ] -} -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then - cat > "$out" <<'JSON' -{ - "type": "KnowledgeItem", - "properties": { - "dataConnectorType": "KnowledgeFile", - "extendedProperties": { - "createdAt": "2026-05-25T19:57:31Z", - "lastModifiedAt": "2026-05-25T19:57:31Z" - } - } -} -JSON - if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then - [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" - cat > "$out" <<'JSON' -{ - "type": "ExtendedAgent", - "properties": { - "provisioningState": "Succeeded" - } -} -JSON - printf "201" - exit 0 -fi - -if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then - cat > "$out" <<'JSON' -{ - "properties": { - "provisioningState": "Succeeded" - } -} -JSON - printf "201" - exit 0 -fi - -if [[ "$url" == */api/v2/agent/tools/configure ]]; then - cat > "$out" <<'JSON' -{} -JSON - printf "200" - exit 0 -fi - -if [[ "$url" == */api/v1/scheduledtasks ]]; then - cat > "$out" <<'JSON' -[] -JSON - printf "200" - exit 0 -fi - -cat > "$out" <<'JSON' -{ - "files": [ - { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, - { "name": "document-index-md", "isIndexed": true, "errorReason": null }, - { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, - { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, - { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, - { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } - ], - "continuationToken": "" -} -JSON -printf "200" -'@ - - Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' -#!/usr/bin/env bash -exit 0 -'@ - - try { - $command = "AGENT_APPLY_LOG='$logPath' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:PostProvisionScript' --endpoint https://example.azuresre.ai --subscription 00000000-0000-0000-0000-000000000000 --resource-group rg-test-customer --name customer-sre-agent --recipe '$script:RecipeDir' --build-dir '$buildDir'" - $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 - - $order = @(Get-Content -Path $logPath) - [array]::IndexOf($order, 'chief-financial-officer') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) - [array]::IndexOf($order, 'ftk-database-query') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) - [array]::IndexOf($order, 'ftk-hubs-agent') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) - } - finally { - Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue - } - } - - It 'derives expected recipe connectors for verification' { - $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw - - $verifyScript | Should -Match 'connectors\.json' - $verifyScript | Should -Match 'EXPECTED_CONNECTORS' - $verifyScript | Should -Match 'EXP_CONN_CT=.*EXPECTED_CONNECTORS' - $verifyScript | Should -Match 'EXP_CONN_NAMES=.*EXPECTED_CONNECTORS' - } - - It 'uploads the shared FinOps output style as a portal knowledge source' { - $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw - $buildExtrasScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/build-extras.py') -Raw - - Test-Path $script:OutputStylePath | Should -BeTrue - $buildExtrasScript | Should -Match 'claude-plugin/output-styles/ftk-output-style\.md' - $buildExtrasScript | Should -Match 'Output style knowledge document not found' - $applyExtrasScript | Should -Match 'knowledgeItems' - $applyExtrasScript | Should -Match '/api/v2/extendedAgent/connectors' - $applyExtrasScript | Should -Match 'Knowledge sources failed to index' - $applyExtrasScript | Should -Match 'KnowledgeFile' - $applyExtrasScript | Should -Not -Match ('sr' + 'ectl') - $applyExtrasScript | Should -Not -Match '/api/v1/agentmemory/files' - } - - It 'requires expected knowledge sources and verifies indexing' { - $expectedConfig = Get-Content -Path (Join-Path $script:RecipeDir 'expected-config.json') -Raw | ConvertFrom-Json - $verifyScript = Get-Content -Path $script:VerifyScript -Raw - - $expectedConfig.knowledgeSources.Count | Should -Be 6 - $expectedConfig.knowledgeSources | Should -Contain 'ftk-output-style.md' - $expectedConfig.PSObject.Properties.Name | Should -Not -Contain 'knowledgeDocs' - $verifyScript | Should -Match '/api/v2/extendedAgent/connectors' - $verifyScript | Should -Match '\$expected\[\] \| \. as \$name \| select\(\$actual \| index\(\$name\)\)' - $verifyScript | Should -Match 'Knowledge sources expected' - $verifyScript | Should -Match 'Knowledge sources indexed' - $verifyScript | Should -Match 'Unindexed knowledge sources' - $verifyScript | Should -Not -Match '/api/v1/agentmemory' - $verifyScript | Should -Not -Match '"knowledge_" \+' - $verifyScript | Should -Not -Match 'Knowledge connector rows' - } - - It 'does not duplicate response plan verification with dead incident-filter scan state' { - $verifyScript = Get-Content -Path $script:VerifyScript -Raw - - ([regex]::Matches($verifyScript, 'check "Filter names"')).Count | Should -Be 1 - $verifyScript | Should -Not -Match 'EXP_FILTERS' - $verifyScript | Should -Not -Match 'automations/incident-filters' - } - - It 'requires every scheduled task to apply the shared output style' { - $taskFiles = @(Get-ChildItem -Path $script:ScheduledTaskDir -Filter '*.yaml') - $taskFiles.Count | Should -Be 19 - - $expectedInstruction = [regex]::Escape('Output style: Apply `ftk-output-style.md`') - foreach ($file in $taskFiles) { - $content = Get-Content -Path $file.FullName -Raw - $content | Should -Match $expectedInstruction - } - } - - It 'deletes existing scheduled tasks before applying manifests' { - $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw - $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw - - $applyExtrasScript | Should -Match 'delete_existing_scheduled_tasks' - $applyExtrasScript | Should -Match '/api/v1/scheduledtasks' - $applyExtrasScript | Should -Match 'dataplane_put_extended "scheduledtasks"' - $verifyScript | Should -Match 'Scheduled task duplicates' - $verifyScript | Should -Match '0 duplicates' - } - - It 'extends the shared output style for Azure capacity management' { - $outputStyle = Get-Content -Path $script:OutputStylePath -Raw - - $outputStyle | Should -Match 'Azure capacity management reporting' - $outputStyle | Should -Match 'Forecast' - $outputStyle | Should -Match 'Procure' - $outputStyle | Should -Match 'Allocate' - $outputStyle | Should -Match 'Monitor' - $outputStyle | Should -Match 'Capacity reservation group' - $outputStyle | Should -Match 'Quota group' - $outputStyle | Should -Match 'Logical zone' - $outputStyle | Should -Match 'CRG utilization' - } - } - - Context 'copy-and-update deployment contract' { - It 'rejects what-if because the copied starter-lab flow deploys directly' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test -n test-agent -l westus3 --what-if" - $result.ExitCode | Should -Be 2 - $result.Output | Should -Match 'unknown flag' - } - - It 'documents that azd is not used' { - if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "git grep -nF 'azd' -- src/templates/sre-agent/bin src/templates/sre-agent/infra docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent/README.md" - $result.Output | Should -Match 'azd' - $result.Output | Should -Match 'not used|doesn''t use' - } - } -} From 05601e681f02c8832f939208dc61c31ce32a8739 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 09:35:27 -0700 Subject: [PATCH 07/19] fix(sre-agent): keep deploy checks in deploy slice --- docs-mslearn/toolkit/changelog.md | 2 +- docs-mslearn/toolkit/hubs/configure-sre.md | 2 +- docs-mslearn/toolkit/sre-agent/agents.md | 2 +- docs-mslearn/toolkit/sre-agent/deploy.md | 2 +- docs-mslearn/toolkit/sre-agent/get-started.md | 2 +- docs-mslearn/toolkit/sre-agent/knowledge.md | 2 +- docs-mslearn/toolkit/sre-agent/kusto-tools.md | 2 +- docs-mslearn/toolkit/sre-agent/overview.md | 2 +- .../toolkit/sre-agent/python-tools.md | 2 +- .../toolkit/sre-agent/scheduled-tasks.md | 2 +- docs-mslearn/toolkit/sre-agent/security.md | 2 +- docs-mslearn/toolkit/sre-agent/template.md | 2 +- docs-mslearn/toolkit/sre-agent/tools.md | 2 +- .../toolkit/sre-agent/troubleshooting.md | 2 +- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 1043 +++++++++++++++++ 15 files changed, 1057 insertions(+), 14 deletions(-) create mode 100644 src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 diff --git a/docs-mslearn/toolkit/changelog.md b/docs-mslearn/toolkit/changelog.md index 6c538b1f8..c46cd6c5d 100644 --- a/docs-mslearn/toolkit/changelog.md +++ b/docs-mslearn/toolkit/changelog.md @@ -3,7 +3,7 @@ title: FinOps toolkit changelog description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more. author: MSBrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md index cf9800933..37f888dcd 100644 --- a/docs-mslearn/toolkit/hubs/configure-sre.md +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -3,7 +3,7 @@ title: Configure an SRE agent for FinOps hubs description: Learn how to configure an Azure SRE agent to connect to your FinOps hub for scheduled cost analysis, capacity monitoring, and reporting. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md index 1257c7b15..5411f4bb6 100644 --- a/docs-mslearn/toolkit/sre-agent/agents.md +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -3,7 +3,7 @@ title: Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) description: Understand how the FinOps toolkit configures Azure SRE Agent with specialist agents, tools, skills, and knowledge to automate FinOps and capacity management work. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md index 3e135a6fe..88e0c3dcc 100644 --- a/docs-mslearn/toolkit/sre-agent/deploy.md +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -3,7 +3,7 @@ title: Deploy Azure SRE Agent with the FinOps toolkit description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: tutorial ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md index 7aba04595..5b2981737 100644 --- a/docs-mslearn/toolkit/sre-agent/get-started.md +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -3,7 +3,7 @@ title: Get started with the FinOps toolkit on Azure SRE Agent description: Learn what to do after deploying Azure SRE Agent with the FinOps toolkit — first queries, scheduled tasks, and specialized subagents. author: flanakin ms.author: micflan -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: quickstart ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md index 7578736c3..9a94d8dda 100644 --- a/docs-mslearn/toolkit/sre-agent/knowledge.md +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -3,7 +3,7 @@ title: Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) description: Learn how knowledge grounds the FinOps toolkit's Azure SRE Agent in your team's context and how memory keeps operational learnings available across sessions and redeployments. author: msbrett ms.author: brettwil -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md index 7c2ca749b..19dfe39da 100644 --- a/docs-mslearn/toolkit/sre-agent/kusto-tools.md +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -3,7 +3,7 @@ title: Kusto tools description: Review the FinOps hub Kusto tools the FinOps toolkit ships for Azure SRE Agent and learn when to use each tool for cost, commitment discount, anomaly, forecast, AI, and price analysis. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md index 97a739e9e..c7240abbf 100644 --- a/docs-mslearn/toolkit/sre-agent/overview.md +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -3,7 +3,7 @@ title: Azure SRE Agent in the FinOps toolkit description: Learn how the FinOps toolkit deploys Azure SRE Agent with FinOps and capacity management automation on top of FinOps hubs. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md index 7def2af39..1de0cce9f 100644 --- a/docs-mslearn/toolkit/sre-agent/python-tools.md +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -3,7 +3,7 @@ title: Python tools description: Review the Python tools the FinOps toolkit ships for Azure SRE Agent for Azure quota, capacity, budgets, anomaly alerts, Resource Graph, FinOps hub health, and Advisor suppressions. author: msbrett ms.author: brettwil -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md index 7862eaa6c..f98f3e14a 100644 --- a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -3,7 +3,7 @@ title: Scheduled tasks (Azure SRE Agent in the FinOps toolkit) description: Learn how the FinOps toolkit's scheduled tasks automate daily, weekly, monthly, and quarterly FinOps operating rhythms on Azure SRE Agent. author: msbrett ms.author: brettwil -ms.date: 05/25/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/security.md b/docs-mslearn/toolkit/sre-agent/security.md index 3aa3109bb..f4b7e0f6b 100644 --- a/docs-mslearn/toolkit/sre-agent/security.md +++ b/docs-mslearn/toolkit/sre-agent/security.md @@ -3,7 +3,7 @@ title: Security and permissions for Azure SRE Agent in the FinOps toolkit description: Review the permissions, identities, run modes, and data flows the FinOps toolkit configures on Azure SRE Agent before you deploy it in your environment. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/template.md b/docs-mslearn/toolkit/sre-agent/template.md index 79e4c00a7..25c7474c6 100644 --- a/docs-mslearn/toolkit/sre-agent/template.md +++ b/docs-mslearn/toolkit/sre-agent/template.md @@ -3,7 +3,7 @@ title: Azure SRE Agent template reference (FinOps toolkit) description: Review the FinOps toolkit's Azure SRE Agent deployment template, parameters, outputs, script flags, and Bicep module structure. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/tools.md b/docs-mslearn/toolkit/sre-agent/tools.md index 429a08d50..a8447b62f 100644 --- a/docs-mslearn/toolkit/sre-agent/tools.md +++ b/docs-mslearn/toolkit/sre-agent/tools.md @@ -3,7 +3,7 @@ title: Tools shipped for Azure SRE Agent in the FinOps toolkit description: Review the Kusto and Python tools the FinOps toolkit ships for Azure SRE Agent for cost analysis, anomaly detection, rate optimization, capacity management, and operations. author: msbrett ms.author: brettwil -ms.date: 06/01/2026 +ms.date: 06/03/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/troubleshooting.md b/docs-mslearn/toolkit/sre-agent/troubleshooting.md index 4f029c16a..53a5af68c 100644 --- a/docs-mslearn/toolkit/sre-agent/troubleshooting.md +++ b/docs-mslearn/toolkit/sre-agent/troubleshooting.md @@ -3,7 +3,7 @@ title: Troubleshoot Azure SRE Agent deployments from the FinOps toolkit description: Resolve common deployment, tenant, connector, data, and query issues for Azure SRE Agent deployments from the FinOps toolkit. author: msbrett ms.author: brettwil -ms.date: 06/02/2026 +ms.date: 06/03/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 new file mode 100644 index 000000000..b1042a83f --- /dev/null +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -0,0 +1,1043 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'SRE Agent deploy template' { + BeforeAll { + $script:RepoRoot = (Get-Item -Path $PSScriptRoot).Parent.Parent.Parent.Parent.FullName + $script:DeployScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/deploy.sh' + $script:ApplyExtrasScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh' + $script:PostProvisionScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/post-provision.sh' + $script:VerifyScript = Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh' + $script:RecipeDir = Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub' + $script:ScheduledTaskDir = Join-Path $script:RecipeDir 'automations/scheduled-tasks' + $script:OutputStylePath = Join-Path $script:RepoRoot 'src/templates/claude-plugin/output-styles/ftk-output-style.md' + $script:ReadmePath = Join-Path $script:RepoRoot 'src/templates/sre-agent/README.md' + $script:DocsPath = Join-Path $script:RepoRoot 'docs-mslearn/toolkit/sre-agent/deploy.md' + $script:AgentJsonPath = Join-Path $script:RecipeDir 'agent.json' + $script:SkipBash = -not (Get-Command bash -ErrorAction SilentlyContinue) + + function Invoke-BashCommand { + param( + [Parameter(Mandatory)] + [string] $Command + ) + + Push-Location $script:RepoRoot + try { + $output = & bash -lc $Command 2>&1 + [pscustomobject]@{ + ExitCode = $LASTEXITCODE + Output = ($output -join "`n") + } + } + finally { + Pop-Location + } + } + + function Invoke-BashCommandWithPath { + param( + [Parameter(Mandatory)] + [string] $Command, + + [Parameter(Mandatory)] + [string] $PathPrefix + ) + + Push-Location $script:RepoRoot + try { + $originalPath = $env:PATH + $env:PATH = "${PathPrefix}:$originalPath" + $output = & bash -c $Command 2>&1 + [pscustomobject]@{ + ExitCode = $LASTEXITCODE + Output = ($output -join "`n") + } + } + finally { + $env:PATH = $originalPath + Pop-Location + } + } + + function Set-BashStub { + param( + [Parameter(Mandatory)] + [string] $Path, + + [Parameter(Mandatory)] + [string] $Content + ) + + $utf8NoBom = [System.Text.UTF8Encoding]::new($false) + [System.IO.File]::WriteAllText($Path, ($Content -replace "`r`n", "`n"), $utf8NoBom) + & chmod +x $Path + } + } + + Context 'bash availability' { + It 'has bash available for hermetic tests' { + if ($script:SkipBash) { + Set-ItResult -Skipped -Because 'bash is unavailable' + } + $true | Should -BeTrue + } + } + + Context 'help and parsing' { + It 'prints help with portal labels and required flags' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --help" + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Resource group' + $result.Output | Should -Match 'Agent name' + $result.Output | Should -Match 'Region' + $result.Output | Should -Match 'Subscription' + $result.Output | Should -Match '--cluster-uri' + } + + It 'documents the same help lines in README and docs' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $help = Invoke-BashCommand "bash '$script:DeployScript' --help" + $help.ExitCode | Should -Be 0 + $readme = Get-Content -Path $script:ReadmePath -Raw + $docs = Get-Content -Path $script:DocsPath -Raw + + @( + '--recipe ', + '--resource-group ', + '--name ', + '--location ', + '--subscription ', + '--cluster-uri ', + '--cluster-resource-id ', + '--deploy-name ' + ) | ForEach-Object { + $escaped = [regex]::Escape($_) + $help.Output | Should -Match $escaped + $readme | Should -Match $escaped + $docs | Should -Match $escaped + } + } + + It 'errors for each missing required recipe flag' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $cases = @( + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --dry-run" + Match = 'subscription' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 --dry-run" + Match = 'resource-group' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x --dry-run" + Match = 'name' + } + @{ + Command = "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-x -n a --dry-run" + Match = 'location' + } + ) + + foreach ($case in $cases) { + $result = Invoke-BashCommand $case.Command + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match $case.Match + } + } + + It 'errors on unknown flags' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipes '$script:RecipeDir' --dry-run" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown flag' + } + + It 'errors when a value-taking flag is missing its value' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' -g -n foo --dry-run" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'requires a value' + } + + It 'errors when verify-agent expected config is missing its value' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --expected" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'flag --expected requires a value' + $result.Output | Should -Not -Match 'unbound variable' + } + + It 'rejects unknown verify-agent arguments before Azure calls' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:VerifyScript' 00000000-0000-0000-0000-000000000000 rg-test test-agent --bogus" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match "unknown argument '--bogus'" + $result.Output | Should -Not -Match 'Could not resolve agent endpoint' + } + + It 'rejects the positional footgun' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --dry-run rg-test" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown argument' + } + + It 'shows customer values and not maintainer defaults on happy-path dry-run' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'rg-test-customer' + $result.Output | Should -Match 'customer-sre-agent' + $result.Output | Should -Match 'westus3' + $result.Output | Should -Not -Match 'rg-finops-sre-agent|finops-sre-agent|eastus2' + } + + It 'uses a deterministic default deployment name across dry-runs' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-deploy-name-" + [guid]::NewGuid().ToString('N')) + try { + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --cluster-resource-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-test/providers/Microsoft.Kusto/clusters/fake --dry-run" + $first = Invoke-BashCommand $command + $second = Invoke-BashCommand $command + + $first.ExitCode | Should -Be 0 + $second.ExitCode | Should -Be 0 + $firstPath = [regex]::Match($first.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() + $secondPath = [regex]::Match($second.Output, 'Parameters:\s+(.+)').Groups[1].Value.Trim() + + $firstPath | Should -Be $secondPath + $firstPath | Should -Match 'sre-agent-customer-sre-agent-[a-f0-9]{12}' + + $parameters = Get-Content -Path $firstPath -Raw | ConvertFrom-Json + $parameters.parameters.upgradeChannel.value | Should -Be 'Preview' + $parameters.parameters.experimentalSettings.value.EnableSandboxGroup | Should -BeTrue + $parameters.parameters.experimentalSettings.value.EnableWorkspaceTools | Should -BeTrue + $parameters.parameters.monthlyAgentUnitLimit.value | Should -Be 10000 + } + finally { + Remove-Item -Path $deployRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'requires cluster resource ID for dry-run when a Kusto URI is provided' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l westus3 --cluster-uri https://example.westus3.kusto.windows.net/Hub --dry-run" + + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match '--cluster-resource-id is required with --cluster-uri for --dry-run' + } + + It 'auto-resolves the Kusto cluster resource ID before deployment' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-resolve-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $deployRoot = Join-Path $tempRoot 'deploy' + New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +if [[ "$*" == *"resource list"* ]]; then + exit 0 +fi + +if [[ "$*" == *"graph query"* ]]; then + cat <<'JSON' +{ + "data": [ + { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example" + } + ] +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub show"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub create"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"provider register"*|*"version"*) + exit 0 + ;; +esac + +exit 0 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then + cat > "$out" <<'JSON' +{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then + [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" + cat > "$out" <<'JSON' +{ + "type": "ExtendedAgent", + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +cat > "$out" <<'JSON' +{ + "files": [ + { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, + { "name": "document-index-md", "isIndexed": true, "errorReason": null }, + { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, + { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, + { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, + { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } + ], + "continuationToken": "" +} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://example.westus3.kusto.windows.net/Hub" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Resolving Kusto cluster resource ID from --cluster-uri' + $result.Output | Should -Match '/providers/Microsoft\.Kusto/clusters/example' + + $parametersFile = (Get-ChildItem -Path $deployRoot -Recurse -Filter 'deploy.parameters.json' | Select-Object -First 1).FullName + $parametersFile | Should -Not -BeNullOrEmpty + $parameters = Get-Content -Path $parametersFile -Raw | ConvertFrom-Json + $parameters.parameters.finopsHubKustoClusterResourceId.value | Should -Be '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/example' + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'warns but continues when the Kusto cluster denies public query access' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-kusto-private-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $deployRoot = Join-Path $tempRoot 'deploy' + New-Item -ItemType Directory -Force -Path $binDir, $deployRoot | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +if [[ "$*" == *"resource show"* ]]; then + cat <<'JSON' +{ + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx", + "properties": { + "uri": "https://privateadx.westus.kusto.windows.net", + "publicNetworkAccess": "Disabled", + "privateEndpointConnections": [ + { + "name": "privateadx-ep", + "properties": { + "privateLinkServiceConnectionState": { + "status": "Approved" + } + } + } + ] + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub show"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +if [[ "$*" == *"deployment sub create"* ]]; then + cat <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded", + "outputs": { + "SRE_AGENT_ENDPOINT": { "value": "https://example.azuresre.ai" }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { "value": "00000000-0000-0000-0000-000000000001" }, + "AGENT_PORTAL_URL": { "value": "https://sre.azure.com/#/agent/00000000-0000-0000-0000-000000000000/rg-test-customer/customer-sre-agent" } + } + } +} +JSON + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"provider register"*|*"version"*) + exit 0 + ;; +esac + +exit 0 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors/finops-hub-kusto ]]; then + cat > "$out" <<'JSON' +{"name":"finops-hub-kusto","properties":{"dataConnectorType":"Kusto"}} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* || "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +cat > "$out" <<'JSON' +{} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $clusterId = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx' + $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://privateadx.westus.kusto.windows.net/Hub --cluster-resource-id $clusterId" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + $result.Output | Should -Match 'Warning: The Kusto cluster denies public query access' + $result.Output | Should -Match 'private endpoint ADX blocks direct KQL queries' + $result.Output | Should -Match 'https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations' + $result.Output | Should -Match 'SRE Agent ready' + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'routes deploy through the copied starter-lab infra and apply-extras path' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployContent = Get-Content -Path $script:DeployScript -Raw + $deployContent | Should -Match 'INFRA_DIR=.*infra' + $deployContent | Should -Match '\$\{INFRA_DIR\}/main\.bicep' + $deployContent | Should -Match 'apply-extras\.sh' + $deployContent | Should -Not -Match 'bicep/assemble-agent|hydrate-extensions' + + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') | Should -BeTrue + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/apply-extras.sh') | Should -BeTrue + } + } + + Context 'repo invariants' { + It 'removes shipped recipe identity defaults' { + $agentJson = Get-Content -Path $script:AgentJsonPath -Raw + $agentJson | Should -Not -Match '"identity"' + } + + It 'uses the current SRE Agent API, model provider, and sandbox configuration' { + $agentJson = Get-Content -Path $script:AgentJsonPath -Raw | ConvertFrom-Json + $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $sreAgentBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/modules/sre-agent.bicep') -Raw + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $agentJson.upgradeChannel | Should -Be 'Preview' + $agentJson.defaultModelProvider | Should -Be 'MicrosoftFoundry' + $agentJson.defaultModelName | Should -Be 'Automatic' + $agentJson.experimentalSettings.EnableSandboxGroup | Should -BeTrue + $agentJson.experimentalSettings.EnableWorkspaceTools | Should -BeTrue + $sreAgentBicep | Should -Match 'Microsoft\.App/agents@2026-01-01' + $sreAgentBicep | Should -Not -Match 'Microsoft\.App/agents@2025-05-01-preview' + $sreAgentBicep | Should -Match 'defaultModel:' + $sreAgentBicep | Should -Match 'provider: defaultModelProvider' + $sreAgentBicep | Should -Match 'name: defaultModelName' + $sreAgentBicep | Should -Match 'upgradeChannel: upgradeChannel' + $mainBicep | Should -Match 'defaultModelProvider' + $mainBicep | Should -Match 'defaultModelName' + $mainBicep | Should -Match 'EnableSandboxGroup' + $mainBicep | Should -Match 'EnableWorkspaceTools' + $verifyScript | Should -Match 'API_VERSION="2026-01-01"' + } + + It 'limits legacy config env-var references to the allowlist' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" + $result.ExitCode | Should -Be 0 + + $paths = $result.Output -split "`n" | + Where-Object { $_ } | + ForEach-Object { ($_ -split ':', 2)[0] } | + Sort-Object -Unique + + $paths | Should -Be @( + 'docs-mslearn/toolkit/sre-agent/deploy.md', + 'src/templates/sre-agent/bin/build-extras.py', + 'src/templates/sre-agent/README.md', + 'src/templates/sre-agent/recipes/finops-hub/connectors.json' + ) + } + + It 'keeps connectors.secrets.env out of scripts' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'connectors\.secrets\.env' -- src/templates/sre-agent/bin src/templates/sre-agent/infra" + $result.ExitCode | Should -Be 1 + } + + It 'removes the legacy custom bicep deployment surface' { + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bicep') | Should -BeFalse + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/hydrate-extensions.sh') | Should -BeFalse + } + + It 'uses deterministic subscription and resource group identity for support resource names' { + $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $resourcesBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/resources.bicep') -Raw + + $mainBicep | Should -Match "agentResourceGroupId = subscriptionResourceId\('Microsoft\.Resources/resourceGroups', resourceGroupName\)" + $mainBicep | Should -Match 'namingSeed = toLower' + $mainBicep | Should -Match 'subscription\(\)\.subscriptionId' + $mainBicep | Should -Match 'agentResourceGroupId' + $mainBicep | Should -Match 'agentName' + + $resourcesBicep | Should -Match 'param namingSeed string' + $resourcesBicep | Should -Match 'uniqueSuffix = uniqueString\(namingSeed\)' + $resourcesBicep | Should -Not -Match 'resourceGroup\(\)\.id|deployment\(\)\.name' + } + + It 'applies subagents after their local handoff targets' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("sre-agent-post-provision-" + [guid]::NewGuid().ToString('N')) + $binDir = Join-Path $tempRoot 'bin' + $buildDir = Join-Path $tempRoot 'build' + $logPath = Join-Path $tempRoot 'agent-apply.log' + New-Item -ItemType Directory -Force -Path $binDir, $buildDir | Out-Null + + $fakeAz = Join-Path $binDir 'az' + Set-BashStub -Path $fakeAz -Content @' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$*" == *"account get-access-token"* ]]; then + echo "fake-token" + exit 0 +fi + +if [[ "${1:-}" == "rest" ]]; then + echo "{}" + exit 0 +fi + +case "$*" in + *"account show"*|*"account set"*|*"version"*) + exit 0 + ;; +esac + +exit 1 +'@ + + $fakeCurl = Join-Path $binDir 'curl' + Set-BashStub -Path $fakeCurl -Content @' +#!/usr/bin/env bash +set -euo pipefail + +out="" +url="" +method="GET" +while [[ $# -gt 0 ]]; do + case "$1" in + -o) + out="$2" + shift 2 + ;; + -w) + shift 2 + ;; + -X) + method="$2" + shift 2 + ;; + -H|--data-binary) + shift 2 + ;; + http*) + url="$1" + shift + ;; + *) + shift + ;; + esac +done + +if [[ "$url" == */api/v2/extendedAgent/connectors ]]; then + cat > "$out" <<'JSON' +{ + "value": [ + { "name": "chart-artifact-verification-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "chart-artifact-verification.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "document-index-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "document-index.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "ftk-output-style-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "ftk-output-style.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "known-issues-and-workarounds-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "known-issues-and-workarounds.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "onboarding-recommendations-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "onboarding-recommendations.md", "createdAt": "2026-05-25T19:57:31Z" } } }, + { "name": "teams-notification-guide-md", "type": "KnowledgeItem", "properties": { "dataConnectorType": "KnowledgeFile", "extendedProperties": { "displayName": "teams-notification-guide.md", "createdAt": "2026-05-25T19:57:31Z" } } } + ] +} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/connectors/* ]]; then + cat > "$out" <<'JSON' +{ + "type": "KnowledgeItem", + "properties": { + "dataConnectorType": "KnowledgeFile", + "extendedProperties": { + "createdAt": "2026-05-25T19:57:31Z", + "lastModifiedAt": "2026-05-25T19:57:31Z" + } + } +} +JSON + if [[ "$method" == "PUT" ]]; then printf "201"; else printf "200"; fi + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/agents/* ]]; then + [[ -n "${AGENT_APPLY_LOG:-}" ]] && basename "$url" >> "$AGENT_APPLY_LOG" + cat > "$out" <<'JSON' +{ + "type": "ExtendedAgent", + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/extendedAgent/tools/* || "$url" == */api/v2/extendedAgent/skills/* || "$url" == */api/v2/extendedAgent/scheduledtasks/* ]]; then + cat > "$out" <<'JSON' +{ + "properties": { + "provisioningState": "Succeeded" + } +} +JSON + printf "201" + exit 0 +fi + +if [[ "$url" == */api/v2/agent/tools/configure ]]; then + cat > "$out" <<'JSON' +{} +JSON + printf "200" + exit 0 +fi + +if [[ "$url" == */api/v1/scheduledtasks ]]; then + cat > "$out" <<'JSON' +[] +JSON + printf "200" + exit 0 +fi + +cat > "$out" <<'JSON' +{ + "files": [ + { "name": "chart-artifact-verification-md", "isIndexed": true, "errorReason": null }, + { "name": "document-index-md", "isIndexed": true, "errorReason": null }, + { "name": "ftk-output-style-md", "isIndexed": true, "errorReason": null }, + { "name": "known-issues-and-workarounds-md", "isIndexed": true, "errorReason": null }, + { "name": "onboarding-recommendations-md", "isIndexed": true, "errorReason": null }, + { "name": "teams-notification-guide-md", "isIndexed": true, "errorReason": null } + ], + "continuationToken": "" +} +JSON +printf "200" +'@ + + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' +#!/usr/bin/env bash +exit 0 +'@ + + try { + $command = "AGENT_APPLY_LOG='$logPath' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:PostProvisionScript' --endpoint https://example.azuresre.ai --subscription 00000000-0000-0000-0000-000000000000 --resource-group rg-test-customer --name customer-sre-agent --recipe '$script:RecipeDir' --build-dir '$buildDir'" + $result = Invoke-BashCommandWithPath $command $binDir + $result.ExitCode | Should -Be 0 + + $order = @(Get-Content -Path $logPath) + [array]::IndexOf($order, 'chief-financial-officer') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + [array]::IndexOf($order, 'ftk-database-query') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + [array]::IndexOf($order, 'ftk-hubs-agent') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) + } + finally { + Remove-Item -Path $tempRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } + + It 'derives expected recipe connectors for verification' { + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $verifyScript | Should -Match 'connectors\.json' + $verifyScript | Should -Match 'EXPECTED_CONNECTORS' + $verifyScript | Should -Match 'EXP_CONN_CT=.*EXPECTED_CONNECTORS' + $verifyScript | Should -Match 'EXP_CONN_NAMES=.*EXPECTED_CONNECTORS' + } + + It 'uploads the shared FinOps output style as a portal knowledge source' { + $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw + $buildExtrasScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/build-extras.py') -Raw + + Test-Path $script:OutputStylePath | Should -BeTrue + $buildExtrasScript | Should -Match 'claude-plugin/output-styles/ftk-output-style\.md' + $buildExtrasScript | Should -Match 'Output style knowledge document not found' + $applyExtrasScript | Should -Match 'knowledgeItems' + $applyExtrasScript | Should -Match '/api/v2/extendedAgent/connectors' + $applyExtrasScript | Should -Match 'Knowledge sources failed to index' + $applyExtrasScript | Should -Match 'KnowledgeFile' + $applyExtrasScript | Should -Not -Match ('sr' + 'ectl') + $applyExtrasScript | Should -Not -Match '/api/v1/agentmemory/files' + } + + It 'requires expected knowledge sources and verifies indexing' { + $expectedConfig = Get-Content -Path (Join-Path $script:RecipeDir 'expected-config.json') -Raw | ConvertFrom-Json + $verifyScript = Get-Content -Path $script:VerifyScript -Raw + + $expectedConfig.knowledgeSources.Count | Should -Be 6 + $expectedConfig.knowledgeSources | Should -Contain 'ftk-output-style.md' + $expectedConfig.PSObject.Properties.Name | Should -Not -Contain 'knowledgeDocs' + $verifyScript | Should -Match '/api/v2/extendedAgent/connectors' + $verifyScript | Should -Match '\$expected\[\] \| \. as \$name \| select\(\$actual \| index\(\$name\)\)' + $verifyScript | Should -Match 'Knowledge sources expected' + $verifyScript | Should -Match 'Knowledge sources indexed' + $verifyScript | Should -Match 'Unindexed knowledge sources' + $verifyScript | Should -Not -Match '/api/v1/agentmemory' + $verifyScript | Should -Not -Match '"knowledge_" \+' + $verifyScript | Should -Not -Match 'Knowledge connector rows' + } + + It 'does not duplicate response plan verification with dead incident-filter scan state' { + $verifyScript = Get-Content -Path $script:VerifyScript -Raw + + ([regex]::Matches($verifyScript, 'check "Filter names"')).Count | Should -Be 1 + $verifyScript | Should -Not -Match 'EXP_FILTERS' + $verifyScript | Should -Not -Match 'automations/incident-filters' + } + + It 'requires every scheduled task to apply the shared output style' { + $taskFiles = @(Get-ChildItem -Path $script:ScheduledTaskDir -Filter '*.yaml') + $taskFiles.Count | Should -Be 19 + + $expectedInstruction = [regex]::Escape('Output style: Apply `ftk-output-style.md`') + foreach ($file in $taskFiles) { + $content = Get-Content -Path $file.FullName -Raw + $content | Should -Match $expectedInstruction + } + } + + It 'deletes existing scheduled tasks before applying manifests' { + $applyExtrasScript = Get-Content -Path $script:ApplyExtrasScript -Raw + $verifyScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/verify-agent.sh') -Raw + + $applyExtrasScript | Should -Match 'delete_existing_scheduled_tasks' + $applyExtrasScript | Should -Match '/api/v1/scheduledtasks' + $applyExtrasScript | Should -Match 'dataplane_put_extended "scheduledtasks"' + $verifyScript | Should -Match 'Scheduled task duplicates' + $verifyScript | Should -Match '0 duplicates' + } + + } + + Context 'copy-and-update deployment contract' { + It 'rejects what-if because the copied starter-lab flow deploys directly' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test -n test-agent -l westus3 --what-if" + $result.ExitCode | Should -Be 2 + $result.Output | Should -Match 'unknown flag' + } + + It 'documents that azd is not used' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nF 'azd' -- src/templates/sre-agent/bin src/templates/sre-agent/infra docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent/README.md" + $result.Output | Should -Match 'azd' + $result.Output | Should -Match 'not used|doesn''t use' + } + } +} From b332089fff46b2ae69bf567473f500d4940ca9d1 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 09:45:43 -0700 Subject: [PATCH 08/19] fix(sre-agent): address deploy CI failures --- docs-mslearn/toolkit/hubs/configure-sre.md | 26 +++++++++---------- docs-mslearn/toolkit/sre-agent/agents.md | 6 ++--- docs-mslearn/toolkit/sre-agent/get-started.md | 2 +- docs-mslearn/toolkit/sre-agent/knowledge.md | 6 ++--- docs-mslearn/toolkit/sre-agent/kusto-tools.md | 4 +-- docs-mslearn/toolkit/sre-agent/overview.md | 6 ++--- .../toolkit/sre-agent/python-tools.md | 2 +- .../toolkit/sre-agent/scheduled-tasks.md | 4 +-- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md index 37f888dcd..0dd1deacf 100644 --- a/docs-mslearn/toolkit/hubs/configure-sre.md +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -13,7 +13,7 @@ ms.reviewer: micflan # Configure an SRE agent for FinOps hubs -[Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) supports agent-based operational workflows. This article shows how to connect Azure SRE Agent to a [FinOps hub](finops-hubs-overview.md), configure scheduled cost analysis and capacity checks from the [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), and send results to Teams with the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). +[Azure SRE Agent](/azure/sre-agent/overview) supports agent-based operational workflows. This article shows how to connect Azure SRE Agent to a [FinOps hub](finops-hubs-overview.md), configure scheduled cost analysis and capacity checks from the [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent), and send results to Teams with the [Teams notification connector](/azure/sre-agent/send-notifications).
@@ -22,8 +22,8 @@ ms.reviewer: micflan - [Deployed a FinOps hub instance](finops-hubs-overview.md#create-a-new-hub) with Data Explorer. - [Configured scopes](configure-scopes.md) and ingested data successfully. - Permissions to create deployed resources, such as **Contributor** on the subscription when the template creates the agent resource group. You also need permissions to assign roles at subscription, target resource group, and agent scopes, such as **Role Based Access Control Administrator**, **User Access Administrator**, or **Owner** on those scopes. [Learn more](/azure/role-based-access-control/built-in-roles). -- The `Microsoft.App` resource provider [registered](https://learn.microsoft.com/azure/azure-resource-manager/management/resource-providers-and-types#register-resource-provider) on the subscription. -- For local CLI deployments only: [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) 2.60 or later, `curl`, `jq`, `python3`, and `bash` available locally for the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent). +- The `Microsoft.App` resource provider [registered](/azure/azure-resource-manager/management/resource-providers-and-types#register-resource-provider) on the subscription. +- For local CLI deployments only: [Azure CLI](/cli/azure/install-azure-cli) 2.60 or later, `curl`, `jq`, `python3`, and `bash` available locally for the [deployment script](https://github.com/microsoft/finops-toolkit/tree/main/src/templates/sre-agent).
@@ -33,7 +33,7 @@ The [SRE agent template](https://github.com/microsoft/finops-toolkit/tree/main/s | Component | Count | Description | |-----------|-------|-------------| -| SRE agent | 1 | Stable [`Microsoft.App/agents`](https://learn.microsoft.com/azure/sre-agent/overview) resource in [autonomous mode](https://learn.microsoft.com/azure/sre-agent/run-modes) | +| SRE agent | 1 | Stable [`Microsoft.App/agents`](/azure/sre-agent/overview) resource in [autonomous mode](/azure/sre-agent/run-modes) | | Managed identities | 1-2 | System-assigned managed identity for the agent; portal deployments also create a user-assigned identity for the deployment script | | Log Analytics | 1 | Workspace for agent telemetry | | Application Insights | 1 | Linked to Log Analytics for monitoring | @@ -132,7 +132,7 @@ After `bin/deploy.sh` completes, use the template's [post-deployment verificatio ## Configure Teams notifications -Scheduled tasks can send reports to a Teams channel through the [Teams notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). The connector requires interactive OAuth setup in the portal. +Scheduled tasks can send reports to a Teams channel through the [Teams notification connector](/azure/sre-agent/send-notifications). The connector requires interactive OAuth setup in the portal. 1. Open [sre.azure.com](https://sre.azure.com), open your agent, then go to **Builder** > **Connectors**. 2. Select **Add connector** > **Send notification (Microsoft Teams)**. @@ -142,7 +142,7 @@ Scheduled tasks can send reports to a Teams channel through the [Teams notificat Use the built-in `PostTeamsMessage` tool from the [Teams notification guidance](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/recipes/finops-hub/knowledge/teams-notification-guide.md). Don't call the Microsoft Graph API or the connection's `dynamicInvoke` endpoint directly because that path returns a 403 error for this connector configuration. -For Outlook notifications, follow the same pattern with the **Outlook Tools (Office 365 Outlook)** connector. See [Send notifications](https://learn.microsoft.com/azure/sre-agent/send-notifications) for details. +For Outlook notifications, follow the same pattern with the **Outlook Tools (Office 365 Outlook)** connector. See [Send notifications](/azure/sre-agent/send-notifications) for details.
@@ -172,7 +172,7 @@ The template deploys 19 scheduled tasks from the [`recipes/finops-hub/automation | Semiannual | finops-practitioner | January 5 and July 5 at 9:00 AM | Semiannual year-over-year finance analysis with forecast and CFO consultation | | CapacityQuarterlyStrategy | finops-practitioner | Quarterly 9:00 AM | FinOps capability maturity, commitment alignment, and architecture review | -Each scheduled task reads the uploaded knowledge documents before it starts and applies `ftk-output-style.md` for evidence, formatting, FinOps capability mapping, confidence, and caveat conventions. Send financial results to Teams through the configured [notification connector](https://learn.microsoft.com/azure/sre-agent/send-notifications). Save only operational notes, such as tool errors, workarounds, and patterns, to agent [memory](https://learn.microsoft.com/azure/sre-agent/memory) with `#remember`; don't save financial data. +Each scheduled task reads the uploaded knowledge documents before it starts and applies `ftk-output-style.md` for evidence, formatting, FinOps capability mapping, confidence, and caveat conventions. Send financial results to Teams through the configured [notification connector](/azure/sre-agent/send-notifications). Save only operational notes, such as tool errors, workarounds, and patterns, to agent [memory](/azure/sre-agent/memory) with `#remember`; don't save financial data.
@@ -194,10 +194,10 @@ Browser success with CLI failure indicates that the CLI token was issued for the Azure SRE Agent includes platform capabilities that are on by default in this template: -- **Workspace tools**: Azure SRE Agent can run file, terminal, and Python operations in a sandboxed environment for data analysis, chart generation, and report formatting. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/sre-agent.bicep) deploys the stable agent API and sets `experimentalSettings.EnableSandboxGroup` and `experimentalSettings.EnableWorkspaceTools`. See [Deep context](https://learn.microsoft.com/azure/sre-agent/workspace-tools). -- **DocsGuide**: DocsGuide provides Azure documentation grounding for agent responses. See [Use DocsGuide](https://learn.microsoft.com/azure/sre-agent/use-docsguide). -- **Visualization**: Built-in chart and table rendering for investigation results. See [Tools](https://learn.microsoft.com/azure/sre-agent/tools). -- **Memory**: Memory stores operational knowledge across sessions. See [Memory and knowledge](https://learn.microsoft.com/azure/sre-agent/memory). +- **Workspace tools**: Azure SRE Agent can run file, terminal, and Python operations in a sandboxed environment for data analysis, chart generation, and report formatting. The [Bicep template](https://github.com/microsoft/finops-toolkit/blob/main/src/templates/sre-agent/infra/modules/sre-agent.bicep) deploys the stable agent API and sets `experimentalSettings.EnableSandboxGroup` and `experimentalSettings.EnableWorkspaceTools`. See [Deep context](/azure/sre-agent/workspace-tools). +- **DocsGuide**: DocsGuide provides Azure documentation grounding for agent responses. See [Use DocsGuide](/azure/sre-agent/use-docsguide). +- **Visualization**: Built-in chart and table rendering for investigation results. See [Tools](/azure/sre-agent/tools). +- **Memory**: Memory stores operational knowledge across sessions. See [Memory and knowledge](/azure/sre-agent/memory). The analytical subagents include `execute_python` where they need calculations, charts, tables, and downloadable artifacts. `finops-practitioner` orchestrates scheduled analysis, `ftk-database-query` owns Kusto evidence, `azure-capacity-manager` owns Azure capacity evidence, and `chief-financial-officer` provides finance and leadership consultation. @@ -237,8 +237,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md index 5411f4bb6..f074791d2 100644 --- a/docs-mslearn/toolkit/sre-agent/agents.md +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -13,7 +13,7 @@ ms.reviewer: brettwil # Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) -The FinOps toolkit configures [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) with a multi-agent architecture aligned to the canonical FinOps Framework. One orchestrator receives prompts and scheduled tasks, then delegates work to specialist subagents with focused FinOps, finance, capacity, database, and hub operations expertise. +The FinOps toolkit configures [Azure SRE Agent](/azure/sre-agent/overview) with a multi-agent architecture aligned to the canonical FinOps Framework. One orchestrator receives prompts and scheduled tasks, then delegates work to specialist subagents with focused FinOps, finance, capacity, database, and hub operations expertise. The template configures 5 subagents, 3 skills, 50 tools (37 generated Kusto tools and 13 Python tools), and a FinOps hub connector. The orchestrator keeps the experience simple. The specialist agents keep answers grounded in the right domain. @@ -349,8 +349,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Azure Monitor](/azure/azure-monitor/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md index 5b2981737..daa869ae7 100644 --- a/docs-mslearn/toolkit/sre-agent/get-started.md +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -120,7 +120,7 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure SRE Agent](/azure/sre-agent/overview) - [Azure Data Explorer](/azure/data-explorer/) - [Microsoft Cost Management](/azure/cost-management-billing/costs/) diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md index 9a94d8dda..30ee26c5a 100644 --- a/docs-mslearn/toolkit/sre-agent/knowledge.md +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -159,9 +159,9 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) -- [Microsoft Teams](https://learn.microsoft.com/microsoftteams/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) +- [Microsoft Teams](/microsoftteams/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md index 19dfe39da..fbf33361c 100644 --- a/docs-mslearn/toolkit/sre-agent/kusto-tools.md +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -484,8 +484,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Microsoft Cost Management](/azure/cost-management-billing/costs/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md index c7240abbf..e0f62bdb9 100644 --- a/docs-mslearn/toolkit/sre-agent/overview.md +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -13,7 +13,7 @@ ms.reviewer: brettwil # Azure SRE Agent in the FinOps toolkit -The FinOps toolkit ships a Deploy to Azure template and a local Azure CLI + Bicep wrapper that deploy [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) and configure it for FinOps and capacity management workflows on top of [FinOps hubs](../hubs/finops-hubs-overview.md). The deployment includes specialist subagents, FOCUS-aligned Kusto and Python tools, scheduled tasks, and grounded knowledge so the agent can investigate cost changes, monitor quota and capacity signals, prepare executive summaries, and deliver scheduled updates. The deployment focuses on three core design principles: +The FinOps toolkit ships a Deploy to Azure template and a local Azure CLI + Bicep wrapper that deploy [Azure SRE Agent](/azure/sre-agent/overview) and configure it for FinOps and capacity management workflows on top of [FinOps hubs](../hubs/finops-hubs-overview.md). The deployment includes specialist subagents, FOCUS-aligned Kusto and Python tools, scheduled tasks, and grounded knowledge so the agent can investigate cost changes, monitor quota and capacity signals, prepare executive summaries, and deliver scheduled updates. The deployment focuses on three core design principles: - **Automate the rhythm**
_Run daily, weekly, monthly, and quarterly FinOps workflows without waiting for manual report requests._ - **Ground every answer**
_Use FinOps hub data, FOCUS-aligned Kusto tools, and Azure platform context to keep recommendations tied to evidence._ @@ -138,8 +138,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Azure Monitor](/azure/azure-monitor/) Related solutions: diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md index 1de0cce9f..31831392c 100644 --- a/docs-mslearn/toolkit/sre-agent/python-tools.md +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -500,7 +500,7 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) +- [Azure SRE Agent](/azure/sre-agent/overview) - [Azure Resource Graph](/azure/governance/resource-graph/) - [Microsoft Cost Management](/azure/cost-management-billing/costs/) - [Azure Advisor](/azure/advisor/) diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md index f98f3e14a..608e277ca 100644 --- a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -264,8 +264,8 @@ Related FinOps capabilities: Related products: -- [Azure SRE Agent](https://learn.microsoft.com/azure/sre-agent/overview) -- [Azure Data Explorer](https://learn.microsoft.com/azure/data-explorer/) +- [Azure SRE Agent](/azure/sre-agent/overview) +- [Azure Data Explorer](/azure/data-explorer/) - [Azure Monitor](/azure/azure-monitor/) Related solutions: diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index b1042a83f..946e61225 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -47,7 +47,7 @@ Describe 'SRE Agent deploy template' { Push-Location $script:RepoRoot try { $originalPath = $env:PATH - $env:PATH = "${PathPrefix}:$originalPath" + $env:PATH = "${PathPrefix}$([System.IO.Path]::PathSeparator)$originalPath" $output = & bash -c $Command 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE From 3e8308180ce9dfb7eb67bdd14de12a93be69574f Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 09:53:24 -0700 Subject: [PATCH 09/19] test(sre-agent): normalize bash stub path on Windows --- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index 946e61225..bd9e2ab07 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -47,8 +47,9 @@ Describe 'SRE Agent deploy template' { Push-Location $script:RepoRoot try { $originalPath = $env:PATH - $env:PATH = "${PathPrefix}$([System.IO.Path]::PathSeparator)$originalPath" - $output = & bash -c $Command 2>&1 + $bashPathPrefix = ConvertTo-BashPath $PathPrefix + $quotedPathPrefix = ConvertTo-BashSingleQuoted $bashPathPrefix + $output = & bash -c "PATH=${quotedPathPrefix}:`$PATH $Command" 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE Output = ($output -join "`n") @@ -60,6 +61,30 @@ Describe 'SRE Agent deploy template' { } } + function ConvertTo-BashPath { + param( + [Parameter(Mandatory)] + [string] $Path + ) + + $quotedPath = ConvertTo-BashSingleQuoted $Path + $converted = & bash -lc "command -v cygpath >/dev/null 2>&1 && cygpath -u $quotedPath" 2>$null + if ($LASTEXITCODE -eq 0 -and $converted) { + return ($converted -join '') + } + + return $Path + } + + function ConvertTo-BashSingleQuoted { + param( + [Parameter(Mandatory)] + [string] $Value + ) + + return "'" + ($Value -replace "'", "'\''") + "'" + } + function Set-BashStub { param( [Parameter(Mandatory)] From 60d7857ca2407ee4d70eb5e9b5d1c1088f8bb25a Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:00:10 -0700 Subject: [PATCH 10/19] test(sre-agent): harden bash stub permissions --- .../Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index bd9e2ab07..4ee5c6ef3 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -96,7 +96,12 @@ Describe 'SRE Agent deploy template' { $utf8NoBom = [System.Text.UTF8Encoding]::new($false) [System.IO.File]::WriteAllText($Path, ($Content -replace "`r`n", "`n"), $utf8NoBom) - & chmod +x $Path + $bashPath = ConvertTo-BashPath $Path + $quotedPath = ConvertTo-BashSingleQuoted $bashPath + & bash -c "chmod +x $quotedPath" + if ($LASTEXITCODE -ne 0) { + throw "Failed to mark bash stub executable: $Path" + } } } @@ -480,7 +485,7 @@ exit 0 try { $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://example.westus3.kusto.windows.net/Hub" $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 + $result.ExitCode | Should -Be 0 -Because $result.Output $result.Output | Should -Match 'Resolving Kusto cluster resource ID from --cluster-uri' $result.Output | Should -Match '/providers/Microsoft\.Kusto/clusters/example' @@ -699,7 +704,7 @@ exit 0 $clusterId = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Kusto/clusters/privateadx' $command = "SRE_AGENT_DEPLOY_DIR='$deployRoot' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:DeployScript' --recipe '$script:RecipeDir' --subscription 00000000-0000-0000-0000-000000000000 -g rg-test-customer -n customer-sre-agent -l eastus2 --cluster-uri https://privateadx.westus.kusto.windows.net/Hub --cluster-resource-id $clusterId" $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 + $result.ExitCode | Should -Be 0 -Because $result.Output $result.Output | Should -Match 'Warning: The Kusto cluster denies public query access' $result.Output | Should -Match 'private endpoint ADX blocks direct KQL queries' $result.Output | Should -Match 'https://sre.azure.com/docs/capabilities/azure-observability-vnet#known-limitations' @@ -965,7 +970,7 @@ exit 0 try { $command = "AGENT_APPLY_LOG='$logPath' SRE_AGENT_APPLY_REQUEST_DELAY_SECONDS=0 SRE_AGENT_APPLY_RETRY_DELAY_SECONDS=0 bash '$script:PostProvisionScript' --endpoint https://example.azuresre.ai --subscription 00000000-0000-0000-0000-000000000000 --resource-group rg-test-customer --name customer-sre-agent --recipe '$script:RecipeDir' --build-dir '$buildDir'" $result = Invoke-BashCommandWithPath $command $binDir - $result.ExitCode | Should -Be 0 + $result.ExitCode | Should -Be 0 -Because $result.Output $order = @(Get-Content -Path $logPath) [array]::IndexOf($order, 'chief-financial-officer') | Should -BeLessThan ([array]::IndexOf($order, 'finops-practitioner')) From e46aa39106a4212403b1c89fd1038eedfbf85b04 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:06:58 -0700 Subject: [PATCH 11/19] test(sre-agent): stub extras builder in deploy tests --- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index 4ee5c6ef3..ff328ebc8 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -103,6 +103,67 @@ Describe 'SRE Agent deploy template' { throw "Failed to mark bash stub executable: $Path" } } + + function Set-PythonExtrasStub { + param( + [Parameter(Mandatory)] + [string] $BinDir + ) + + $realPython = (Get-Command python3 -ErrorAction SilentlyContinue).Source + if (-not $realPython) { + $realPython = (Get-Command python -ErrorAction Stop).Source + } + $realPython = ConvertTo-BashPath $realPython + + Set-BashStub -Path (Join-Path $BinDir 'python3') -Content @" +#!/usr/bin/env bash +set -euo pipefail +real_python='$realPython' + +if [[ "`$\{1:-\}" == "-c" && "`$\{2:-\}" == "import yaml" ]]; then + exit 0 +fi + +if [[ "`$\{1:-\}" == */build-extras.py ]]; then + output="" + while [[ "`$#" -gt 0 ]]; do + case "`$1" in + --output) + output="`$2" + shift 2 + ;; + *) + shift + ;; + esac + done + + [[ -n "`$output" ]] || exit 2 + mkdir -p "`$(dirname "`$output")" + cat > "`$output" <<'JSON' +{ + "connectors": [], + "builtInTools": { "overrides": [] }, + "knowledgeItems": [], + "tools": [], + "skills": [], + "subagents": [ + { "metadata": { "name": "chief-financial-officer" }, "spec": { "description": "test" } }, + { "metadata": { "name": "ftk-database-query" }, "spec": { "description": "test" } }, + { "metadata": { "name": "ftk-hubs-agent" }, "spec": { "description": "test" } }, + { "metadata": { "name": "finops-practitioner" }, "spec": { "description": "test" } } + ], + "scheduledTasks": [] +} +JSON + printf '{"connectors":0,"knowledgeItems":0,"tools":0,"skills":0,"subagents":4,"scheduledTasks":0}\n' + exit 0 +fi + +exec "`$real_python" "`$@" +"@ + } } Context 'bash availability' { @@ -477,6 +538,8 @@ JSON printf "200" '@ + Set-PythonExtrasStub -BinDir $binDir + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' #!/usr/bin/env bash exit 0 @@ -695,6 +758,8 @@ JSON printf "200" '@ + Set-PythonExtrasStub -BinDir $binDir + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' #!/usr/bin/env bash exit 0 @@ -962,6 +1027,8 @@ JSON printf "200" '@ + Set-PythonExtrasStub -BinDir $binDir + Set-BashStub -Path (Join-Path $binDir 'sleep') -Content @' #!/usr/bin/env bash exit 0 From de97720371de5f424b3f1f462eea102510dedfba Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:14:36 -0700 Subject: [PATCH 12/19] test(sre-agent): fix Windows Python extras stub --- .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index ff328ebc8..f16c0be30 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -115,22 +115,23 @@ Describe 'SRE Agent deploy template' { $realPython = (Get-Command python -ErrorAction Stop).Source } $realPython = ConvertTo-BashPath $realPython + $realPythonLiteral = ConvertTo-BashSingleQuoted $realPython - Set-BashStub -Path (Join-Path $BinDir 'python3') -Content @" + $stubContent = @' #!/usr/bin/env bash set -euo pipefail -real_python='$realPython' +real_python=__REAL_PYTHON__ -if [[ "`$\{1:-\}" == "-c" && "`$\{2:-\}" == "import yaml" ]]; then +if [[ "${1:-}" == "-c" && "${2:-}" == "import yaml" ]]; then exit 0 fi -if [[ "`$\{1:-\}" == */build-extras.py ]]; then +if [[ "${1:-}" == */build-extras.py ]]; then output="" - while [[ "`$#" -gt 0 ]]; do - case "`$1" in + while [[ "$#" -gt 0 ]]; do + case "$1" in --output) - output="`$2" + output="$2" shift 2 ;; *) @@ -139,9 +140,9 @@ if [[ "`$\{1:-\}" == */build-extras.py ]]; then esac done - [[ -n "`$output" ]] || exit 2 - mkdir -p "`$(dirname "`$output")" - cat > "`$output" <<'JSON' + [[ -n "$output" ]] || exit 2 + mkdir -p "$(dirname "$output")" + cat > "$output" <<'JSON' { "connectors": [], "builtInTools": { "overrides": [] }, @@ -161,8 +162,12 @@ JSON exit 0 fi -exec "`$real_python" "`$@" -"@ +exec "$real_python" "$@" +'@ + $stubContent = $stubContent.Replace('__REAL_PYTHON__', $realPythonLiteral) + + Set-BashStub -Path (Join-Path $BinDir 'python3') -Content $stubContent + Set-BashStub -Path (Join-Path $BinDir 'python') -Content $stubContent } } From 4ed9fb94d3126ecd81b29229e22cc643e7b2f34a Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 3 Jun 2026 10:21:03 -0700 Subject: [PATCH 13/19] test(sre-agent): preserve Azure resource IDs on Windows --- src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index f16c0be30..83b7e3ad7 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -24,7 +24,7 @@ Describe 'SRE Agent deploy template' { Push-Location $script:RepoRoot try { - $output = & bash -lc $Command 2>&1 + $output = & bash -lc "MSYS2_ARG_CONV_EXCL='/subscriptions;/providers' $Command" 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE Output = ($output -join "`n") @@ -49,7 +49,7 @@ Describe 'SRE Agent deploy template' { $originalPath = $env:PATH $bashPathPrefix = ConvertTo-BashPath $PathPrefix $quotedPathPrefix = ConvertTo-BashSingleQuoted $bashPathPrefix - $output = & bash -c "PATH=${quotedPathPrefix}:`$PATH $Command" 2>&1 + $output = & bash -c "MSYS2_ARG_CONV_EXCL='/subscriptions;/providers' PATH=${quotedPathPrefix}:`$PATH $Command" 2>&1 [pscustomobject]@{ ExitCode = $LASTEXITCODE Output = ($output -join "`n") From a6d68e6c26d20bd2167c2254176214257853d963 Mon Sep 17 00:00:00 2001 From: msbrett Date: Thu, 4 Jun 2026 06:21:25 -0700 Subject: [PATCH 14/19] fix(sre-agent): address recipe review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/templates/sre-agent/.gitattributes | 1 + src/templates/sre-agent/bin/build-extras.py | 14 ++++++++++++++ .../config/subagents/ftk-hubs-agent.yaml | 6 +++--- .../recipes/finops-hub/expected-config.json | 2 +- .../sre-agent/recipes/finops-hub/roles.yaml | 2 ++ 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/templates/sre-agent/.gitattributes b/src/templates/sre-agent/.gitattributes index dfdb8b771..1bbd6959a 100644 --- a/src/templates/sre-agent/.gitattributes +++ b/src/templates/sre-agent/.gitattributes @@ -1 +1,2 @@ *.sh text eol=lf +*.py text eol=lf diff --git a/src/templates/sre-agent/bin/build-extras.py b/src/templates/sre-agent/bin/build-extras.py index 769dcb831..5b81f7f69 100755 --- a/src/templates/sre-agent/bin/build-extras.py +++ b/src/templates/sre-agent/bin/build-extras.py @@ -208,6 +208,20 @@ def catalog_kpi_tool_names(recipe_dir: pathlib.Path) -> set[str]: def validate_tool_and_task_coverage(recipe_dir: pathlib.Path, extras: JsonObject) -> None: + expected_config = load_json(recipe_dir / "expected-config.json", {}) + if not isinstance(expected_config, dict): + raise SystemExit(f"Expected config must be an object: {recipe_dir / 'expected-config.json'}") + + expected_skills = sorted(str(name) for name in expected_config.get("skills") or []) + if expected_skills: + skill_names = {metadata_name(skill) for skill in extras.get("skills") or []} + missing_skills = [name for name in expected_skills if name not in skill_names] + if missing_skills: + raise SystemExit( + "Expected skill directory missing SKILL.md or has a broken symlink: " + + ", ".join(missing_skills) + ) + catalog_dir = (recipe_dir / "../../../../queries/catalog").resolve() catalog_names = {path.stem for path in catalog_dir.glob("*.kql")} tools = extras.get("tools") or [] diff --git a/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml b/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml index 01959c356..5beea5721 100644 --- a/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/config/subagents/ftk-hubs-agent.yaml @@ -48,9 +48,9 @@ spec: Maintenance and troubleshooting workflow: - Gather the exact operation, error text, resource IDs, deployment logs, and recent changes. - - Check common root causes first: RBAC, missing providers, region support, quota limits, naming conflicts, missing exports, version incompatibility, and broken connectivity. - - For errors such as "The sku is not supported in " in nested Microsoft.FinOpsHubs.Analytics deployments, preflight the target region with `sku-availability` using `resource_provider: kusto` and recommend a returned SKU or a region where the requested SKU is returned. - - Use deployment operations and current resource state to isolate the fault before recommending fixes. + - Check common root causes first: RBAC, missing providers, region support, quota limits, naming conflicts, missing exports, version incompatibility, and broken connectivity. + - For errors such as "The sku is not supported in " in nested Microsoft.FinOpsHubs.Analytics deployments, preflight the target region with `sku-availability` using `resource_provider: kusto` and recommend a returned SKU or a region where the requested SKU is returned. + - Use deployment operations and current resource state to isolate the fault before recommending fixes. - Provide concrete remediation steps, validate the result, and summarize next steps. - Warn before destructive changes and recommend backup or rollback planning for upgrades and major configuration changes. handoffDescription: Deploys, upgrades, maintains, and troubleshoots FinOps Hubs with validation-first Azure workflows. diff --git a/src/templates/sre-agent/recipes/finops-hub/expected-config.json b/src/templates/sre-agent/recipes/finops-hub/expected-config.json index 9e6e49a04..dae5444d1 100644 --- a/src/templates/sre-agent/recipes/finops-hub/expected-config.json +++ b/src/templates/sre-agent/recipes/finops-hub/expected-config.json @@ -1,7 +1,7 @@ { "agent": { "accessLevel": "High", - "actionMode": "autonomous", + "actionMode": "Autonomous", "upgradeChannel": "Preview", "defaultModelProvider": "MicrosoftFoundry", "experimentalSettings": [ diff --git a/src/templates/sre-agent/recipes/finops-hub/roles.yaml b/src/templates/sre-agent/recipes/finops-hub/roles.yaml index dbd851335..8ec08ee8f 100644 --- a/src/templates/sre-agent/recipes/finops-hub/roles.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/roles.yaml @@ -6,6 +6,8 @@ roles: targetResourceGroups: - name: Reader roleDefinitionId: acdd72a7-3385-48ef-bd42-f606fba81ae7 + - name: Monitoring Reader + roleDefinitionId: 43d0d8ad-25c7-4714-9337-8ba259a9fe05 - name: Log Analytics Reader roleDefinitionId: 73c42c96-874c-492b-b04d-ab87d138a893 - name: Contributor From fe4aa54472ec30c564245000ccccca283d6b0697 Mon Sep 17 00:00:00 2001 From: msbrett Date: Thu, 4 Jun 2026 06:26:51 -0700 Subject: [PATCH 15/19] chore: update mslearn dates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs-mslearn/toolkit/changelog.md | 2 +- docs-mslearn/toolkit/hubs/configure-sre.md | 2 +- docs-mslearn/toolkit/sre-agent/agents.md | 2 +- docs-mslearn/toolkit/sre-agent/deploy.md | 2 +- docs-mslearn/toolkit/sre-agent/get-started.md | 2 +- docs-mslearn/toolkit/sre-agent/knowledge.md | 2 +- docs-mslearn/toolkit/sre-agent/kusto-tools.md | 2 +- docs-mslearn/toolkit/sre-agent/overview.md | 2 +- docs-mslearn/toolkit/sre-agent/python-tools.md | 2 +- docs-mslearn/toolkit/sre-agent/scheduled-tasks.md | 2 +- docs-mslearn/toolkit/sre-agent/security.md | 2 +- docs-mslearn/toolkit/sre-agent/template.md | 2 +- docs-mslearn/toolkit/sre-agent/tools.md | 2 +- docs-mslearn/toolkit/sre-agent/troubleshooting.md | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs-mslearn/toolkit/changelog.md b/docs-mslearn/toolkit/changelog.md index c46cd6c5d..762824bfb 100644 --- a/docs-mslearn/toolkit/changelog.md +++ b/docs-mslearn/toolkit/changelog.md @@ -3,7 +3,7 @@ title: FinOps toolkit changelog description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more. author: MSBrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md index 0dd1deacf..8a1810137 100644 --- a/docs-mslearn/toolkit/hubs/configure-sre.md +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -3,7 +3,7 @@ title: Configure an SRE agent for FinOps hubs description: Learn how to configure an Azure SRE agent to connect to your FinOps hub for scheduled cost analysis, capacity monitoring, and reporting. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md index f074791d2..836779c74 100644 --- a/docs-mslearn/toolkit/sre-agent/agents.md +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -3,7 +3,7 @@ title: Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) description: Understand how the FinOps toolkit configures Azure SRE Agent with specialist agents, tools, skills, and knowledge to automate FinOps and capacity management work. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md index 88e0c3dcc..25d5ed821 100644 --- a/docs-mslearn/toolkit/sre-agent/deploy.md +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -3,7 +3,7 @@ title: Deploy Azure SRE Agent with the FinOps toolkit description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: tutorial ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md index daa869ae7..eefc72449 100644 --- a/docs-mslearn/toolkit/sre-agent/get-started.md +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -3,7 +3,7 @@ title: Get started with the FinOps toolkit on Azure SRE Agent description: Learn what to do after deploying Azure SRE Agent with the FinOps toolkit — first queries, scheduled tasks, and specialized subagents. author: flanakin ms.author: micflan -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: quickstart ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md index 30ee26c5a..985a92b4f 100644 --- a/docs-mslearn/toolkit/sre-agent/knowledge.md +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -3,7 +3,7 @@ title: Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) description: Learn how knowledge grounds the FinOps toolkit's Azure SRE Agent in your team's context and how memory keeps operational learnings available across sessions and redeployments. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md index fbf33361c..6ee383c9a 100644 --- a/docs-mslearn/toolkit/sre-agent/kusto-tools.md +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -3,7 +3,7 @@ title: Kusto tools description: Review the FinOps hub Kusto tools the FinOps toolkit ships for Azure SRE Agent and learn when to use each tool for cost, commitment discount, anomaly, forecast, AI, and price analysis. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md index e0f62bdb9..3c8433299 100644 --- a/docs-mslearn/toolkit/sre-agent/overview.md +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -3,7 +3,7 @@ title: Azure SRE Agent in the FinOps toolkit description: Learn how the FinOps toolkit deploys Azure SRE Agent with FinOps and capacity management automation on top of FinOps hubs. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md index 31831392c..01a869551 100644 --- a/docs-mslearn/toolkit/sre-agent/python-tools.md +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -3,7 +3,7 @@ title: Python tools description: Review the Python tools the FinOps toolkit ships for Azure SRE Agent for Azure quota, capacity, budgets, anomaly alerts, Resource Graph, FinOps hub health, and Advisor suppressions. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md index 608e277ca..f16463779 100644 --- a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -3,7 +3,7 @@ title: Scheduled tasks (Azure SRE Agent in the FinOps toolkit) description: Learn how the FinOps toolkit's scheduled tasks automate daily, weekly, monthly, and quarterly FinOps operating rhythms on Azure SRE Agent. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/security.md b/docs-mslearn/toolkit/sre-agent/security.md index f4b7e0f6b..0b7d89305 100644 --- a/docs-mslearn/toolkit/sre-agent/security.md +++ b/docs-mslearn/toolkit/sre-agent/security.md @@ -3,7 +3,7 @@ title: Security and permissions for Azure SRE Agent in the FinOps toolkit description: Review the permissions, identities, run modes, and data flows the FinOps toolkit configures on Azure SRE Agent before you deploy it in your environment. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/template.md b/docs-mslearn/toolkit/sre-agent/template.md index 25c7474c6..80047181f 100644 --- a/docs-mslearn/toolkit/sre-agent/template.md +++ b/docs-mslearn/toolkit/sre-agent/template.md @@ -3,7 +3,7 @@ title: Azure SRE Agent template reference (FinOps toolkit) description: Review the FinOps toolkit's Azure SRE Agent deployment template, parameters, outputs, script flags, and Bicep module structure. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/tools.md b/docs-mslearn/toolkit/sre-agent/tools.md index a8447b62f..c7bf92a09 100644 --- a/docs-mslearn/toolkit/sre-agent/tools.md +++ b/docs-mslearn/toolkit/sre-agent/tools.md @@ -3,7 +3,7 @@ title: Tools shipped for Azure SRE Agent in the FinOps toolkit description: Review the Kusto and Python tools the FinOps toolkit ships for Azure SRE Agent for cost analysis, anomaly detection, rate optimization, capacity management, and operations. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/troubleshooting.md b/docs-mslearn/toolkit/sre-agent/troubleshooting.md index 53a5af68c..d11ec0516 100644 --- a/docs-mslearn/toolkit/sre-agent/troubleshooting.md +++ b/docs-mslearn/toolkit/sre-agent/troubleshooting.md @@ -3,7 +3,7 @@ title: Troubleshoot Azure SRE Agent deployments from the FinOps toolkit description: Resolve common deployment, tenant, connector, data, and query issues for Azure SRE Agent deployments from the FinOps toolkit. author: msbrett ms.author: brettwil -ms.date: 06/03/2026 +ms.date: 06/04/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit From 4b6448466c695b3378a5ffd0add84769dfc758f6 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 17 Jun 2026 09:40:09 -0700 Subject: [PATCH 16/19] fix(sre-agent): vendor capacity skill, default read-only access, customizable fiscal year - Vendor azure-capacity-management skill as real files and drop the azcapman git submodule + symlinks so a clean clone builds all 3 skills (Roland H3). - Default the recipe agent to Low (read-only) access and autonomous reporting, and stop granting subscription-wide Reader by default (Roland H1); reports run unattended on a least-privilege identity. - Mark the yoy-report July-June fiscal year as a documented, customizable example instead of a silent assumption (Roland M5). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitmodules | 3 - .../sre-agent/recipes/finops-hub/agent.json | 4 +- .../scheduled-tasks/yoy-report.yaml | 19 +- .../skills/azure-capacity-management/SKILL.md | 249 +++++- .../azure-capacity-management/references/docs | 1 - .../references/docs/billing/README.md | 16 + .../references/docs/billing/legacy/README.md | 33 + .../references/docs/billing/modern/README.md | 109 +++ .../references/docs/billing/toc.yml | 91 ++ .../references/docs/deployment/README.md | 23 + .../docs/deployment/multi-tenant/README.md | 71 ++ .../docs/deployment/single-tenant/README.md | 95 +++ .../references/docs/deployment/toc.yml | 91 ++ .../references/docs/docfx.yml | 45 + .../references/docs/images/azure-logo.svg | 10 + .../docs/images/deployment-topologies.svg | 270 ++++++ .../docs/images/multi-tenant-topology.svg | 121 +++ .../docs/images/single-tenant-topology.svg | 145 ++++ .../references/docs/index.md | 100 +++ .../docs/labs/lab-02-forecasting.md | 654 ++++++++++++++ .../docs/labs/lab-04-procurement.md | 731 ++++++++++++++++ .../docs/labs/lab-05-monitoring-governance.md | 807 ++++++++++++++++++ .../references/docs/operations/README.md | 31 + .../docs/operations/aks-capacity/README.md | 135 +++ .../operations/capacity-and-quotas/README.md | 69 ++ .../operations/capacity-governance/README.md | 65 ++ .../operations/capacity-planning/README.md | 61 ++ .../capacity-reservations/README.md | 75 ++ .../docs/operations/escalation/README.md | 33 + .../references/docs/operations/glossary.md | 49 ++ .../docs/operations/legacy/README.md | 30 + .../docs/operations/modern/README.md | 35 + .../operations/monitoring-alerting/README.md | 32 + .../operations/non-compute-quotas/README.md | 93 ++ .../docs/operations/quota-groups/README.md | 63 ++ .../docs/operations/quota/README.md | 145 ++++ .../support-and-reference/README.md | 10 + .../support-and-reference/citation-matrix.md | 144 ++++ .../docs/operations/tenant-hygiene/README.md | 31 + .../references/docs/operations/toc.yml | 91 ++ .../docs/operations/tools-scripts/README.md | 52 ++ .../tools-scripts/deploy-anomalyalert.md | 245 ++++++ .../operations/tools-scripts/deploy-budget.md | 178 ++++ .../tools-scripts/deploy-bulkalz.md | 265 ++++++ .../tools-scripts/deploy-bulkbudgets.md | 187 ++++ .../get-azavailabilityzonemapping.md | 209 +++++ .../tools-scripts/get-azvmquotausage.md | 177 ++++ .../get-benefitrecommendations.md | 223 +++++ .../tools-scripts/show-azvmquotareport.md | 244 ++++++ .../suppress-advisorrecommendations.md | 144 ++++ .../references/docs/toc.yml | 104 +++ .../references/scripts | 1 - .../references/scripts/advisor/README.md | 27 + .../Suppress-AdvisorRecommendations.ps1 | 79 ++ .../anomaly-alerts/Deploy-AnomalyAlert.ps1 | 312 +++++++ .../scripts/anomaly-alerts/Deploy-BulkALZ.ps1 | 168 ++++ .../scripts/anomaly-alerts/README.md | 436 ++++++++++ .../anomaly-alerts/anomaly-alert.bicep | 17 + .../anomaly-alert.parameters.json | 15 + .../scripts/budgets/Deploy-Budget.ps1 | 449 ++++++++++ .../scripts/budgets/Deploy-BulkBudgets.ps1 | 257 ++++++ .../references/scripts/budgets/README.md | 152 ++++ .../references/scripts/budgets/budget.bicep | 89 ++ .../scripts/budgets/budget.parameters.json | 45 + .../references/scripts/calculator/README.md | 219 +++++ .../scripts/calculator/calculator.py | 100 +++ .../scripts/calculator/example_usage.py | 107 +++ .../scripts/calculator/requirements.txt | 1 + .../scripts/generate_citation_matrix.py | 79 ++ .../quota/Get-AzAvailabilityZoneMapping.ps1 | 232 +++++ .../scripts/quota/Get-AzVMQuotaUsage.ps1 | 555 ++++++++++++ .../scripts/quota/Get-AzVMQuotaUsageCli.ps1 | 597 +++++++++++++ .../references/scripts/quota/README.md | 219 +++++ .../scripts/quota/Show-AzVMQuotaReport.ps1 | 517 +++++++++++ .../rate/Get-BenefitRecommendations.ps1 | 74 ++ .../references/scripts/rate/README.md | 107 +++ .../scripts/serverless-sql-storage/README.md | 92 ++ .../serverless-sql-storage/workbook.json | 32 + .../recipes/finops-hub/expected-config.json | 8 +- src/templates/sre-agent/submodules/azcapman | 1 - 80 files changed, 11878 insertions(+), 17 deletions(-) delete mode 100644 .gitmodules mode change 120000 => 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md delete mode 120000 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/legacy/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/modern/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/toc.yml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/multi-tenant/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/single-tenant/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/toc.yml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/docfx.yml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/azure-logo.svg create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/deployment-topologies.svg create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/multi-tenant-topology.svg create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/single-tenant-topology.svg create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/index.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-02-forecasting.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-04-procurement.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-05-monitoring-governance.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/aks-capacity/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-and-quotas/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-governance/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-planning/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-reservations/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/escalation/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/glossary.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/legacy/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/modern/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/monitoring-alerting/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/non-compute-quotas/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota-groups/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/citation-matrix.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tenant-hygiene/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/toc.yml create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-anomalyalert.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-budget.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkalz.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkbudgets.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azavailabilityzonemapping.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azvmquotausage.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-benefitrecommendations.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/show-azvmquotareport.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/suppress-advisorrecommendations.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/toc.yml delete mode 120000 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/Suppress-AdvisorRecommendations.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-AnomalyAlert.ps1 create mode 100755 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-BulkALZ.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.bicep create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.parameters.json create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-Budget.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-BulkBudgets.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.bicep create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.parameters.json create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/README.md create mode 100755 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/calculator.py create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/example_usage.py create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/requirements.txt create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/generate_citation_matrix.py create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzAvailabilityZoneMapping.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsage.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsageCli.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Show-AzVMQuotaReport.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/Get-BenefitRecommendations.ps1 create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/README.md create mode 100644 src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/workbook.json delete mode 160000 src/templates/sre-agent/submodules/azcapman diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index d982686fe..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "src/templates/sre-agent/submodules/azcapman"] - path = src/templates/sre-agent/submodules/azcapman - url = https://github.com/microsoft/azcapman.git diff --git a/src/templates/sre-agent/recipes/finops-hub/agent.json b/src/templates/sre-agent/recipes/finops-hub/agent.json index a2a90bbe8..b2b21d260 100644 --- a/src/templates/sre-agent/recipes/finops-hub/agent.json +++ b/src/templates/sre-agent/recipes/finops-hub/agent.json @@ -1,7 +1,7 @@ { "access": { - "accessLevel": "High", - "actionMode": "Autonomous" + "accessLevel": "Low", + "actionMode": "autonomous" }, "upgradeChannel": "Preview", "defaultModelProvider": "MicrosoftFoundry", diff --git a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml index d8a5870e7..69dacb965 100644 --- a/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml +++ b/src/templates/sre-agent/recipes/finops-hub/automations/scheduled-tasks/yoy-report.yaml @@ -10,6 +10,19 @@ spec: agent: finops-practitioner agent_prompt: '# Semiannual Financial Analysis + --- + **FISCAL YEAR CONFIGURATION:** + + This task is configured for a **July–June fiscal year** (the Microsoft fiscal calendar) as a worked example. If your organization uses a different fiscal year, customize the following elements to match your fiscal calendar: + + 1. **Cron schedule** (line 8): Adjust `0 9 5 1,7 *` to run at your mid-year and year-end close dates + 2. **Fiscal period logic** (line 28): Update "July through June", "January 5 and July 5", and period-comparison statements + 3. **Forecast targets** (lines 87, 145): Adjust "June 30" and checkpoint dates to align with your fiscal year end and mid-year close + + The analysis logic below assumes July–June periods as the default example. Adapt month references and comparison windows to your fiscal calendar before deploying. + + --- + ## Phase 0: Preparation @@ -25,7 +38,7 @@ spec: Load your finops-toolkit and azure-cost-management skills. Lead this as the FinOps practitioner. Delegate all FinOps Hub Kusto evidence collection to `ftk-database-query`, delegate capacity-risk evidence to `azure-capacity-manager`, and consult `chief-financial-officer` for fiscal planning, executive framing, and commitment-risk recommendations. - Our fiscal year runs July through June. This task runs on January 5 and July 5. On January 5, compare the completed July-December first-half period against the same period in the prior fiscal year and forecast through June 30. On July 5, compare the just-completed July-June fiscal year against the previous fiscal year and prepare the next fiscal year planning view. + **Fiscal period assumptions (default: July–June fiscal year):** This task runs at mid-year and year-end close checkpoints. For a July–June fiscal year, that means January 5 and July 5. On the January checkpoint, compare the completed first-half period (July–December) against the same period in the prior fiscal year and forecast through the fiscal year end (June 30). On the July checkpoint, compare the just-completed fiscal year (July–June) against the previous fiscal year and prepare the next fiscal year planning view. Adjust these month references if your organization uses a different fiscal calendar (see configuration note above). ## Specialist evidence requests for this task @@ -84,7 +97,7 @@ spec: ### 1.9 Forecast - Ask `ftk-database-query` to run `cost-forecasting-model` using the current comparison period as actuals and enough historical data to project the next fiscal checkpoint. For January runs, forecast through June 30. For July runs, forecast the next fiscal year planning baseline. + Ask `ftk-database-query` to run `cost-forecasting-model` using the current comparison period as actuals and enough historical data to project the next fiscal checkpoint. For the mid-year checkpoint, forecast through fiscal year end (e.g., June 30 for a July–June fiscal year). For the year-end checkpoint, forecast the next fiscal year planning baseline. ### 1.10 Reservation Recommendations @@ -142,7 +155,7 @@ spec: ### 2.2 Forecast - For January runs, project total fiscal year spend with Conservative/Expected/Optimistic scenarios and compare to annual budget. For July runs, create the next fiscal year planning baseline. + For mid-year checkpoint runs, project total fiscal year spend with Conservative/Expected/Optimistic scenarios and compare to annual budget. For year-end checkpoint runs, create the next fiscal year planning baseline. ### 2.3 Savings opportunities diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md deleted file mode 120000 index 2c7fa82d2..000000000 --- a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md +++ /dev/null @@ -1 +0,0 @@ -../../../../../submodules/azcapman/skills/azure-capacity-management/SKILL.md \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md new file mode 100644 index 000000000..0b0af57a3 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/SKILL.md @@ -0,0 +1,248 @@ +--- +name: azure-capacity-management +description: | + This skill should be used when the user asks about Azure capacity management, quota + operations, or capacity planning for SaaS ISVs running workloads in their own Azure + subscriptions under EA or MCA. Relevant queries include: how to increase VM quota across + subscriptions, how quota groups work, how to create or share capacity reservation groups, + what the difference is between capacity reservations and Azure Reservations or savings plans, + how to request region access or zonal enablement, how logical and physical availability zones + map across subscriptions, how to configure quota or budget or anomaly alerts, how AKS node + pools interact with capacity reservations, how to manage non-compute quotas, how deployment + stamps map to FinOps Planning & Estimating, Forecasting, Architecting & Workload Placement, + Usage Optimization, and Governance, Policy & Risk, and how Azure capacity controls support + estate-level governance. Also covers quota transfers, overallocation, SKU restrictions, CRG + sharing, billing hierarchy, and subscription vending. +--- + +# Azure capacity management + +Estate-level capacity and quota management for SaaS ISVs operating workloads in subscriptions they own or control under an [Enterprise Agreement (EA)](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-enterprise-agreement) or [Microsoft Customer Agreement (MCA)](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement). This skill aligns with the [ISV landing zone guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) and covers pure SaaS and [stamp-based isolation](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) patterns where customers are isolated through dedicated or shared deployment stamps inside the ISV's Azure estate. + +Read the full Azure implementation reference at `references/docs/operations/capacity-and-quotas/README.md`. + +## FinOps capability mapping + +Treat Azure capacity management as implementation detail under the canonical FinOps Framework. Capacity evidence commonly supports Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization, Budgeting, Governance, Policy & Risk, and Automation, Tools & Services. Use [Well-Architected capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [reliable scaling](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling), and [workload supply chain guidance](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) as Azure implementation guidance, not as a replacement framework. [Source](https://www.finops.org/framework/) [Source](https://www.finops.org/framework/domains/) + +| FinOps capability | Capacity question | Azure surfaces | +|------|-------------|----------------| +| Planning & Estimating | What capacity does the planned workload, scenario, or stamp need? | Workload requirements, scale-unit assumptions, Azure Monitor, estimates, FinOps budgets | +| Forecasting | When will demand exceed quota, region, SKU, zone, or reserved-capacity headroom? | Historical usage, growth trends, forecast breach dates, capacity planning models | +| Architecting & Workload Placement | Which regions, zones, SKUs, quota pools, or deployment patterns should change? | SKU availability, region access, quota groups, capacity reservation groups, CRG sharing, overallocation | +| Usage Optimization | Which allocated capacity, quota, or deployment pattern is underused or inefficient? | Utilization, headroom, rightsizing evidence, unused reserved capacity, demand signals | +| Rate Optimization | Where should capacity guarantees be coordinated with reservations or savings plans? | Benefit recommendations, commitment utilization, CRG utilization, pricing evidence from FinOps Hub | +| Governance, Policy & Risk | Which capacity risks need ownership, exception review, or escalation? | Approved regions and SKUs, owner metadata, risk thresholds, exception status | +| Automation, Tools & Services | Which controls expose capacity risk before deployment or scale events? | Quota alerts, budget alerts, anomaly alerts, CI/CD gates, workflow status | + +Read `references/docs/operations/capacity-planning/README.md` for forecasting details and `references/docs/operations/capacity-governance/README.md` for the governance program design. + +## Quota operations + +Azure assigns [default quota limits](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) per subscription. EA subscriptions typically start with 350 cores; pay-as-you-go subscriptions start with 20 cores. Some VM series have offer restrictions that block deployment until you request access. + +Key workflows: +- **Region access:** Submit a [region access support request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) when a subscription can't deploy to a restricted region. +- **Zonal enablement:** Submit a [zonal enablement request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) for restricted VM series in specific availability zones. +- **Quota increases:** Use [per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) for individual subscriptions or [quota group limit increases](https://learn.microsoft.com/en-us/azure/quotas/quota-group-limit-increase) for grouped subscriptions. + +CLI reference: +```bash +# List quota usage for a subscription +az quota usage list --scope /subscriptions/{sub-id}/providers/Microsoft.Compute/locations/{location} + +# Request a quota increase +az quota create --resource-name "StandardDSv3Family" --scope /subscriptions/{sub-id}/providers/Microsoft.Compute/locations/{location} --limit-object value=500 +``` + +Read `references/docs/operations/quota/README.md` for the complete quota operations reference. + +## Quota groups + +[Quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) are ARM objects that aggregate compute quota across eligible subscriptions at the management group scope. They reduce stranded VM-family headroom and let you request group-level increases. + +**Prerequisites:** Register the `Microsoft.Quota` resource provider on each member subscription. The management group must exist before creating the quota group. + +**Limitations:** +- IaaS compute only — doesn't cover storage, networking, or PaaS services +- A subscription can belong to a single quota group at a time ([source](https://learn.microsoft.com/en-us/azure/quotas/quota-groups)) +- Doesn't grant region or zone access — those require separate support requests +- [Quota transfers](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups) move allocation between member subscriptions but don't change the group total + +**Lifecycle:** Create the quota group under a management group, [add subscriptions](https://learn.microsoft.com/en-us/azure/quotas/add-remove-subscriptions-quota-group), then request group-level limit increases. Monitor allocation snapshots and transfer as demand shifts between subscriptions. + +Read `references/docs/operations/quota-groups/README.md` for the complete reference including ARM lifecycle, transfer mechanics, and monitoring integration. + +## Capacity reservations + +[Capacity reservation groups (CRGs)](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) guarantee compute capacity for specific VM sizes in a region or availability zone. CRGs are capacity guarantees, not pricing commitments — unused reserved capacity is billed at the pay-as-you-go rate for the VM size. + +**Cost implications:** Reserved capacity is billed whether or not VMs run against it. Pair CRGs with Azure Reservations or savings plans to get both capacity guarantee and pricing discount. + +**Sharing (preview):** CRGs can be [shared across subscriptions](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share) within the same tenant. The ODCR owner in the consumer subscription needs `Microsoft.Compute/capacityReservationGroups/share/action`. The VM owner in the consumer subscription needs `Microsoft.Compute/capacityReservationGroups/read`, `Microsoft.Compute/capacityReservationGroups/deploy`, `Microsoft.Compute/capacityReservationGroups/capacityReservations/read`, and `Microsoft.Compute/capacityReservationGroups/capacityReservations/deploy`. Portal support isn't available in preview; use CLI, PowerShell, or REST API. + +**Overallocation:** [Overallocation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) lets you deploy more VMs than the reserved quantity. Excess VMs don't have capacity guarantees but benefit from the reservation when capacity is available. + +**Zone alignment:** CRGs are zone-specific. Before sharing across subscriptions, verify logical-to-physical zone mapping with the `Get-AzAvailabilityZoneMapping.ps1` script — [logical zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) can map to different physical zones across subscriptions. + +Read `references/docs/operations/capacity-reservations/README.md` for the complete reference including automation patterns (REST API, Bicep, Terraform). + +## AKS capacity governance + +AKS node pools consume VM quota and can associate with capacity reservation groups, but with constraints specific to the AKS lifecycle: + +- **Node pool CRG association** happens at creation time — you can't associate an existing node pool with a CRG after the fact +- **Identity requirement:** The AKS cluster must use a [user-assigned managed identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) with `Microsoft.Compute/capacityReservationGroups/read` permission on the CRG +- **Disassociation** removes the CRG association but doesn't delete the node pool +- **Zone alignment** matters for cross-subscription CRG sharing — verify physical zone mapping before configuring AKS node pools against shared CRGs + +Read `references/docs/operations/aks-capacity/README.md` for the complete reference including Bicep and Terraform examples. + +## Non-compute quotas + +Storage accounts, App Service plans, Cosmos DB throughput, Service Bus namespaces, Key Vault transactions, and other services have their own quota limits outside the compute quota system. Quota groups don't cover these — manage them through standard [quota requests](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests) and service-specific scaling controls. + +Read `references/docs/operations/non-compute-quotas/README.md` for service-specific quota references. + +## Monitoring and governance + +Three alert types cover the capacity governance space: + +1. **Quota alerts:** [Azure Monitor alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) triggered when quota usage crosses a configured threshold. Requires Reader or higher on the subscription. +2. **Budget alerts:** [Cost Management alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending) triggered when actual or forecasted spend exceeds budget thresholds. Uses Cost Management RBAC. +3. **Anomaly alerts:** Cost Management anomaly detection that flags unexpected spending patterns. Deploy with `references/scripts/anomaly-alerts/Deploy-AnomalyAlert.ps1` or bulk deploy with `references/scripts/anomaly-alerts/Deploy-BulkALZ.ps1`. + +**Governance cadence:** Monthly quota reviews, quarterly capacity planning cycles, and post-incident reviews when scaling events fail. Read `references/docs/operations/monitoring-alerting/README.md` for alert configuration details and `references/docs/operations/capacity-governance/README.md` for the governance program design. + +## Scripts quick reference + +| Script | Path | Purpose | +|--------|------|---------| +| Get-AzVMQuotaUsage.ps1 | `references/scripts/quota/` | Multi-threaded quota analysis across subscriptions | +| Show-AzVMQuotaReport.ps1 | `references/scripts/quota/` | Single-threaded quota reporting | +| Get-AzAvailabilityZoneMapping.ps1 | `references/scripts/quota/` | Logical-to-physical zone mapping | +| Get-BenefitRecommendations.ps1 | `references/scripts/rate/` | Reservation and savings plan recommendations | +| Deploy-AnomalyAlert.ps1 | `references/scripts/anomaly-alerts/` | Deploy cost anomaly alerts | +| Deploy-BulkALZ.ps1 | `references/scripts/anomaly-alerts/` | Bulk deploy anomaly alerts | +| Deploy-Budget.ps1 | `references/scripts/budgets/` | Deploy individual budgets | +| Deploy-BulkBudgets.ps1 | `references/scripts/budgets/` | Bulk deploy budgets | +| Suppress-AdvisorRecommendations.ps1 | `references/scripts/advisor/` | Suppress Advisor recommendations | +| Serverless SQL workbook | `references/scripts/serverless-sql-storage/` | Azure Monitor workbook for serverless SQL allocated vs. used storage; identifies databases worth shrinking to reclaim billing waste | + +Read the README in each script directory for parameter requirements and prerequisites. + +## Key distinctions + +These are commonly confused — keep them separated: + +- **Capacity reservation vs Azure Reservation vs savings plan:** [Capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) guarantee compute supply. [Azure Reservations](https://www.finops.org/framework/capabilities/rate-optimization/) and [savings plans](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/) provide pricing discounts. Capacity guarantees supply; pricing commitments reduce cost. +- **Quota group vs management group:** [Quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) aggregate compute quota. Management groups organize subscriptions for RBAC and policy. Quota groups are created under management groups but don't inherit their policy or access controls. +- **Logical vs physical zone:** [Logical zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) are subscription-specific labels. Physical zones are datacenter locations. Zone 1 in subscription A may map to a different physical zone than zone 1 in subscription B. +- **Region access vs quota increase:** Quota increases raise limits within an already-enabled region. [Region access requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) unblock a restricted region for the subscription. + +## Operational agent + +The `azure-capacity-manager` agent is a capacity evidence specialist for FinOps workflows. It handles operational tasks like quota analysis and reservation evaluation, maps Azure capacity evidence back to FinOps capabilities, has access to the same references, and can run scripts and `az` commands for live operations. + +## Documentation map + +| Domain | Reference path | +|--------|---------------| +| Azure capacity reference | `references/docs/operations/capacity-and-quotas/README.md` | +| Glossary | `references/docs/operations/glossary.md` | +| Quota operations | `references/docs/operations/quota/README.md` | +| Quota groups | `references/docs/operations/quota-groups/README.md` | +| Capacity reservations | `references/docs/operations/capacity-reservations/README.md` | +| AKS capacity | `references/docs/operations/aks-capacity/README.md` | +| Non-compute quotas | `references/docs/operations/non-compute-quotas/README.md` | +| Monitoring and alerting | `references/docs/operations/monitoring-alerting/README.md` | +| Capacity governance | `references/docs/operations/capacity-governance/README.md` | +| Capacity planning | `references/docs/operations/capacity-planning/README.md` | +| Billing (EA) | `references/docs/billing/legacy/README.md` | +| Billing (MCA) | `references/docs/billing/modern/README.md` | +| Deployment patterns | `references/docs/deployment/README.md` | +| Tools and scripts | `references/docs/operations/tools-scripts/README.md` | +| Quota scripts | `references/scripts/quota/README.md` | +| Anomaly alerts | `references/scripts/anomaly-alerts/README.md` | +| Budgets | `references/scripts/budgets/README.md` | +| Rate optimization | `references/scripts/rate/README.md` | +| Serverless SQL storage | `references/scripts/serverless-sql-storage/README.md` | + +## Notification procedures + + +The capacity manager can send alerts and reports through [SRE Agent's notification connectors](https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications). Use Teams for urgent capacity events and email for periodic reports. + +### Teams channel alerts + +Use Teams notifications for urgent capacity events that need immediate attention, following the [Azure SRE Agent notification guidance](https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications). The SRE Agent sends messages through the Teams connector in HTML format, so keep the payload compact, scannable, and action-oriented, as described in [Send notifications from Azure SRE Agent](https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications). + +**When to send Teams alerts:** +- Quota utilization exceeds 80 percent for any VM family in a production region. +- VM deployment fails with a quota or capacity error. +- Capacity reservation group utilization drops below 50 percent, which points to wasted spend. +- Quota group is depleted or nearly depleted. +- Region access or zonal enablement request is needed. + +**Teams alert template:** + +Use this HTML template when you compose a Teams message. Include alert severity, the affected resource, current state, the recommended action, and links to the relevant Azure portal blades, following [Send notifications from Azure SRE Agent](https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications). + +```html +

⚠️ Quota utilization alert

+

Severity: warning
+VM family: Standard_D_v5
+Region: eastus
+Subscription: prod-001
+Usage: 85/100 vCPUs (85%)

+

Recommended action: Request a quota increase before the next deployment cycle.

+

+ Open quota blade
+
Open capacity reservation groups +

+``` + +### Email capacity reports + +Use Outlook email for periodic capacity reports and non-urgent recommendations, following the same [Azure SRE Agent notification guidance](https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications). The SRE Agent sends email through the Outlook connector in HTML format, so structure the message for scanning first, and detailed follow-up second. + +**When to send email reports:** +- Weekly capacity digest, including quota utilization trends across the estate. +- Reservation expiring within 30 days, including a renewal recommendation and cost analysis. +- Monthly savings plan optimization review. +- Quarterly capacity planning summary. +- Post-incident capacity analysis. + +**Email report template:** + +Use this HTML template for email reports. Include the report title, date range, a summary table of key metrics, highlighted findings, recommended actions with priority, and links to Azure portal resources or supporting documentation, as described in [Send notifications from Azure SRE Agent](https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications). + +```html +

Weekly capacity digest

+

Period: March 3–9, 2026
+Subscriptions analyzed: 47

+

Key findings

+ + + + +
RegionVM familyUtilizationAction
eastusStandard_D_v592%Request increase
westus2Standard_E_v578%Monitor
+

Recommendations

+
    +
  1. Request quota increase for Standard_D_v5 in eastus (critical)
  2. +
  3. Review CRG utilization in westeurope—45% utilized, consider right-sizing
  4. +
  5. Savings plan expires April 15—evaluate renewal versus pay-as-you-go
  6. +
+

+ Open quota blade
+ Review quota monitoring guidance +

+``` + +### Scheduled notification patterns + +Configure recurring notifications with [Azure SRE Agent scheduled tasks](https://learn.microsoft.com/en-us/azure/sre-agent/scheduled-tasks), and pair the schedule with the connector flow from [Send notifications from Azure SRE Agent](https://learn.microsoft.com/en-us/azure/sre-agent/send-notifications). + +- Daily: quota utilization check, then send a Teams alert if any family is above 80 percent. +- Weekly: capacity digest, then send email to stakeholders. +- Monthly: savings plan and reservation review, then send email with recommendations. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs deleted file mode 120000 index faec10874..000000000 --- a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs +++ /dev/null @@ -1 +0,0 @@ -../../../../../../submodules/azcapman/docs \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/README.md new file mode 100644 index 000000000..a7ae1665e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/README.md @@ -0,0 +1,16 @@ +--- +title: Billing models +nav_order: 3 +has_children: true +--- + +# Billing models + +Use this section to navigate between Microsoft Customer Agreement (modern) and Enterprise Agreement (legacy) billing guidance: + +- [`modern/`](modern/README.md)—MCA billing hierarchy, automation, and reservation scope guidance. [Source](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement) +- [`legacy/`](legacy/README.md)—Enterprise Agreement subscription creation and quota considerations. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) + +Azure enterprise customers typically operate under either the historic Enterprise Agreement (EA) or the modern Microsoft Customer Agreement (MCA). Both contracts deliver the same enterprise-grade commitment, but the MCA streamlines administration and automation workflows according to [MCA billing guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement). + +This repo treats EA and MCA customers identically for capacity planning guidance. EA customers can continue to use existing constructs, while MCA customers gain the same enterprise controls plus easier automation and tenant alignment. For an estate-level view that connects these billing models to subscription vending, quota operations, capacity reservations, and automation, see [capacity and billing operations](../operations/capacity-and-quotas/README.md). diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/legacy/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/legacy/README.md new file mode 100644 index 000000000..5d76a19c2 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/legacy/README.md @@ -0,0 +1,33 @@ +--- +title: Enterprise Agreement +parent: Billing models +nav_order: 2 +--- + +# Enterprise Agreement billing model + +## Contract and hierarchy + +- The [Enterprise Agreement (EA)](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/understand-ea-roles) uses a hierarchical structure—enrollment > departments > accounts > subscriptions—managed in the Azure Cost Management portal. +- [Enterprise Administrators](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/understand-ea-roles) control enrollment-level settings, assign Department Administrators and Account Owners, and can provision new subscriptions under any [active account](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/direct-ea-administration). + +## Billing administration tasks + +- [EA administrators](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/direct-ea-administration) manage their enrollment directly in the Azure portal: they select the billing scope, activate the enrollment, adjust policies (for example, dev/test enablement, AO/DA view charges), and configure authentication requirements for account owners. +- [Departments](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/understand-ea-roles) allow cost segmentation and quota/budget controls, while accounts own the subscriptions and surface usage/cost reports for their scope. + +## Subscription provisioning and tenant placement + +- Enterprise Administrators or Account Owners can [create EA subscriptions](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-enterprise-subscription) either for themselves or on behalf of another user, choosing the subscription directory (tenant) during creation and specifying additional subscription owners, including service principals via App IDs. +- [Cross-tenant provisioning](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-enterprise-subscription) is supported: the owner in the target tenant receives an acceptance request before the subscription is finalized. + +## Automation and service principals + +- EA exposes a dedicated [**SubscriptionCreator** role](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/assign-roles-azure-service-principals) for service principals so automation can create subscriptions at the account scope. +- [Automating EA actions](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/assign-roles-azure-service-principals) requires registering a Microsoft Entra application, capturing the service principal object ID, and assigning the desired EA role (for example, SubscriptionCreator or EnrollmentReader) via the EA REST API or PowerShell before calling subscription APIs. + +## Governance, Policy & Risk + +- [Enrollment policies](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/direct-ea-administration#view-and-manage-enrollment-policies) let administrators control who can create subscriptions (authorization levels: Microsoft Account only, Work/School only, cross-tenant) and whether dev/test offers are available to account owners. +- [EA billing roles](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/understand-ea-roles) must be assigned to individual identities (not groups) to ensure compliance and traceability; each user should have a monitored email for notifications so requests don't go unnoticed. + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/modern/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/modern/README.md new file mode 100644 index 000000000..3677e3bf2 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/modern/README.md @@ -0,0 +1,109 @@ +--- +title: Microsoft Customer Agreement +parent: Billing models +nav_order: 1 +--- + +# Microsoft Customer Agreement billing model + +## Contract overview + +- The [Microsoft Customer Agreement (MCA)](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/understand-mca-roles) is the modern Azure commerce platform that delivers the same enterprise-grade billing foundation as legacy Enterprise Agreements while simplifying contracting and ongoing administration. +- It's anchored to a single Microsoft Entra tenant, but billing owners can [associate additional tenants and link subscriptions across directories](https://learn.microsoft.com/en-us/azure/cost-management-billing/microsoft-customer-agreement/manage-tenants) without changing their resource tenancy. + +## Why ISVs move from pay-as-you-go to MCA + +- Pay-as-you-go subscriptions invoice separately, each with its own payment method, which forces you to manage multiple credit cards for production workloads at scale. +- MCA consolidates subscriptions under a single invoice payable via [wire transfer or ACH](https://learn.microsoft.com/en-us/azure/cost-management-billing/understand/pay-bill), removing the need to attach credit cards to individual subscriptions. +- MCA for enterprise supports [up to 10,000 subscriptions](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/view-all-accounts) under a single billing account, while pay-as-you-go limits you to 5 subscriptions per account. + +## Billing hierarchy + +- The [MCA billing hierarchy](https://learn.microsoft.com/en-us/azure/cost-management-billing/understand/mca-overview) flows from the billing account to billing profiles, invoice sections, and down to subscriptions, as illustrated in the official diagram below. You'll see the scopes you need to automate clearly labeled in that reference image. + +![Microsoft Customer Agreement billing hierarchy diagram](https://learn.microsoft.com/en-us/azure/cost-management-billing/understand/media/mca-overview/mca-billing-hierarchy.png) + +## Structuring costs with billing profiles and invoice sections + +- Billing profiles correspond to individual invoices and payment methods. Each [invoice section](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/mca-section-invoice) under a billing profile groups the charges that appear on that invoice, giving fine-grained cost segmentation for departments, environments, or projects. +- Billing profile owners or contributors can [create additional invoice sections](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/mca-section-invoice) directly in **Cost Management + Billing** to mirror the organization's cost centers or workload boundaries. +- Billing profiles also define the shared scope boundary for [Azure Reservations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/prepare-buy-reservation#scope-reservations) and [Savings Plans](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/scope-savings-plan) in an MCA, so shared benefits only apply to eligible subscriptions that stay within the same billing profile context. + +## Automation and service principals + +- Any automation account or pipeline that needs to [create subscriptions](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) must hold the **Azure subscription creator** role (or owner/contributor) on the target invoice section, billing profile, or billing account—otherwise it can't submit alias requests successfully. +- Microsoft's [subscription-request workflow](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription-request) allows selecting a service principal as the subscription owner by pasting its App (client) ID, confirming that service principals are first-class identities for billing operations. +- To onboard a service principal for subscription creation: + 1. Ensure the service principal exists in the Microsoft Entra tenant associated with the billing account (or an associated tenant). + 2. Assign the service principal the **Azure subscription creator** role on the desired invoice section so it can create subscriptions under that scope. The [official guidance](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) explicitly notes that the same billing roles can be granted to service principals. + 3. When triggering a [subscription request](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription-request) or calling the [subscription-creation APIs](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest), use the service principal's object ID/App ID; the portal experience accepts the value when you add it as a subscription owner. + +## Multi-tenant considerations + +- Billing owners can create subscriptions in any tenant they have associated with the MCA billing account, and they can [transfer billing ownership of existing subscriptions](https://learn.microsoft.com/en-us/azure/cost-management-billing/microsoft-customer-agreement/manage-tenants) without moving the underlying resources. +- Guest users or associated tenants can be [granted billing roles](https://learn.microsoft.com/en-us/azure/cost-management-billing/microsoft-customer-agreement/manage-tenants) so finance teams in other directories can manage invoice sections or run automation without duplicating subscriptions. + +## Rate optimization through commitments + +### MACC (Microsoft Azure Consumption Commitment) + +- A [Microsoft Azure Consumption Commitment (MACC)](https://learn.microsoft.com/en-us/marketplace/azure-consumption-commitment-benefit) is a contractual commitment to spend a specific amount on Azure over a defined period. +- Eligible Azure services and Marketplace purchases automatically count toward fulfillment, and you don't need to manually track which resources apply; however, [not all Azure Marketplace purchases count toward MACC](https://learn.microsoft.com/en-us/marketplace/azure-consumption-commitment-benefit)—verify eligibility for third-party offerings. +- You can [track your MACC progress](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/track-consumption-commitment) directly in the Azure portal under Cost Management + Billing. + +### ACD (Azure Commitment Discount) + +- Azure Commitment Discount (ACD) is a negotiated percentage discount on pay-as-you-go rates for customers with a MACC agreement. +- The discount percentage isn't fixed—it's negotiated as part of your agreement. +- When you purchase a Savings Plan, Azure [automatically applies whichever discount is better](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/discount-application)—the ACD rate or the Savings Plan rate—so you always get the optimal price. + +### Negotiated pricing + +- Organizations can negotiate discounts on their [customer price sheet](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/ea-pricing-overview), which sets custom rates for specific Azure services. +- [Reservation prices can be negotiated](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/ea-portal-vm-reservations) separately from ACD, and ACD doesn't stack on top of reservations—reservations have their own negotiated rates. + +### Visibility through FinOps Hubs + +- Use [FinOps Hubs](https://learn.microsoft.com/en-us/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) to monitor commitment discount utilization and realized savings across your estate; [FinOps Hubs requires deployment](https://learn.microsoft.com/en-us/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) before queries are available. +- The [rate optimization capability](https://www.finops.org/framework/capabilities/rate-optimization/) in the FinOps Framework provides guidance on when to use reservations versus savings plans based on workload stability. +- FinOps Hubs exposes commitment tracking queries documented in the [FinOps Toolkit query index](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md). + +### Capacity allocation as a rate optimization signal + +Capacity reservations and quota staging signal when to evaluate rate optimization purchases. + +> **Warning: Use Cost Management + Billing for enterprise-wide reservation recommendations.** +> [Azure Advisor rightsizing and shutdown recommendations use retail (pay-as-you-go) prices](https://learn.microsoft.com/en-us/azure/advisor/advisor-cost-recommendations), not your negotiated rates. Advisor's reservation recommendations do use negotiated pricing, but Advisor is limited to single-subscription scope. [Cost Management + Billing reservation recommendations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/reserved-instance-purchase-recommendations) see all VMs across your billing account and use your [negotiated price sheet](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/ea-pricing). Navigate to **Reservations > Add** in Cost Management + Billing to get accurate, estate-wide savings estimates. + +**Review usage before purchasing:** + +- [Reservation recommendations are calculated](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/reserved-instance-purchase-recommendations) by evaluating hourly usage over the past 7, 30, and 60 days. Select **See details** on any recommendation to view the usage breakdown chart. +- Review the 60-day usage pattern before purchasing. Usage spikes, seasonal patterns, and planned changes aren't reflected in the recommendation math. +- Consider purchasing 80% of the recommended quantity rather than 100%. The recommendation maximizes theoretical savings assuming consistent future usage—your actual usage will vary. + +**Evaluate before you allocate:** + +- When you create a capacity reservation or increase quota for a new workload, use that as a trigger to run the [reservation-recommendation-breakdown query](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md) to evaluate whether a reservation or savings plan makes sense. +- The query calculates `x_BreakEvenMonths` based on trailing usage patterns, which [may not account for upcoming business changes](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/reserved-instance-purchase-recommendations) like customer churn, planned migrations, or architecture pivots. +- [Savings plans can't be canceled or exchanged](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/cancel-savings-plan)—purchases are final. [Reservations allow unlimited exchanges and $50,000/year in refunds](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/exchange-and-refund-azure-reservations) for most services, but [some reservations can't be exchanged or refunded](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/exchange-and-refund-azure-reservations#products-that-cant-be-exchanged-or-refunded) (Databricks, Synapse pre-purchase, Red Hat, SUSE, Defender for Cloud, Sentinel). +- 3-year commitments offer deeper discounts than 1-year terms; use the [Azure Pricing Calculator](https://azure.microsoft.com/en-us/pricing/calculator/) to calculate specific rates for your SKUs and regions. Consider deferring long-term commitments for workloads you'll migrate to PaaS or serverless before the term expires. + +**Monitor and rebalance:** + +- Run [commitment-discount-utilization](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md) monthly to track coverage. High on-demand percentage indicates optimization headroom; your target ratio depends on workload stability and customer retention patterns. +- Set [reservation utilization alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/reservation-utilization-alerts) based on your reservation cost and workload volatility. Lower thresholds catch waste earlier but may trigger false alerts for seasonal workloads. +- Use [savings-summary-report](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md) to calculate your effective savings rate (ESR). Track ESR month-over-month as a portfolio health indicator. +- When customer churn exceeds forecast or you decommission stamps, [exchange reservations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/exchange-and-refund-azure-reservations) for different SKUs or regions within the same product family—there's no penalty for exchanges. +- For ISVs with stamp-based isolation, verify [reservation scope](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/prepare-buy-reservation#scope-reservations) (single subscription, resource group, or shared) before rescoping. Shared scope applies reservations across all subscriptions in your billing context, which can cross customer isolation boundaries and distort per-stamp cost attribution. + +**What Azure doesn't know:** + +Azure's recommendations are based on your trailing usage. They don't account for: + +- **Customer lifecycle**: A stamp serving a customer whose contract expires in 6 months shouldn't get a 3-year reservation. +- **Planned decommissioning**: Workloads migrating to serverless or a different region will break utilization assumptions. +- **Growth plans**: Historical usage doesn't reflect the customer win you're onboarding next quarter. +- **Cash flow constraints**: 3-year NPV might be better, but your CFO cares about runway. +- **Architecture pivots**: If you're evaluating a move from IaaS to AKS, consider deferring VM reservations until architecture stabilizes. + +Treat recommendations as math, not strategy. You own the business context that makes the decision. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/toc.yml b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/toc.yml new file mode 100644 index 000000000..5f453c85d --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/billing/toc.yml @@ -0,0 +1,91 @@ +- name: Capacity management + href: ../operations/README.md + items: + - name: Overview + href: ../operations/README.md + - name: Planning and forecasting + href: ../operations/capacity-planning/README.md + items: + - name: Capacity and billing operations + href: ../operations/capacity-and-quotas/README.md + - name: Capacity planning + href: ../operations/capacity-planning/README.md + - name: Customer isolation + href: ../deployment/README.md + items: + - name: Overview + href: ../deployment/README.md + - name: Single-tenant + href: ../deployment/single-tenant/README.md + - name: Multi-tenant + href: ../deployment/multi-tenant/README.md + - name: Workload placement + href: ../operations/quota/README.md + items: + - name: Billing models + href: README.md + items: + - name: Overview + href: README.md + - name: Microsoft Customer Agreement + href: modern/README.md + items: + - name: Overview + href: modern/README.md + - name: Subscription creation (billing scope) + href: ../operations/modern/README.md + - name: Enterprise Agreement + href: legacy/README.md + items: + - name: Overview + href: legacy/README.md + - name: Subscription creation (billing scope) + href: ../operations/legacy/README.md + - name: Quota operations + href: ../operations/quota/README.md + - name: Capacity reservations + href: ../operations/capacity-reservations/README.md + - name: AKS capacity governance + href: ../operations/aks-capacity/README.md + - name: Non-compute quotas + href: ../operations/non-compute-quotas/README.md + - name: Usage and rate optimization + href: ../operations/quota-groups/README.md + items: + - name: Quota groups + href: ../operations/quota-groups/README.md + - name: Governance and automation + href: ../operations/monitoring-alerting/README.md + items: + - name: Monitoring and alerting + href: ../operations/monitoring-alerting/README.md + - name: Capacity governance + href: ../operations/capacity-governance/README.md + - name: Tools and scripts + href: ../operations/tools-scripts/README.md + items: + - name: Overview + href: ../operations/tools-scripts/README.md + - name: Get-AzVMQuotaUsage.ps1 + href: ../operations/tools-scripts/get-azvmquotausage.md + - name: Get-AzAvailabilityZoneMapping.ps1 + href: ../operations/tools-scripts/get-azavailabilityzonemapping.md + - name: Show-AzVMQuotaReport.ps1 + href: ../operations/tools-scripts/show-azvmquotareport.md + - name: Get-BenefitRecommendations.ps1 + href: ../operations/tools-scripts/get-benefitrecommendations.md + - name: Deploy-AnomalyAlert.ps1 + href: ../operations/tools-scripts/deploy-anomalyalert.md + - name: Deploy-BulkALZ.ps1 + href: ../operations/tools-scripts/deploy-bulkalz.md + - name: Support and reference + href: ../operations/support-and-reference/README.md + items: + - name: Overview + href: ../operations/support-and-reference/README.md + - name: Support escalation + href: ../operations/escalation/README.md + - name: Tenant hygiene + href: ../operations/tenant-hygiene/README.md + - name: Glossary + href: ../operations/glossary.md diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/README.md new file mode 100644 index 000000000..392c9e5f0 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/README.md @@ -0,0 +1,23 @@ +--- +title: Customer isolation +nav_order: 2 +has_children: true +--- + +# Customer isolation + +ISVs commonly operate on two primary delivery models highlighted in [Microsoft's landing zone guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone). The [ISV landing zone documentation](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) describes pure SaaS, customer-deployed, and dual-deployment SaaS models and how they relate to Azure landing zones. This folder focuses on pure SaaS scenarios where the ISV controls subscriptions and isolates customers through dedicated or shared deployment stamps. + +![SaaS Deployment Topologies showing single-tenant subscription isolation vs multi-tenant shared infrastructure](../images/deployment-topologies.svg) + +- Dedicated (single-tenant) environments where each customer receives an isolated subscription and landing zone. +- Shared (multi-tenant) SaaS platforms that centralize control planes while segmenting tenant workloads through application logic and deployment stamps. + +The [ISV landing zone guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) identifies three common deployment models—pure SaaS, customer-deployed, and dual-deployment SaaS—each with different landing zone implications. The guides in this directory show how those models map to Azure subscription and landing zone design so you can adopt the pattern that fits your product roadmap. + +Use this directory to choose the isolation model that aligns with your product offering: + +- [Single-tenant deployment guide](single-tenant/README.md)—guidance for customer-isolated deployments, including subscription vending, landing zone setup, and availability zone alignment. +- [Multi-tenant deployment guide](multi-tenant/README.md)—guidance for centrally operated SaaS solutions that rely on shared infrastructure, deployment stamps, and multitenant governance. + +Before diving into either model, review the [Azure landing zone guidance tailored for ISVs](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone). It shows how to structure management groups, subscriptions, and shared services to support both deployment approaches. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/multi-tenant/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/multi-tenant/README.md new file mode 100644 index 000000000..00be0dba9 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/multi-tenant/README.md @@ -0,0 +1,71 @@ +--- +title: Multi-tenant +parent: Customer isolation +nav_order: 2 +--- + +# Multi-tenant deployment guide + +Use this guide for SaaS offerings where multiple customers share a centralized platform. The [ISV landing zone guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) describes these scenarios as "pure SaaS" or "dual-deployment" models, depending on whether customers also receive dedicated environments. You'll use this guide to plan tenant isolation, deployment stamps, and supporting services that maintain reliability at scale. + +![Multi-Tenant SaaS Architecture showing shared infrastructure with application-level isolation](../../images/multi-tenant-topology.svg) + +## Critical subscription service limits + +**WARNING**: [Azure subscription service limits](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits) impose hard architectural constraints that affect multi-tenant designs far more than quota limits. These aren't negotiable—they're platform constraints that dictate your architecture: + +### Storage account limits +- **250 storage accounts per region per subscription** (500 with support request) +- If you isolate customer data in separate storage accounts, you hit a scaling wall at 250 tenants +- Each storage account limited to 40,000 requests/second in primary regions +- Maximum 200 private endpoints per storage account limits network isolation options + +### Resource group constraints +- **980 resource groups per subscription maximum** +- **800 resources per resource group, per resource type** +- If you use resource groups for tenant isolation, you're capped at 980 tenants per subscription +- Tagged resource groups further reduce this limit + +### Compute and app limits +- **100 App Service plans per resource group** +- **100 function apps per subscription** (Consumption tier) +- **512 access restriction rules per app** constrains IP-based tenant isolation + +### Network isolation boundaries +- **200 private endpoints per app service** +- Virtual network limits vary by region and subscription type +- Network security group rules have regional caps + +These [service limits](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits) force critical architectural decisions from day one. Unlike quotas that you can request increases for, these are immutable platform constraints that determine whether you need multiple subscriptions, how you isolate tenants, and when you must implement deployment stamps. + +## Architectural principles + +- **Balance all Well-Architected pillars.** SaaS providers must design for reliability, security, cost, operations, and performance simultaneously. Evaluate trade-offs for each release and document how they affect [tenant experience](https://learn.microsoft.com/en-us/azure/well-architected/saas/design-principles). +- **Adopt Zero Trust and least privilege.** Isolate tenants through identity, networking, and data segmentation. Combine resource-level controls with application-layer enforcement to prevent [cross-tenant leakage](https://learn.microsoft.com/en-us/azure/well-architected/saas/design-principles). +- **Design within service limits.** Unlike quotas, [subscription service limits](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits) are fixed platform constraints. Architecture decisions must accommodate these non-negotiable boundaries. + +## Deployment stamps and control planes + +- **Shared deployment stamps.** Use the [Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) to scale out infrastructure units that each host multiple tenants. Stamps simplify safe deployment, progressive rollout, and regional expansion. +- **Control plane design.** Separate centralized services (portal, onboarding pipeline, provisioning API) from tenant workloads. The [control plane](https://learn.microsoft.com/en-us/azure/well-architected/saas/design-principles) coordinates stamp creation, tenant placement, and lifecycle operations. +- **Zone alignment for stamps.** When stamps span multiple subscriptions, run `scripts/quota/Get-AzAvailabilityZoneMapping.ps1` to verify logical-to-physical zone mappings. Azure randomizes zone assignments per subscription, so logical zone 1 in subscription A may map to a different physical datacenter than zone 1 in subscription B. This script reveals actual mappings for proper fault domain alignment. + +## Tenancy model decisions + +- **Resource sharing tiers.** Decide which components remain multitenant (for example, compute cluster, databases) versus per-tenant. Factor in cost modeling, [noisy-neighbor risk](https://learn.microsoft.com/en-us/azure/well-architected/saas/compute#tenancy-model-and-isolation), and customer-specific compliance commitments. +- **Governance and monitoring.** Instrument [per-tenant metrics and quotas](https://learn.microsoft.com/en-us/azure/well-architected/saas/compute#tenancy-model-and-isolation) even when tenants share resources. This enables proactive detection of overconsumption and supports usage-based billing. + +## Data architecture + +- **Data store selection.** Choose [transactional data stores](https://learn.microsoft.com/en-us/azure/well-architected/saas/data) that match workload needs (relational vs. nonrelational) and support tenant growth. Minimize the number of technologies to reduce operational complexity. +- **Isolation strategies.** Implement [database-per-tenant, schema-per-tenant, or shared tables with tenant keys](https://learn.microsoft.com/en-us/azure/well-architected/saas/data) depending on compliance and scale requirements. Remember that [storage account limits](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits) (250 per region) constrain per-tenant storage isolation—plan for multi-subscription architectures before you hit these walls. +- **Scale planning.** Document how you enforce tenant-level backup, restore, and data residency guarantees within [service limits](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits). Storage-account-per-tenant architectures fail at 250 tenants without proactive subscription scaling strategies. + +## Operational excellence + +- **Safe deployments.** Use [progressive exposure](https://learn.microsoft.com/en-us/azure/well-architected/saas/design-principles) (rings, feature flags) when rolling out new releases across stamps. Monitor health signals per tenant and stamp to trigger rollbacks based on clear thresholds and policies. +- **Cost governance.** Track [cost of goods sold (COGS)](https://learn.microsoft.com/en-us/azure/well-architected/saas/design-principles) per tenant and align pricing tiers with resource consumption. Automate reporting so finance teams can adjust pricing or optimize resource allocation. + +## Landing zone integration + +- Build the underpinning [Azure landing zone with ISV guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) to guarantee management groups, policy assignments, and cross-subscription networking support multitenant growth. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/single-tenant/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/single-tenant/README.md new file mode 100644 index 000000000..f4e27591f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/single-tenant/README.md @@ -0,0 +1,95 @@ +--- +title: Single-tenant +parent: Customer isolation +nav_order: 1 +--- + +# Single-tenant deployment guide + +Use this guide when each customer gets a dedicated Azure subscription or deployment stamp. The [ISV landing zone guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) defines this "customer-deployed" model as one of the core ISV patterns—customers run workloads inside subscriptions that you provision or manage on their behalf. This approach maximizes isolation, aligns with per-customer regulatory requirements, and simplifies noisy-neighbor mitigation at the expense of higher infrastructure cost per tenant using the [deployment stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern). + +![Single-Tenant SaaS Architecture showing subscription-isolated customer deployments](../../images/single-tenant-topology.svg) + +## Subscription quota flow without quota groups + +When each subscription manages its own quota independently, the subscription vending workflow introduces several failure points that can block or delay customer onboarding. Azure's Quota API handles most regional VM quota increases programmatically, but specific scenarios require manual support ticket escalation. + +```mermaid +flowchart TB + Start([Start]) --> CreateSub[Create Subscription] + CreateSub --> ForEach[For Each Subscription] + ForEach --> Retrieve[Retrieve Quota and Zonal Status] + + Retrieve --> ZonalCheck{Zonal Enablement
Required?} + + ZonalCheck -->|Yes| ZonalQuotaCheck{Quota
Required?} + ZonalCheck -->|No| QuotaOnlyCheck{Quota
Required?} + + ZonalQuotaCheck -->|Yes| ZonalQuotaAPI[Quota API Call] + ZonalQuotaCheck -->|No| ZonalNoQuota[Support Ticket
Zonal enablement only]:::fail + + QuotaOnlyCheck -->|Yes| QuotaOnlyAPI[Quota API Call] + QuotaOnlyCheck -->|No| Complete1([Complete]):::success + + ZonalQuotaAPI --> ZonalAPIResult{API
Success?} + ZonalAPIResult -->|Success| Complete2([Complete]):::success + ZonalAPIResult -->|Fail| ZonalFail[Support Ticket]:::fail + + QuotaOnlyAPI --> QuotaAPIResult{API
Success?} + QuotaAPIResult -->|Success| Complete3([Complete]):::success + QuotaAPIResult -->|Fail| QuotaFail[Support Ticket]:::fail + + classDef fail fill:#ffcccc,stroke:#cc0000,stroke-width:2px,color:#000 + classDef success fill:#ccffcc,stroke:#00cc00,stroke-width:2px,color:#000 +``` + + +> [!WARNING] +> **Quota API rejection.** The [Quota API](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) rejects increase requests when regional capacity is constrained, rate limits are exceeded, or the SKU is restricted by subscription offer type. API rejections return error codes but don't provide capacity availability timelines—operators can't distinguish between temporary capacity shortages and permanent regional restrictions without opening a support ticket. + +> [!WARNING] +> **Zonal enablement isn't self-service.** GPU VM families and other restricted SKUs require [zonal enablement requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) through Azure Support before the Quota API will accept increases. This means subscriptions that need both zonal enablement and quota increases require at least one manual support ticket per subscription-SKU combination, even if the subscription only needs a single VM. + +> [!WARNING] +> **N×M ticket explosion.** When vending multiple subscriptions (N) that each require multiple restricted SKUs (M), the foreach loop over subscriptions generates N×M support tickets. If 10 customers each need 3 GPU SKUs across 2 regions, that's 60 individual tickets—each requiring manual review and approval before deployment can proceed. + +> [!WARNING] +> **Timing gaps.** Quota API requests complete in minutes to hours when capacity is available. Support tickets for zonal enablement or [region access](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) take 3-10 business days on average, and responses don't guarantee capacity—they only confirm eligibility. This timing variance makes it difficult to commit to onboarding SLAs when you can't predict which subscriptions will hit the manual path. +> +> *These timelines reflect Microsoft CSU operational experience, not documented Azure SLAs.* + +> [!IMPORTANT] +> **Quota doesn't guarantee capacity.** Approved quota increases establish the subscription's entitlement ceiling but don't reserve physical capacity. ARM deployments can still fail with `SkuNotAvailable` errors when regional capacity is exhausted, even if the subscription has sufficient quota headroom. This gap between quota approval and deployment success means testing the full onboarding flow in production is the only way to validate capacity availability. + +## Landing zone preparation + +1. **Design the control plane.** Follow the [ISV landing zone guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) to organize management groups, policies, and shared services before onboarding customer subscriptions. Separate corporate IT assets from the SaaS product landing zone if your organization uses different operating models. +2. **Define subscription vending workflows.** Automate subscription creation (EA or MCA) and attach the new subscription to the correct management group, policy assignments, and billing profile. Capture owner/contributor assignments during provisioning so operations teams can [manage the environment end to end](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone). +3. **Apply baseline policies.** Enforce guardrails for networking, identity, tagging, cost management, and diagnostics so every customer environment starts [compliant with corporate standards](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone). + +## Deployment stamps + +- **Stamp per customer.** Deploy a repeatable infrastructure footprint (virtual network, hub services, shared monitoring) per customer. [Single-tenant stamps](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) provide clear isolation boundaries and avoid the need for multitenant logic inside the workload. +- **Automate stamp rollout.** Use infrastructure as code (Bicep, Terraform, ARM) or SDK automation to instantiate the stamp whenever a new customer onboards. Maintain versioning so [upgrades can be rolled out safely](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) across the stamp fleet. +- **Support dual-deployment scenarios.** Some ISVs offer both dedicated and shared deployment options. Document how the single-tenant stamp integrates with any central control plane so you can [reuse automation and monitoring patterns](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) across models. +- **Plan for regional variation.** Some customers require specific geographies or availability zones. Incorporate availability zone alignment and [regional access requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) into the onboarding checklist to prevent last-minute deployment blocks. + +## Workload configuration + +- **Compute isolation.** Choose SKUs and scaling rules that reflect customer contract expectations. Single-tenant models justify higher per-customer spend, so [align pricing with the required compute footprint and SLAs](https://learn.microsoft.com/en-us/azure/well-architected/saas/compute#tenancy-model-and-isolation). +- **Data isolation.** Provision dedicated data stores (for example, separate Azure SQL databases or Cosmos DB accounts) per customer. This simplifies compliance audits and supports [customer-specific backup/restore operations](https://learn.microsoft.com/en-us/azure/well-architected/saas/data). + +## Cost allocation surfaces + +Azure exposes these surfaces for per-tenant cost tracking in single-tenant deployments: + +- **Tag inheritance:** [Tag inheritance policies](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/enable-tag-inheritance) apply subscription and resource group tags to cost records, allowing filtering by customer or business unit without modifying resources. +- **Cost data ingestion:** [FinOps Hubs](https://learn.microsoft.com/en-us/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) aggregates cost data from tenant subscriptions into Azure Data Explorer for analysis across the stamp fleet. +- **Cost exports:** [Scheduled exports](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/tutorial-export-acm-data) deliver cost data to storage accounts for integration with internal systems. + +## Lifecycle management + +- **Onboarding:** Automate the sequence—create subscription, apply the landing zone blueprint, deploy the stamp, run validation tests, and hand over to customer success so teams aren't rebuilding steps manually. +- **Expansion:** When customers need more capacity, scale the stamp vertically or horizontally, or [deploy additional stamps](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) for regional redundancy. Coordinate with quota and reservation guides to guarantee capacity. +- **Recycle vs. retire:** When a customer churns, reclaim quotas and shared services but keep the subscription if [region/zone enablement or regulatory approvals](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) might be reused for future tenants. + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/toc.yml b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/toc.yml new file mode 100644 index 000000000..b62f5bbb7 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/deployment/toc.yml @@ -0,0 +1,91 @@ +- name: Capacity management + href: ../operations/README.md + items: + - name: Overview + href: ../operations/README.md + - name: Planning and forecasting + href: ../operations/capacity-planning/README.md + items: + - name: Capacity and billing operations + href: ../operations/capacity-and-quotas/README.md + - name: Capacity planning + href: ../operations/capacity-planning/README.md + - name: Customer isolation + href: README.md + items: + - name: Overview + href: README.md + - name: Single-tenant + href: single-tenant/README.md + - name: Multi-tenant + href: multi-tenant/README.md + - name: Workload placement + href: ../operations/quota/README.md + items: + - name: Billing models + href: ../billing/README.md + items: + - name: Overview + href: ../billing/README.md + - name: Microsoft Customer Agreement + href: ../billing/modern/README.md + items: + - name: Overview + href: ../billing/modern/README.md + - name: Subscription creation (billing scope) + href: ../operations/modern/README.md + - name: Enterprise Agreement + href: ../billing/legacy/README.md + items: + - name: Overview + href: ../billing/legacy/README.md + - name: Subscription creation (billing scope) + href: ../operations/legacy/README.md + - name: Quota operations + href: ../operations/quota/README.md + - name: Capacity reservations + href: ../operations/capacity-reservations/README.md + - name: AKS capacity governance + href: ../operations/aks-capacity/README.md + - name: Non-compute quotas + href: ../operations/non-compute-quotas/README.md + - name: Usage and rate optimization + href: ../operations/quota-groups/README.md + items: + - name: Quota groups + href: ../operations/quota-groups/README.md + - name: Governance and automation + href: ../operations/monitoring-alerting/README.md + items: + - name: Monitoring and alerting + href: ../operations/monitoring-alerting/README.md + - name: Capacity governance + href: ../operations/capacity-governance/README.md + - name: Tools and scripts + href: ../operations/tools-scripts/README.md + items: + - name: Overview + href: ../operations/tools-scripts/README.md + - name: Get-AzVMQuotaUsage.ps1 + href: ../operations/tools-scripts/get-azvmquotausage.md + - name: Get-AzAvailabilityZoneMapping.ps1 + href: ../operations/tools-scripts/get-azavailabilityzonemapping.md + - name: Show-AzVMQuotaReport.ps1 + href: ../operations/tools-scripts/show-azvmquotareport.md + - name: Get-BenefitRecommendations.ps1 + href: ../operations/tools-scripts/get-benefitrecommendations.md + - name: Deploy-AnomalyAlert.ps1 + href: ../operations/tools-scripts/deploy-anomalyalert.md + - name: Deploy-BulkALZ.ps1 + href: ../operations/tools-scripts/deploy-bulkalz.md + - name: Support and reference + href: ../operations/support-and-reference/README.md + items: + - name: Overview + href: ../operations/support-and-reference/README.md + - name: Support escalation + href: ../operations/escalation/README.md + - name: Tenant hygiene + href: ../operations/tenant-hygiene/README.md + - name: Glossary + href: ../operations/glossary.md diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/docfx.yml b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/docfx.yml new file mode 100644 index 000000000..965b7a258 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/docfx.yml @@ -0,0 +1,45 @@ +### YamlMime:DocFX +metadata: +- name: _appTitle + content: ISV Quota & Capacity Management +- name: _appName + content: Azure ISV Documentation +- name: _enableNewTab + content: true +- name: _enableSearch + content: true + +build: + content: + - files: + - "**/*.md" + - "**/*.yml" + exclude: + - "_site/**" + - "obj/**" + src: . + dest: . + resource: + - files: + - "images/**" + - "**/*.png" + - "**/*.jpg" + - "**/*.jpeg" + - "**/*.gif" + - "**/*.svg" + overwrite: + - files: + - "apidoc/**.md" + exclude: + - "obj/**" + - "_site/**" + globalMetadata: + _appTitle: ISV Quota & Capacity Management + _appFooter: Copyright © 2024 Microsoft Corporation + _gitContribute: + repo: https://github.com/microsoft/azcapman + branch: main + template: + - default + - modern + dest: _site \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/azure-logo.svg b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/azure-logo.svg new file mode 100644 index 000000000..0ad8bbe1f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/azure-logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/deployment-topologies.svg b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/deployment-topologies.svg new file mode 100644 index 000000000..c1bfb9f30 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/deployment-topologies.svg @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + SaaS Deployment Topologies for ISVs + + + + Customer Isolation Strategies in Azure + + + + + + + + + + + Single-Tenant SaaS (Subscription Isolated) + + + + + + ISV Control Plane + + + Provisioning, Billing, Management + + + + + Customer Azure Subscriptions: + + + + + + + Customer A Subscription + + + + Resources + + + + Database + + + + + + + + Customer B Subscription + + + + Resources + + + + Database + + + + + + + + Customer C Subscription + + + + Resources + + + + Database + + + + + + + + Customer D Subscription + + + + Resources + + + + Database + + + + + + Key Characteristics: + + + • Full infrastructure isolation per customer + + + • Independent scaling and deployment + + + • Customer-specific compliance boundaries + + + • Higher operational overhead + + + + + + + + + + + + Multi-Tenant SaaS (Shared Infrastructure) + + + + + + ISV Shared Platform (Single/Few Subscriptions) + + + + + + Control Plane (Authentication, Billing, Provisioning) + + + + + + Application Tier + + + + + Customer A + + + + Customer B + + + + Customer C + + + + Customer D + + + + + + Shared Database with Logical Isolation + + + + + + Multi-Tenant Database + + + + TenantID | Data | ... + + + Row-Level Security + + + + + Key Characteristics: + + + • Shared infrastructure across all customers + + + • Application-level tenant isolation + + + • Efficient resource utilization + + + • Lower per-customer operational cost + + + + + + + + + + + + + + + Single-Tenant SaaS + + + Isolation Level: + + + Infrastructure + + + Resource Model: + + + 1:1 (Customer:Subscription) + + + + + Multi-Tenant SaaS + + + Isolation Level: + + + Application + + + Resource Model: + + + N:1 (Customers:Platform) + + + + + vs + + + \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/multi-tenant-topology.svg b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/multi-tenant-topology.svg new file mode 100644 index 000000000..fdfb2acd1 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/multi-tenant-topology.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + Multi-Tenant SaaS Architecture + + + + Shared Infrastructure with Application Isolation + + + + + + + + + + + Multi-Tenant SaaS (Shared Infrastructure) + + + + + + ISV Shared Platform (Single/Few Subscriptions) + + + + + + Control Plane (Authentication, Billing, Provisioning) + + + + + + Application Tier + + + + + Customer A + + + + Customer B + + + + Customer C + + + + Customer D + + + + + + Shared Database with Logical Isolation + + + + + + Multi-Tenant Database + + + + TenantID | Data | ... + + + Row-Level Security + + + + + Key Characteristics: + + + • Shared infrastructure across all customers + + + • Application-level tenant isolation + + + • Efficient resource utilization + + + • Lower per-customer operational cost + + + + + + + + Isolation Level: Application + + + Resource Model: N:1 (Customers:Platform) + + + \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/single-tenant-topology.svg b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/single-tenant-topology.svg new file mode 100644 index 000000000..81bc88182 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/images/single-tenant-topology.svg @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + Single-Tenant SaaS Architecture + + + + Subscription-Isolated Customer Deployments + + + + + + + + + + + Single-Tenant SaaS (Subscription Isolated) + + + + + + ISV Control Plane + + + Provisioning, Billing, Management + + + + + Customer Azure Subscriptions: + + + + + + + Customer A Subscription + + + + Resources + + + + Database + + + + + + + + Customer B Subscription + + + + Resources + + + + Database + + + + + + + + Customer C Subscription + + + + Resources + + + + Database + + + + + + + + Customer D Subscription + + + + Resources + + + + Database + + + + + + Key Characteristics: + + + • Full infrastructure isolation per customer + + + • Independent scaling and deployment + + + • Customer-specific compliance boundaries + + + • Higher operational overhead + + + + + + + + Isolation Level: Infrastructure + + + Resource Model: 1:1 (Customer:Subscription) + + + \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/index.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/index.md new file mode 100644 index 000000000..50f6761f1 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/index.md @@ -0,0 +1,100 @@ +--- +title: Overview +nav_order: 1 +--- + +
+

Azure capacity governance for ISVs

+

Azure quota, access, reservations, monitoring, and billing controls mapped to the canonical FinOps Framework capabilities for SaaS ISV estates.

+ Open the capability map → +
+ + + +
+ +## FinOps capability map + +Learn how Azure capacity evidence supports the FinOps Framework capabilities for SaaS ISV estates. The FinOps Foundation defines Domains and Capabilities as the outcomes and activities of a FinOps practice, not as a serial process. [Source](https://www.finops.org/framework/) [Source](https://www.finops.org/framework/domains/) + +
+
+ +### Plan and forecast demand + +- [Capacity planning](operations/capacity-planning/README.md) +- [Scale units and stamps](deployment/README.md) +- [Capacity and billing operations](operations/capacity-and-quotas/README.md) + +
+
+ +### Place workloads and secure capacity + +- [Region access requests](operations/quota/README.md) +- [Quota increases](operations/quota/README.md#requesting-quota-increases) +- [Quota groups](operations/quota-groups/README.md) +- [Capacity reservations](operations/capacity-reservations/README.md) + +
+
+ +### Optimize, govern, and automate + +- [Monitoring and alerts](operations/monitoring-alerting/README.md) +- [Governance program](operations/capacity-governance/README.md) +- [Escalation paths](operations/escalation/README.md) +- [Support and reference](operations/support-and-reference/README.md) + +
+
+
+ +
+ +## Explore more + +
+
+

Customer isolation

+

Single-tenant and multi-tenant deployment patterns for ISVs.

+
+
+

Billing enrollment

+

EA and MCA billing structures for capacity management.

+
+
+

Glossary

+

Key terms and definitions for capacity governance.

+
+
+
diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-02-forecasting.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-02-forecasting.md new file mode 100644 index 000000000..d6c44d73f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-02-forecasting.md @@ -0,0 +1,654 @@ +# Lab 2: Forecasting + +## Overview + +Forecasting capacity needs is about collecting utilization signals, analyzing patterns, and translating them into infrastructure commitments. This lab walks you through using Azure Cost Management APIs, quota telemetry, and utilization metrics to build a forecast of compute and storage demand across your SaaS platform, aligned with [Well-Architected capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) guidance. + +You'll gather baseline quota usage, analyze utilization patterns in Azure Monitor, pull savings plan recommendations, assess storage costs, and map your forecast to deployment scale units. These outputs feed directly into procurement and allocation decisions. + +> **Pilot scope boundary:** Forecasting improves planning quality and escalation readiness, but it doesn't guarantee regional or zonal service availability on its own. Region and zone deployment access still depends on subscription-level access approvals and current capacity availability in Azure regions ([Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [Region access request process](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process), [Zonal enablement request process](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series)). + +### Required lab outputs + +Produce these outputs before moving to procurement and allocation work: + +1. **FY26 forecasting template output** with assumptions, confidence ranges, and quarter-by-quarter demand projections ([Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)). +2. **Technical action register** with signal, threshold, evidence, recommended action, and validation timestamp for every identified quota, capacity, or cost action ([Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain)). +3. **Escalation-ready evidence pack** with support-ready artifacts for quota, region access, and reservation blockers ([Create an Azure support request](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request), [Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests)). +4. **Regional PaaS readiness matrix** for non-compute services in each target region, backed by reproducible API output ([Azure REST API reference](https://learn.microsoft.com/en-us/rest/api/azure/), [Azure CLI quota reference](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest)). + +### Technical decision evidence model + +Capture a decision artifact only when forecast output changes one or more technical control values: + +- Target deployment date or milestone date +- Target region or availability zone +- Requested quota, capacity reservation quantity, or commitment amount +- Service scaling boundary (for example, storage sharding, partitioning, or throughput target) + +If none of these values change, keep the item as an observation in your evidence workbook, not as a decision artifact ([Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [FinOps planning and estimating](https://www.finops.org/framework/capabilities/planning-estimating/)). + +> **Policy callout:** All training steps in this lab must be reproducible with publicly documented Azure APIs or documented CLI surfaces. Don't rely on private tools, unpublished endpoints, or portal-only behavior without an API equivalent ([Azure REST API reference](https://learn.microsoft.com/en-us/rest/api/azure/), [Azure CLI overview](https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli)). + +**Prerequisites:** +- Authenticated access to a billing scope and at least one Azure subscription that contains workload resources for analysis ([scripts/rate/README.md](../../scripts/rate/README.md), [Azure subscriptions and management groups](https://learn.microsoft.com/en-us/azure/governance/management-groups/overview)) +- A supported command surface for reproducible queries: Azure CLI and, for PowerShell examples in this lab, the Az PowerShell modules used by the scripts ([Azure CLI overview](https://learn.microsoft.com/en-us/cli/azure/what-is-azure-cli), [Install Azure PowerShell](https://learn.microsoft.com/en-us/powershell/azure/install-azure-powershell), [scripts/rate/README.md](../../scripts/rate/README.md), [scripts/quota/README.md](../../scripts/quota/README.md)) +- Read access on the target billing or subscription scope so you can query cost, quota, and monitoring data ([scripts/rate/README.md](../../scripts/rate/README.md), [Use cost alerts to monitor usage and spending](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending), [How to monitor quotas and generate alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting)) + +--- + +## Exercise 1: Gather baseline quota and usage data + +**Objective:** Collect current quota limits and actual usage across compute SKUs and regions to understand headroom for growth. + +Quota tells you what you're allowed to run, and usage tells you what you're actually running. The gap is your growth buffer for planning and escalation lead time ([Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)). + +### Step 1.1: Export VM SKU quota usage across subscriptions + +Run the multithreaded quota analysis script to scan all subscriptions for compute quota: + +```powershell +.\scripts/quota/Get-AzVMQuotaUsage.ps1 ` + -SKUs "Standard_D2s_v3", "Standard_D4s_v3", "Standard_E2s_v3", "Standard_E4s_v3" ` + -Locations "eastus", "westus2", "northeurope" ` + -Threads 4 ` + -UsePhysicalZones +``` + +This script: +- Queries each subscription in parallel (4 concurrent threads) ([Get-AzVMQuotaUsage script](../../scripts/quota/Get-AzVMQuotaUsage.ps1), [quota scripts README](../../scripts/quota/README.md)) +- Returns quota limits, current usage, and utilization % per SKU per location ([Get-AzVMQuotaUsage script](../../scripts/quota/Get-AzVMQuotaUsage.ps1), [quota scripts README](../../scripts/quota/README.md)) +- Identifies subscriptions approaching quota limits (the constraint on scaling) ([Get-AzVMQuotaUsage script](../../scripts/quota/Get-AzVMQuotaUsage.ps1), [quota scripts README](../../scripts/quota/README.md)) +- Includes physical zone information if -UsePhysicalZones is set ([Get-AzVMQuotaUsage script](../../scripts/quota/Get-AzVMQuotaUsage.ps1), [quota scripts README](../../scripts/quota/README.md)) + +**Output interpretation:** +- Use your own alert policy thresholds for investigation and escalation. If you use >80% and <20% as internal triage bands, treat them as operator-defined heuristics, not Azure platform defaults ([How to monitor quotas and generate alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)) +- Compare across regions to identify uneven capacity distribution + +### Step 1.2: Query quota usage via Azure CLI + +For a specific subscription and region, use the CLI to drill down: + +```bash +az vm list-usage \ + --location eastus \ + --subscription YOUR_SUBSCRIPTION_ID \ + --query "[?contains(name.value, 'DSv3')].{Family: name.localizedValue, Limit: limit, CurrentUsage: currentValue}" \ + --output table +``` + +This returns per-family vCPU limits and current usage. Filter by family name substring (e.g., `DSv3`, `ESv3`) — the `name.value` field contains family identifiers like `standardDSv3Family`, not individual SKU names. + +Reference the [az vm list-usage documentation](https://learn.microsoft.com/en-us/cli/azure/vm?view=azure-cli-latest#az-vm-list-usage) for output schema details. + +**What to look for (operator-defined triage heuristics):** +- Subscriptions or regions where current usage approaches configured alert thresholds for the quota family. +- SKU families with sustained low utilization relative to allocated limits. +- Regional concentration patterns that create uneven headroom across target deployment regions. + +References: [How to monitor quotas and generate alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning). + +### Step 1.3: Document baseline + +Save the output CSVs. You'll use these as a baseline to track growth rate quarter-over-quarter. + +Also capture escalation evidence fields in your baseline workbook so the output can move directly into support or capacity escalation when needed: + +- Subscription ID, tenant ID, and billing scope +- Region and availability zone (logical and physical mapping, where applicable) +- VM family, current limit, current usage, requested limit, and utilization % +- Blocking deployment timestamp, error code, and failed operation ID +- Forecasted demand window (date range), estimated shortfall, and business impact statement +- Evidence links (CLI output, script export, workbook snapshot), and last validated date + +References: [Create an Azure support request](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request), [Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests), [Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain). + +### Step 1.4: Run explicit multi-subscription analysis and hand off allocation decisions + +Run this exercise across all in-scope subscriptions, not a single subscription sample. Forecast quality depends on estate-level variance by subscription and region ([Quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)). + +At the end of Exercise 1, hand off these outputs to [Lab 3: Allocation](./lab-03-allocation.md) for quota-group allocation decisions: + +- Regional and per-family utilization heatmap by subscription +- Candidate subscriptions for quota transfer or rebalance +- Escalation candidates where projected demand exceeds available headroom + +### Step 1.5: Run non-compute quota and access checks with public APIs + +Run service-specific checks in parallel with compute quota checks. Quota groups cover IaaS compute, not PaaS service limits ([Quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups), [Non-compute quota guide](../operations/non-compute-quotas/README.md)). + +**Azure SQL Database usage check (`Microsoft.Sql/locations/usages`):** + +```bash +az rest --method GET \ + --url "https://management.azure.com/subscriptions/YOUR_SUBSCRIPTION_ID/providers/Microsoft.Sql/locations/eastus/usages?api-version=2023-08-01-preview" +``` + +Reference: [SQL usage operations](https://learn.microsoft.com/en-us/rest/api/sql/usages/list-by-location). + +> **API version hygiene:** This sample uses a preview API version (`2023-08-01-preview`). Before running it in production or automation, verify the current supported `Microsoft.Sql` `usages` API version in the [SQL usage operations reference](https://learn.microsoft.com/en-us/rest/api/sql/usages/list-by-location), and update the command if a newer stable version is available. + +**Azure Cosmos DB regional readiness check (regional footprint and account capability):** + +```bash +az cosmosdb show \ + --resource-group YOUR_RESOURCE_GROUP \ + --name YOUR_COSMOS_ACCOUNT \ + --query "{writeRegions:writableLocations[].locationName,readRegions:readableLocations[].locationName,capabilities:capabilities[].name}" \ + --output json +``` + +Reference: [Azure Cosmos DB account management and global distribution](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/how-to-manage-database-account), [az cosmosdb reference](https://learn.microsoft.com/en-us/cli/azure/cosmosdb?view=azure-cli-latest). + +**Azure Database for PostgreSQL regional capability check (`az postgres flexible-server list-skus`):** + +```bash +az postgres flexible-server list-skus \ + --location eastus \ + --output table +``` + +Reference: [az postgres flexible-server list-skus](https://learn.microsoft.com/en-us/cli/azure/postgres/flexible-server?view=azure-cli-latest#az-postgres-flexible-server-list-skus). + +If you need a REST equivalent for automation parity, keep that endpoint mapping as pending validation in this lab revision, and only add it after validating the exact API path and version in Microsoft Learn. + +**Azure App Service quota and zonal readiness checks (`Microsoft.Web`):** + +```bash +# 1) Subscription-level App Service quota usage surface +az quota usage list \ + --scope /subscriptions/YOUR_SUBSCRIPTION_ID \ + --resource-provider Microsoft.Web \ + --output json + +# 2) App Service plan zonal readiness surface +az appservice plan show \ + --resource-group YOUR_RESOURCE_GROUP \ + --name YOUR_APP_SERVICE_PLAN \ + --query "{id:id,location:location,sku:sku.name,zoneRedundant:properties.zoneRedundant,maximumNumberOfZones:properties.maximumNumberOfZones,numberOfWorkers:properties.numberOfWorkers,maximumNumberOfWorkers:properties.maximumNumberOfWorkers}" \ + --output json +``` + +References: [az quota usage list](https://learn.microsoft.com/en-us/cli/azure/quota/usage?view=azure-cli-latest#az-quota-usage-list), [az appservice plan show](https://learn.microsoft.com/en-us/cli/azure/appservice/plan?view=azure-cli-latest#az-appservice-plan-show), [App Service Plans - Get (Microsoft.Web/serverfarms)](https://learn.microsoft.com/en-us/rest/api/appservice/app-service-plans/get?view=rest-appservice-2024-11-01). + +**Optional instance-level evidence (physical zone signal from runtime instances):** + +```bash +# 3a) List app instances +az rest --method GET \ + --url "https://management.azure.com/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP/providers/Microsoft.Web/sites/YOUR_APP_NAME/instances?api-version=2024-11-01" + +# 3b) Get one instance detail +az rest --method GET \ + --url "https://management.azure.com/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP/providers/Microsoft.Web/sites/YOUR_APP_NAME/instances/YOUR_INSTANCE_ID?api-version=2024-11-01" +``` + +References: [Web Apps - List Instance Identifiers](https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/list-instance-identifiers?view=rest-appservice-2024-11-01), [Web Apps - Get Instance Info](https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/get-instance-info?view=rest-appservice-2024-11-01). + +**Interpretation signals and evidence fields:** + +- **Quota signal (`Microsoft.Web`):** Track current usage versus limit for App Service quota entries returned by `az quota usage list`; flag an escalation candidate when projected demand exceeds available headroom in the forecast window. +- **Plan zonal readiness signal:** Use `zoneRedundant=true` as the configuration signal that the plan is set for zone balancing; treat `zoneRedundant=false` as non-zonal configuration for that plan. Validate worker headroom with `numberOfWorkers` versus `maximumNumberOfWorkers` from the same plan output. +- **Maximum zones evidence field:** Capture `maximumNumberOfZones` from plan output when present, and record `null` or missing explicitly when the provider response doesn't expose it for the selected SKU, region, or API shape. +- **Runtime placement evidence (optional):** Capture per-instance `properties.physicalZone` from the instance APIs as supporting evidence for where active workers are running. +- **Minimum evidence record:** Subscription ID, resource group, app name, plan name, region, timestamp, command used, raw JSON output link, `zoneRedundant`, `maximumNumberOfZones`, `numberOfWorkers`, `maximumNumberOfWorkers`, and any returned `physicalZone` values. + +**Azure SQL Managed Instance placeholder:** + +API details for a reproducible regional readiness check are pending validation in this lab revision. Don't add speculative commands. Use documented APIs only once validated and cited. + +--- + +## Exercise 2: Analyze compute utilization with Azure Monitor + +**Objective:** Measure actual CPU and memory consumption to forecast peak demand and right-size commitments. + +Quota and usage tell you how many VMs you can and are running. Utilization metrics tell you how hard those VMs are working—critical for forecasting when you'll hit scaling limits. + +### Step 2.1: Query CPU metrics across VMs + +Query aggregate CPU utilization across all VMs using [VM insights](https://learn.microsoft.com/en-us/azure/azure-monitor/vm/vminsights-overview) data in Log Analytics: + +```kusto +InsightsMetrics +| where Origin == "vm.azm.ms" +| where Namespace == "Processor" +| where Name == "UtilizationPercentage" +| where TimeGenerated > ago(30d) +| summarize AvgCPU = avg(Val), MaxCPU = max(Val), P95CPU = percentile(Val, 95) by Computer, bin(TimeGenerated, 1h) +| render timechart +``` + +Run this in the [Log Analytics workspace](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/log-analytics-overview) connected to your VMs, or via CLI: + +```bash +az monitor log-analytics query \ + --workspace YOUR_WORKSPACE_ID \ + --analytics-query "InsightsMetrics | where Origin == 'vm.azm.ms' | where Namespace == 'Processor' | where Name == 'UtilizationPercentage' | where TimeGenerated > ago(30d) | summarize AvgCPU = avg(Val), MaxCPU = max(Val), P95CPU = percentile(Val, 95) by Computer, bin(TimeGenerated, 1h)" \ + --output table +``` + +For a single VM's platform metrics (no Log Analytics required): + +```bash +az monitor metrics list \ + --resource "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RG/providers/Microsoft.Compute/virtualMachines/YOUR_VM_NAME" \ + --metrics "Percentage CPU" \ + --interval PT1H \ + --aggregation Average \ + --output table +``` + +See the [InsightsMetrics table reference](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/insightsmetrics) for the full list of VM insights namespaces and metric names. + +Reference the [capacity planning section of the Well-Architected Framework](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) for guidance on which metrics to track. + +### Step 2.2: Identify utilization patterns + +Look for: +- **Peak hours:** When does CPU spike? This shows your scaling trigger points. +- **Baseline:** What's the minimum CPU during off-peak? This tells you static vs. variable cost. +- **Trend:** Is utilization growing week-over-week? This informs forecast slope. +- **P95:** 95th percentile tells you the threshold for "normal" workload bursts. Budget capacity for this, not average. + +References: [InsightsMetrics table reference](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/insightsmetrics), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning). + +### Step 2.3: Establish growth trends + +Track week-over-week utilization changes from your monitoring data. The growth trend feeds directly into your quota increase cadence—if utilization is climbing, schedule quota requests before you hit your operator-defined 80% triage threshold from Exercise 1 ([How to monitor quotas and generate alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)). + +--- + +## Exercise 3: Pull savings plan recommendations + +**Objective:** Use Azure Cost Management's Benefit Recommendations API to forecast commitment levels that match your utilization forecast. + +Set commitment targets from your own historical usage and from recommendation surfaces, including [Azure Reservations guidance](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations), [savings plan guidance](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/savings-plan-compute-overview), and [FinOps rate optimization guidance](https://www.finops.org/framework/capabilities/rate-optimization/). This exercise focuses on the savings plan recommendation layer in that decision. + +### Step 3.1: Query savings plan recommendations + +```powershell +.\scripts/rate/Get-BenefitRecommendations.ps1 ` + -BillingScope "/subscriptions/YOUR_SUBSCRIPTION_ID" ` + -LookBackPeriod "Last30Days" ` + -Term "P3Y" +``` + +Parameters: +- **BillingScope:** billing account (for EA), subscription, or resource group. Narrower scopes give more targeted recommendations ([scripts/rate/README.md](../../scripts/rate/README.md), [Get-BenefitRecommendations script](../../scripts/rate/Get-BenefitRecommendations.ps1)). +- **LookBackPeriod:** Last7Days / Last30Days / Last60Days. Use 30+ days for reliable trending ([scripts/rate/README.md](../../scripts/rate/README.md), [Get-BenefitRecommendations script](../../scripts/rate/Get-BenefitRecommendations.ps1)). +- **Term:** P1Y (1-year) or P3Y (3-year). 3-year has higher discount but less flexibility ([scripts/rate/README.md](../../scripts/rate/README.md), [Get-BenefitRecommendations script](../../scripts/rate/Get-BenefitRecommendations.ps1), [Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations)). + +**Output fields:** +- `commitmentAmount`: Recommended commitment amount returned by the API. +- `commitmentGranularity`: Time granularity used for the commitment amount. +- `savingsPercentage`: Estimated savings percentage for the look-back period. +- `coveragePercentage`: Estimated coverage percentage for the look-back period. +- `averageUtilizationPercentage`: Estimated average utilization percentage for the look-back period. +- `overageCost`: Estimated overage cost for usage beyond the commitment. +- `wastageCost`: Estimated unused portion of the benefit cost. + +Field names and descriptions above are based on the Cost Management Benefit Recommendations API schema and the script reference used in this repo ([Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations), [scripts/rate/README.md](../../scripts/rate/README.md)). + +### Step 3.2: Interpret the recommendation + +Example output (illustrative scenario, not a platform default target): +- Hourly commitment: $500 +- Coverage: 85% +- Savings: 40% +- Wastage: $12/day + +This means: +- Buy $500/hour of compute commitment (1-year or 3-year term) +- This covers 85% of your typical hourly usage +- The remaining 15% runs at pay-as-you-go rates unless covered by another pricing benefit +- You're leaving ~$12/day on the table to underutilized reserved capacity + +**Decision point (illustrative):** Do you accept 85% coverage to save 40%, or do you need tighter alignment? If your forecast shows 10% growth over the next quarter, and coverage is already 85%, you might increase commitment targets to limit expected overage risk as utilization climbs. + +### Step 3.3: Validate against your forecast + +Cross-check the API's recommendation against your capacity forecast from Exercise 2: +- Example: if your forecast growth rate suggests 12% month-over-month increase, and the API recommendation maps to 85% coverage, plan a commitment refresh window before projected overage risk crosses your internal threshold. +- Schedule your next forecast refresh accordingly. + +Reference the [FinOps Framework planning and estimating guidance](https://www.finops.org/framework/capabilities/planning-estimating/) and [Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations) for structuring this decision. + +--- + +## Exercise 4: Assess storage and PaaS costs and forecast + +**Objective:** Analyze storage, disk, and PaaS service costs across your estate, then forecast growth based on recent trends. + +Storage and PaaS services scale differently from compute. Understanding which resources drive cost—and their growth rate—prevents surprise bill spikes and ensures you allocate capacity correctly across regions. Use [Cost Management cost analysis](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/quick-acm-cost-analysis) to query cost data across service categories. + +### Step 4.1: Query storage costs with Cost Management + +Use the Azure CLI to pull storage costs grouped by subscription and resource for the last billing period: + +```bash +az rest --method POST \ + --url "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/YOUR_BILLING_ACCOUNT_ID/providers/Microsoft.CostManagement/query?api-version=2023-11-01" \ + --body '{ + "type": "ActualCost", + "timeframe": "TheLastBillingMonth", + "dataset": { + "granularity": "None", + "filter": { + "dimensions": { "name": "ServiceName", "operator": "In", "values": ["Storage"] } + }, + "grouping": [ + { "type": "Dimension", "name": "SubscriptionName" }, + { "type": "Dimension", "name": "ResourceId" } + ], + "aggregation": { "totalCost": { "name": "Cost", "function": "Sum" } } + } + }' +``` + +Reference the [Cost Management Query API](https://learn.microsoft.com/en-us/rest/api/cost-management/query/usage) for request body schema and supported dimensions. + +Alternatively, in the Azure portal: +1. Go to **Cost Management** > **Cost analysis** +2. Select **Group by** > **Service name**, then filter to **Storage** +3. Select the **DailyCosts** view to see the trend over the billing period + +For recurring analysis, [create a Cost Management export](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/tutorial-export-acm-data) to automatically deliver cost data to a storage account on a schedule. This gives you a historical dataset for trend analysis without manual queries. + +### Step 4.2: Identify growth drivers + +For each high-cost storage resource: +- Compare this month's cost to the previous month's cost +- Calculate growth rate: (Current - Previous) / Previous * 100 +- If growth > 10% per month, flag for capacity planning + +Example: An analytics storage account grew from 500 GB to 600 GB in 30 days = 20% growth. At that rate, it reaches 1 TB in ~4 months. Plan ingestion limits, archival policies, or regional replica targets now. + +Storage cost varies by tier (hot, cool, archive), replication (LRS, GRS, RA-GRS), and region. Drill down into high-growth accounts and determine if cost is driven by increasing volume, access pattern shifts, or replication overhead. + +### Step 4.3: Forecast Premium SSD v2 disk costs + +[Premium SSD v2](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-types#premium-ssd-v2) disks bill separately for capacity, throughput, and IOPS—each dimension scales independently. This makes forecasting more granular than standard managed disks. + +Query disk costs with: + +```bash +az rest --method POST \ + --url "https://management.azure.com/subscriptions/YOUR_SUBSCRIPTION_ID/providers/Microsoft.CostManagement/query?api-version=2023-11-01" \ + --body '{ + "type": "ActualCost", + "timeframe": "TheLastBillingMonth", + "dataset": { + "granularity": "None", + "filter": { + "dimensions": { "name": "MeterSubCategory", "operator": "In", "values": ["Premium SSD v2"] } + }, + "grouping": [{ "type": "Dimension", "name": "ResourceId" }], + "aggregation": { "totalCost": { "name": "Cost", "function": "Sum" } } + } + }' +``` + +When forecasting Premium SSD v2 growth, track three dimensions separately: +- **Capacity (GiB):** Grows with data volume—forecast from ingestion rate +- **Provisioned throughput (MBps):** Grows with workload IO demands—forecast from performance baselines +- **Provisioned IOPS:** Grows with transaction density—forecast from application telemetry + +Each dimension has its own per-unit price, so a workload that's IOPS-heavy but storage-light has a different cost profile than one that's capacity-heavy. Model each dimension independently for accurate projections. + +### Step 4.4: Forecast Azure Cosmos DB costs + +[Azure Cosmos DB](https://learn.microsoft.com/en-us/azure/cosmos-db/cost-management) uses request units (RUs) as its primary capacity metric. Forecasting Cosmos DB costs requires tracking RU consumption patterns alongside storage growth. + +Query Cosmos DB costs with: + +```bash +az rest --method POST \ + --url "https://management.azure.com/subscriptions/YOUR_SUBSCRIPTION_ID/providers/Microsoft.CostManagement/query?api-version=2023-11-01" \ + --body '{ + "type": "ActualCost", + "timeframe": "TheLastBillingMonth", + "dataset": { + "granularity": "None", + "filter": { + "dimensions": { "name": "ServiceName", "operator": "In", "values": ["Azure Cosmos DB"] } + }, + "grouping": [{ "type": "Dimension", "name": "ResourceId" }], + "aggregation": { "totalCost": { "name": "Cost", "function": "Sum" } } + } + }' +``` + +Key forecasting dimensions for Cosmos DB: +- **Provisioned throughput (RU/s):** If you use [provisioned throughput](https://learn.microsoft.com/en-us/azure/cosmos-db/set-throughput), forecast from peak RU consumption trends in Azure Monitor. Autoscale accounts bill for the max RU/s reached per hour. +- **Serverless consumption:** If you use [serverless](https://learn.microsoft.com/en-us/azure/cosmos-db/serverless), forecast from total RU consumption per billing period. Costs scale linearly with request volume. +- **Storage:** Cosmos DB bills per GB stored. Forecast from data growth rate—partition splits don't change cost, but multi-region writes multiply storage charges per replica. + +For stamp-based deployments, treat this as a workload-specific operator assumption: if your data model assigns throughput and storage boundaries per tenant, Cosmos DB cost can track tenant count more closely than user count. Validate that assumption with your own per-tenant RU telemetry before using it in forecasts ([Set throughput on Azure Cosmos DB containers and databases](https://learn.microsoft.com/en-us/azure/cosmos-db/set-throughput), [Azure Cosmos DB serverless](https://learn.microsoft.com/en-us/azure/cosmos-db/serverless), [Azure Cosmos DB cost management](https://learn.microsoft.com/en-us/azure/cosmos-db/cost-management)). + +### Step 4.5: Map forecasts to workload types + +Combine your storage, disk, and PaaS cost data into a unified forecast: +- **Azure Storage:** Forecast by tier, replication, and transaction volume +- **Premium SSD v2:** Forecast by capacity, throughput, and IOPS independently +- **Azure Cosmos DB:** Forecast by RU consumption pattern and storage growth + +Cross-reference these forecasts with your compute stamp projections from Exercise 5—PaaS costs often scale proportionally with stamp count, but the relationship isn't always linear. A new stamp may need pre-provisioned Cosmos DB throughput before tenants migrate to it. + +### Step 4.6: Add storage scaling and partitioning architecture guidance + +Document the storage scaling and partitioning design that matches each high-growth workload: + +- Storage account sharding or split strategy by workload boundary and region +- Partition-key strategy for high-volume PaaS data paths, including expected hot-partition risk +- Replication pattern (for example, LRS, GRS, or RA-GRS) and the cost-to-recovery tradeoff + +Use service documentation to justify the design choices and scaling constraints ([Storage scalability targets](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview#scalability-targets-for-standard-storage-accounts), [Azure Cosmos DB partitioning overview](https://learn.microsoft.com/en-us/azure/cosmos-db/partitioning-overview)). + +### Step 4.7: Define storage escalation triggers and evidence requirements + +Create explicit escalation triggers for storage and PaaS growth: + +- Trigger when forecasted growth crosses a documented service limit or support-reviewed operational threshold. +- Trigger when projected cost variance crosses your FinOps guardrail for the planning window. +- Trigger when regional readiness checks show a required service isn't ready in a target region. + +For each trigger, capture required evidence: 30-day trend, current usage, forecast method, target region, and requested change ([Create an Azure support request](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request), [FinOps planning and estimating](https://www.finops.org/framework/capabilities/planning-estimating/)). + +> **Implementation note:** Don't hardcode unverified numeric limits in lab assets. Pull limits from current Microsoft Learn documentation or live API output each run, then cite the source used ([Azure REST API reference](https://learn.microsoft.com/en-us/rest/api/azure/), [Azure limits and quotas](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits)). + +--- + +## Exercise 5: Map forecasts to scale units + +**Objective:** Translate compute and storage forecasts into capacity per deployment stamp or region, identifying when you'll exceed current allocation. + +ISVs often deploy multiple independent instances of their platform across regions (the [Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern)). Forecasting capacity per stamp—not only the aggregate—ensures you don't overload one region. + +### Step 5.1: Define your stamp architecture + +Document your deployment unit. Example: +- **Stamp composition:** + - 3 API frontend VMs (Standard_D2s_v3, autoscale 3–10) + - 1 data platform VM (Standard_D8s_v3, fixed) + - 1 cache VM (Standard_E4s_v3, fixed) + - 1 storage account (500 GB hot, 2 TB cool for backups) +- **Stamp capacity limit:** 10,000 concurrent users +- **Deployment regions:** eastus, westus2, and northeurope + +### Step 5.2: Forecast per-stamp demand + +Use utilization data from Exercise 2 to estimate: +- Concurrent users / peak demand per week +- Storage growth per region + +Example forecast: +- **Week 1:** 15,000 users across 2 stamps deployed (1 eastus, 1 westus2)—each stamp handles up to 10,000 users, so you're at 75% capacity +- **Week 12 (end of quarter):** 22,000 users—2 stamps can't cover the load, so deploy a 3rd stamp in northeurope + +### Step 5.3: Calculate quota and commitment needs + +From Exercise 1, your quota per region: 50 Standard_D2s_v3, 10 Standard_D8s_v3, 10 Standard_E4s_v3. + +With 2 stamps fully deployed: +- In-use: 6 D2s, 2 D8s, 2 E4s +- Headroom: 44 D2s, 8 D8s, 8 E4s + +Forecast shows you need 3 stamps by week 12 (9 D2s, 3 D8s, 3 E4s in-use). You're safe. But if westus2 is your high-demand region, you may hit quota limits in that region before others—request regional quota increase now. + +From Exercise 3, your savings plan commitment is $500/hour. With 2 stamps: +- Compute cost: ~$300/hour at on-demand +- Your commitment covers: $300 / $500 = 60% (acceptable) + +At 3 stamps (week 12): +- Compute cost climbs to ~$450/hour +- Commitment covers: $450 / $500 = 90% (tight but viable) + +Decision: Buy additional commitment buffer now for the 3rd stamp, or risk overages in week 12. + +### Step 5.4: Schedule capacity milestones + +Create a table: + +| Milestone | Timestamp | Stamps Deployed | Quota Headroom (D2s) | Commitment Buffer | Action | +|-----------|-----------|-----------------|----------------------|-------------------|--------| +| Current | Week 1 | 2 | 44 | $200/hr | Baseline | +| Q1 End | Week 12 | 3 | 41 | $50/hr | Request +10 D2s quota; buy +$200/hr commitment | +| Q2 End | Week 26 | 4 | 38 | Risk | Plan regional expansion | + +Reference the [Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) and [Well-Architected scaling guidance](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling) for stamp-based capacity planning. + +### Step 5.5: Branch for target-region-unavailable scenarios + +If the target region is unavailable, run this branch before finalizing milestone dates: + +1. **Select escape region options** and map each option to required quota, service readiness, and expected latency impact ([Region access request process](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process), [Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern)). +2. **Assess surge handling implications** for failover or temporary concentration in remaining regions, including autoscale and quota pressure in those regions ([Well-Architected scaling guidance](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling), [Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests)). +3. **Recalculate timeline impact** from supply constraints, including region access approval lead time and datacenter capacity constraints such as power and infrastructure pressure in the target geography ([Region access request process](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process)). + +Update your milestone table with a primary plan and an escape-region plan so procurement and allocation can proceed without reopening forecast assumptions. + +--- + +## Exercise 6: Review the Cost Optimization workbook + +**Objective:** Use Azure Advisor's Cost Optimization workbook to surface right-sizing and underutilization recommendations. + +Azure Advisor and the Cost Optimization workbook provide cost recommendation signals you can review alongside your own telemetry and forecast model ([Cost Optimization workbook](https://learn.microsoft.com/en-us/azure/advisor/advisor-workbook-cost-optimization), [Advisor VM and VMSS cost recommendations](https://learn.microsoft.com/en-us/azure/advisor/advisor-cost-recommendations)). + +### Step 6.1: Open the workbook + +1. In the Azure portal, go to **Azure Advisor** +2. Select **Cost Optimization** tab +3. Open **Cost Optimization workbook** (link in the top toolbar) + +Reference the [Cost Optimization workbook documentation](https://learn.microsoft.com/en-us/azure/advisor/advisor-workbook-cost-optimization) for setup details. + +### Step 6.2: Review recommendation categories + +The workbook typically surfaces recommendation categories across compute, storage, and commitment optimization, including Advisor recommendation tiles and usage optimization views ([Cost Optimization workbook](https://learn.microsoft.com/en-us/azure/advisor/advisor-workbook-cost-optimization)). + +Examples you should evaluate: + +**Underutilized VMs:** +- Advisor can recommend VM and VMSS resize or shutdown actions for low-utilization resources based on its documented utilization criteria and lookback configuration ([Advisor VM and VMSS cost recommendations](https://learn.microsoft.com/en-us/azure/advisor/advisor-cost-recommendations)). +- Decision: Right-size (move to smaller SKU), turn off during off-hours, or delete +- Impact on forecast: Treat underutilized recommendations as an efficiency signal, then validate with your own CPU, memory, and network telemetry before updating per-stamp efficiency assumptions ([Advisor VM and VMSS cost recommendations](https://learn.microsoft.com/en-us/azure/advisor/advisor-cost-recommendations)). + +**Unattached disks:** +- Disks not connected to any VM, still accruing cost +- Decision: Delete if no snapshot backups rely on them +- Impact: Cost reduction without compute capacity impact ([Cost Optimization workbook](https://learn.microsoft.com/en-us/azure/advisor/advisor-workbook-cost-optimization)). + +**Oversized database and storage:** +- Databases and storage accounts with excess reserved capacity +- Decision: Right-size tier or replication settings +- Impact: Reduces storage forecasting headroom; ensure measured growth justifies existing allocation ([Cost Optimization workbook](https://learn.microsoft.com/en-us/azure/advisor/advisor-workbook-cost-optimization)). + +**Unused reservations:** +- Commitments (RI / Savings Plans) with low utilization +- Decision: Evaluate if workload pattern changed; may need to trim commitment or accelerate utilization +- Impact: Informs the next commitment purchase decision (Exercise 3) ([Cost Optimization workbook](https://learn.microsoft.com/en-us/azure/advisor/advisor-workbook-cost-optimization), [Azure Reservations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations), [Azure savings plan for compute](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/savings-plan-compute-overview)). + +### Step 6.3: Cross-check against your forecast + +For each recommendation: +1. Does it contradict your utilization forecast from Exercise 2? + - If Advisor flags underutilization but your metrics show growth, treat that as a validation task before making SKU changes ([Advisor VM and VMSS cost recommendations](https://learn.microsoft.com/en-us/azure/advisor/advisor-cost-recommendations), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)). +2. Does it reveal an allocation misalignment? + - If one region shows persistent underutilization while demand grows elsewhere, validate stamp placement and regional distribution assumptions before you rebalance ([Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)). +3. Does it confirm your savings plan coverage? + - If recommendation signals show persistent underutilization of commitments, re-check renewal targets against measured coverage and wastage trends ([Azure Reservations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations), [Azure savings plan for compute](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/savings-plan-compute-overview), [FinOps planning and estimating](https://www.finops.org/framework/capabilities/planning-estimating/)). + +### Step 6.4: Feed findings into procurement + +Document findings in your capacity planning tracker: +- Right-sizing actions: Record the recommendation, expected savings estimate, and target SKU change, then validate against your effective rates before actioning because Advisor savings are based on retail rates ([Advisor VM and VMSS cost recommendations](https://learn.microsoft.com/en-us/azure/advisor/advisor-cost-recommendations)). +- Headroom recovery: Consolidation frees X quota units per region and can delay the next quota increase window ([Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests), [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)). +- Commitment efficiency: Compare current commitment coverage against measured utilization, then adjust the next purchase target to reduce overage and wastage risk ([Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations), [Azure savings plan for compute](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/savings-plan-compute-overview), [Azure Reservations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations)). + +### Step 6.5: Add dev and test technical validation checkpoint + +Before closing the lab, add one validation row for each forecast action that changes dev or test capacity settings: + +- Environment and scope (subscription, region, and service) +- Planned change (quota, SKU, throughput, storage tier, or reservation target) +- Baseline measurement (query output timestamp and value) +- Post-change validation query and expected threshold +- Rollback trigger and evidence link + +Use the same evidence depth you apply to production checks so forecast assumptions stay testable across environments ([Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain)). + +--- + +## Wrap-up: From forecast to procurement + +You've now gathered all the signals needed to make infrastructure commitments with confidence: + +1. **Quota and usage (Exercise 1):** Know what you're allowed to run and what you're running +2. **Utilization patterns (Exercise 2):** Know the growth rate and peak load patterns +3. **Savings plan recommendations (Exercise 3):** Know the optimal commitment level and discount +4. **Storage and PaaS trends (Exercise 4):** Know which storage, disk, and PaaS resources drive cost and when they'll require scale action +5. **Stamp-level forecasts (Exercise 5):** Know when to deploy new stamps or request regional quota +6. **Advisor recommendations (Exercise 6):** Know where to recover efficiency and trim waste + +**Escalation evidence path:** + +When forecast outputs identify blockers, package technical evidence first, then open the correct Azure support path: + +- Classify blocker type: quota limit, region access restriction, zonal enablement restriction, or reservation mismatch ([Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests), [Region access request process](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process), [Zonal enablement request process](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series), [Capacity reservation overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview)). +- Attach reproducible evidence: failed deployment timestamp, operation ID, requested versus current limits, region and zone target, and forecasted shortfall window ([Create an Azure support request](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request)). +- Map blocker-to-request type so each item routes to the matching support request category without rework ([Create an Azure support request](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request)). + +Reference: [Support escalation guide](../operations/escalation/README.md). + +**Next steps:** +- Refresh these analyses monthly. Create a recurring task to run Exercises 1, 2, and 6 each month. +- Use 3-month utilization trends to refresh reservation and savings-plan targets, and update commitment levels when measured coverage and wastage drift from your forecast bounds. +- Align stamps with regions: review Exercise 5 data in your billing API to confirm actual per-region deployment matches your forecast assumptions. +- Archive historical CSVs (quota, utilization, storage) to track forecast accuracy and refine your projections for next quarter. + +References: [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain), [Azure Reservations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations), [Azure savings plan for compute](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/savings-plan-compute-overview). + +**FOCUS exports and reservation sizing:** +If you use FOCUS (FinOps Open Cost and Usage Specification) exports from Cost Management, map commitment discount utilization to your reservation sizing model. See the [FOCUS exports overview](https://learn.microsoft.com/en-us/cloud-computing/finops/focus/overview) for guidance on structuring cost data for forecasting and commitment planning. + +**Operationalization cadence:** +Define and run a recurring review cadence for utilization analysis, projection updates, and forecast validation so quota and commitment decisions stay aligned with measured demand and delivery timelines ([Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain)). + +**Release gates:** +Before each stamp deployment, validate three gates: +1. Quota headroom ≥ scale unit requirement (from Exercise 5) +2. CRG reserved quantity ≥ deployment target (if applicable) +3. Budget posture allows the spend increase + +These gates prevent quota exhaustion, commitment overages, and budget surprises when you enforce them before each release ([Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests), [Capacity reservation overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview), [Use cost alerts to monitor usage and spending](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending), [Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain)). + +References: [Per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests), [Capacity reservation overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview), [Use cost alerts to monitor usage and spending](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending). + +The output of forecasting feeds directly into: +- **Allocation decisions:** How much quota and commitment per region? +- **Procurement timing:** When to renew savings plans or request capacity increases? +- **Architecture reviews:** Are stamp capacities sized correctly, or is one region a bottleneck? + +For deeper guidance on the FinOps discipline around forecasting, refer to the [FinOps Framework planning and estimating section](https://www.finops.org/framework/capabilities/planning-estimating/). diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-04-procurement.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-04-procurement.md new file mode 100644 index 000000000..0c5a4470c --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-04-procurement.md @@ -0,0 +1,731 @@ +# Lab 4: Procurement + +## Overview + +This lab covers how to procure compute capacity on Azure for production workloads. You'll work with [capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) to guarantee supply, assess zone alignment across subscriptions, configure sharing for multi-subscription architectures, and layer pricing commitments (Azure Reservations and savings plans) on top of supply guarantees. + +The core concept: capacity reservations are supply instruments, not pricing instruments. They guarantee compute availability at pay-as-you-go rates. Pricing commitments (reservations and savings plans) are separate knobs that stack on top. + +By the end of this lab, you'll understand: + +- How to validate SKU availability before committing to capacity +- How to create and manage capacity reservation groups (CRGs) +- How to associate workloads with reserved capacity +- How to share reservations across subscriptions and handle zone alignment +- How to monitor utilization and overallocation +- How to evaluate savings plans and spot VMs as complementary procurement levers + +**Prerequisites:** Access to an Azure subscription with contributor permissions, Azure CLI or PowerShell Az module installed, and familiarity with resource groups and virtual machines. + +--- + +## Exercise 1: Validate SKU availability and zone alignment + +Before creating capacity reservations, confirm that the VM SKUs you need are available in your target regions and zones. Zone alignment matters when sharing CRGs across subscriptions—logical zone 1 in subscription A may map to a different physical zone than zone 1 in subscription B. + +### Step 1: Check SKU availability in a region + +Use `Get-AzComputeResourceSku` to list available VM SKUs: + +```powershell +Get-AzComputeResourceSku ` + -Location "eastus" | + Where-Object { + $_.ResourceType -eq "virtualMachines" -and + $_.Name -eq "Standard_D4s_v5" + } | + Select-Object Name, Locations, Restrictions +``` + +This returns the SKU name, regions where it's available, and any restrictions (regional, zonal, or license-related). + +### Step 2: Map logical zones to physical zones + +Capacity reservations are created in specific logical zones (1, 2, 3). When you share a CRG across subscriptions, you need to confirm that logical zone 1 in the producer subscription aligns with the same physical infrastructure in the consumer subscription. + +Run the provided script to fetch zone mappings: + +```powershell +.\scripts/quota/Get-AzAvailabilityZoneMapping.ps1 ` + -SubscriptionId "your-subscription-id" ` + -Location "eastus" +``` + +Output shows: + +``` +TenantId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +SubscriptionId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +Location : eastus +LogicalZone : 1 +PhysicalZone : 3 +PhysicalZoneName : US-VA-AZ-3 +``` + +Run this for both the producer (CRG owner) and consumer subscriptions. If physical zones don't align, shared workloads may see latency or cross-zone traffic charges. + +### Step 3: Check zone restrictions + +Some SKUs are restricted to specific zones. Query the Compute Resource SKU API: + +```powershell +Get-AzComputeResourceSku ` + -Location "eastus" | + Where-Object { $_.Restrictions -ne $null } | + Select-Object Name, @{ Label="RestrictionType"; Expression={$_.Restrictions.Type} } +``` + +If a SKU shows `ZonesRestricted`, it's available only in certain zones. If `RegionRestricted`, file a [region access request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process). + +--- + +## Exercise 2: Create a capacity reservation group + +A [capacity reservation group (CRG)](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) is a container for one or more capacity reservations in a specific region and logical zone. All VMs associated with a CRG must use the same zone. + +### Step 1: Create a CRG via Azure portal + +1. Go to **Home** > **Create a resource** > search for "capacity reservation group" +2. Select **Capacity Reservation Group** and choose **Create** +3. Fill in: + - **Subscription:** Your target subscription + - **Resource group:** Create or select one + - **Name:** e.g., `crg-eastus-z1-prod` + - **Region:** e.g., East US + - **Availability zone:** e.g., 1 +4. Select **Review + create**, then **Create** + +### Step 2: Create a CRG via Azure CLI + +```bash +az capacity reservation group create \ + --resource-group "rg-prod" \ + --name "crg-eastus-z1-prod" \ + --location "eastus" \ + --zones 1 +``` + +### Step 3: Create a CRG via ARM template + +```json +{ + "type": "Microsoft.Compute/capacityReservationGroups", + "apiVersion": "2023-09-01", + "name": "crg-eastus-z1-prod", + "location": "eastus", + "zones": ["1"], + "properties": {} +} +``` + +Deploy with: + +```bash +az deployment group create \ + --resource-group "rg-prod" \ + --template-file "crg-template.json" +``` + +### Step 4: Verify creation + +```bash +az capacity reservation group show \ + --resource-group "rg-prod" \ + --name "crg-eastus-z1-prod" +``` + +You now have an empty CRG. Next, you'll add capacity reservations to it. + +--- + +## Exercise 2b: Verify two-sided quota constraints + +Before creating a capacity reservation group, confirm you have sufficient quota headroom. Quota works in two dimensions: total regional vCPU and per-family vCPU. Deployments must satisfy both constraints simultaneously, and CRG creation itself consumes quota. + +### Step 1: Understand the quota dimensions + +- **Regional vCPU limit:** Total vCores allocated to a single family (e.g., Standard D family) in a region, regardless of zone +- **Per-VM-family vCPU limit:** Individual per-family caps on regional allocation + +When you create a capacity reservation for 10 Standard_D4s_v5 instances (40 vCores), those vCores are reserved immediately and count against your regional quota. If you have only 35 vCores available in the Standard D quota, the CRG creation will fail. + +### Step 2: Check quota headroom + +Use the quota script to confirm you have room: + +```powershell +.\scripts/quota/Get-AzVMQuotaUsage.ps1 ` + -SubscriptionId "" ` + -Location "eastus" | + Where-Object { $_.SKU -match "Standard_D" } +``` + +For each family, calculate available headroom: + +``` +AvailableQuota = QuotaLimit - UsedQuota +``` + +If you plan to create a CRG for 10 D4s_v5 instances (40 vCores), ensure `AvailableQuota >= 40` in the Standard D family quota. + +### Step 3: Common mistake—forgetting the headroom check + +A common error: teams request a CRG without checking available quota first. The request fails at creation time, delaying workload deployments and forcing emergency quota increases. Always verify both dimensions before submitting the CRG creation request. + +### Step 4: Plan quota growth + +If your procurement roadmap spans multiple quarters, request quota increases early. Azure quota requests typically complete within 1–2 business days, so build review time into your release schedule. See the [VM quotas](https://learn.microsoft.com/en-us/azure/virtual-machines/quotas) reference for details on requesting increases. + +--- + +## Exercise 3: Add member reservations and associate workloads + +A capacity reservation is a reservation for a specific VM SKU and quantity within a CRG. Once created, you can [deploy VMs and associate them with the reservation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-associate-vm). + +### Step 1: Create a capacity reservation within the CRG + +Via Azure CLI: + +```bash +az capacity reservation create \ + --resource-group "rg-prod" \ + --capacity-reservation-group-name "crg-eastus-z1-prod" \ + --name "capres-standard-d4s-v5" \ + --sku "Standard_D4s_v5" \ + --quantity 10 +``` + +This reserves 10 instances of Standard_D4s_v5 in zone 1 of East US. The reservation runs at pay-as-you-go rates—you're charged for all 10 slots whether or not you deploy VMs into them. + +### Step 2: Deploy a VM and associate it with the reservation + +Via Azure CLI: + +```bash +az vm create \ + --resource-group "rg-prod" \ + --name "vm-prod-01" \ + --image "UbuntuLTS" \ + --size "Standard_D4s_v5" \ + --zone 1 \ + --capacity-reservation-group "/subscriptions//resourceGroups/rg-prod/providers/Microsoft.Compute/capacityReservationGroups/crg-eastus-z1-prod" +``` + +Replace `` with your subscription ID. The `--zone` must match the CRG's zone. + +### Step 3: Deploy via ARM template + +```json +{ + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2023-09-01", + "name": "vm-prod-01", + "location": "eastus", + "zones": ["1"], + "properties": { + "capacityReservationGroup": { + "id": "/subscriptions//resourceGroups/rg-prod/providers/Microsoft.Compute/capacityReservationGroups/crg-eastus-z1-prod" + }, + "hardwareProfile": { + "vmSize": "Standard_D4s_v5" + }, + "osProfile": { + "computerName": "vm-prod-01", + "adminUsername": "azureuser" + }, + "storageProfile": { + "imageReference": { + "publisher": "Canonical", + "offer": "0001-com-ubuntu-server-focal", + "sku": "20_04-lts-gen2", + "version": "latest" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "/subscriptions//resourceGroups/rg-prod/providers/Microsoft.Network/networkInterfaces/nic-prod-01" + } + ] + } + } +} +``` + +### Step 4: Check utilization + +Query the reservation's instanceView to see allocated vs. reserved capacity: + +```bash +az capacity reservation show \ + --resource-group "rg-prod" \ + --capacity-reservation-group-name "crg-eastus-z1-prod" \ + --name "capres-standard-d4s-v5" \ + --expand "instanceview" +``` + +Look for: +- `availableCapacity`: slots not yet allocated to VMs +- `virtualMachinesAllocated`: count of running VMs using this reservation +- `remainingCapacity`: available slots + +If `virtualMachinesAllocated` exceeds the reservation quantity, those excess VMs are in overallocation mode—they run without the supply SLA. + +--- + +## Exercise 4: Share a CRG across subscriptions + +Capacity reservations are created in a producer subscription and can be [shared with up to 100 consumer subscriptions](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share). This pattern is common in multi-tenant ISV platforms where a central team manages procurement and consumer teams deploy workloads. + +### Step 1: Configure sharing on the CRG + +Before enabling sharing, use this pre-share checklist to ensure readiness: + +**Pre-share checklist:** + +- **Zone mapping validated:** Run the zone mapping script in both producer and consumer subscriptions (from Exercise 1). Confirm that logical zones align (e.g., logical zone 1 maps to the same physical zone in both subscriptions) +- **Consumer subscriptions identified:** List all subscriptions that will use the shared CRG and confirm access permissions +- **RBAC roles assigned:** The consumer subscription (or specific service principals) must have Reader access at minimum. Confirm the identities that will associate VMs with the CRG +- **Billing scope aligned:** Decide whether the CRG's cost should roll up to the producer subscription's cost center or be shared. Align CRG ownership to cost boundaries so the team that owns the capacity also sees the cost in their billing scope + +In the producer subscription, grant the consumer subscription access to the CRG: + +```bash +az role assignment create \ + --role "Reader" \ + --assignee-object-id "" \ + --scope "/subscriptions//resourceGroups/rg-prod/providers/Microsoft.Compute/capacityReservationGroups/crg-eastus-z1-prod" +``` + +For UI-based assignment, go to the CRG in the producer subscription: +1. Select **Access control (IAM)** +2. Select **Add** > **Add role assignment** +3. Role: **Reader** +4. Assign to: Service principal or user from the consumer subscription +5. Select **Save** + +See [capacity reservation group sharing](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share) for detailed steps. + +### Step 2: Deploy from a consumer subscription + +In the consumer subscription, create a VM and reference the CRG by its full resource ID: + +```bash +az vm create \ + --resource-group "rg-consumer" \ + --name "vm-consumer-01" \ + --image "UbuntuLTS" \ + --size "Standard_D4s_v5" \ + --zone 1 \ + --capacity-reservation-group "/subscriptions//resourceGroups/rg-prod/providers/Microsoft.Compute/capacityReservationGroups/crg-eastus-z1-prod" +``` + +### Step 3: Verify zone alignment + +Before deploying from the consumer subscription, confirm that logical zone 1 in the producer subscription aligns with logical zone 1 in the consumer subscription. Run the zone mapping script in both subscriptions and compare physical zone names. If they differ, file a [zonal enablement request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) to address the misalignment. + +### Step 4: Monitor shared utilization + +The producer subscription owner can see all allocated VMs across all consumer subscriptions. In the producer subscription: + +```bash +az capacity reservation show \ + --resource-group "rg-prod" \ + --capacity-reservation-group-name "crg-eastus-z1-prod" \ + --name "capres-standard-d4s-v5" \ + --expand "instanceview" +``` + +The `virtualMachinesAllocated` count includes VMs from consumer subscriptions. + +--- + +## Exercise 5: Monitor overallocation and utilization + +[Overallocation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) happens when you deploy more VMs than the reserved quantity. Overallocated VMs run without the supply SLA and can be interrupted if capacity is needed. + +### Step 1: Deploy beyond reserved capacity + +You have a reservation for 10 Standard_D4s_v5 instances. Deploy 12 VMs: + +```bash +for i in {1..12}; do + az vm create \ + --resource-group "rg-prod" \ + --name "vm-prod-$i" \ + --image "UbuntuLTS" \ + --size "Standard_D4s_v5" \ + --zone 1 \ + --capacity-reservation-group "/subscriptions//resourceGroups/rg-prod/providers/Microsoft.Compute/capacityReservationGroups/crg-eastus-z1-prod" \ + --no-wait +done +``` + +### Step 2: Check utilization states + +```bash +az capacity reservation show \ + --resource-group "rg-prod" \ + --capacity-reservation-group-name "crg-eastus-z1-prod" \ + --name "capres-standard-d4s-v5" \ + --expand "instanceview" +``` + +The output shows three capacity states: + +1. **Available**: Reserved slots not yet allocated (reserved - allocated) +2. **Consumed**: VMs running within the reserved quantity +3. **Overallocated**: VMs beyond the reserved quantity (virtualMachinesAllocated - reserved quantity) + +For example, if reserved = 10 and allocated = 12, you have 0 available, 10 consumed, and 2 overallocated. + +### Step 3: Understand overallocation implications + +Overallocated VMs don't have the availability SLA from the capacity reservation. They're useful for non-critical or batch workloads, but shouldn't be used for production services. + +If you want to raise the reservation, run: + +```bash +az capacity reservation update \ + --resource-group "rg-prod" \ + --capacity-reservation-group-name "crg-eastus-z1-prod" \ + --name "capres-standard-d4s-v5" \ + --quantity 15 +``` + +--- + +## Exercise 5b: Apply the create-migrate-delete pattern + +You can't edit a capacity reservation's VM size or location in place. If you need to change a reservation's parameters, you must create a new reservation with the target specs, migrate running workloads, and delete the old reservation. This pattern has a cost implication: you'll pay for both reservations during the migration window. + +### Step 1: Understand the immutability constraint + +Once a capacity reservation is created, you cannot modify: + +- SKU (e.g., changing from Standard_D4s_v5 to Standard_D8s_v5) +- Availability zone (e.g., moving from zone 1 to zone 2) +- Region (e.g., moving from East US to West US) + +If your requirements change, the create-migrate-delete pattern is the only path forward. + +### Step 2: Create a new CRG and capacity reservation + +Create a new capacity reservation group in the target zone (if needed) and a new capacity reservation with the new SKU: + +```bash +az capacity reservation group create \ + --resource-group "rg-prod" \ + --name "crg-eastus-z1-prod-new" \ + --location "eastus" \ + --zones 1 + +az capacity reservation create \ + --resource-group "rg-prod" \ + --capacity-reservation-group-name "crg-eastus-z1-prod-new" \ + --name "capres-standard-d8s-v5" \ + --sku "Standard_D8s_v5" \ + --quantity 10 +``` + +### Step 3: Migrate workloads step by step + +Follow this sequence to minimize downtime: + +1. **Disassociate VMs from the old CRG** (they move to pay-as-you-go mode): + +```bash +az vm update \ + --resource-group "rg-prod" \ + --name "vm-prod-01" \ + --capacity-reservation-group "" +``` + +2. **Associate the VM with the new CRG** (it now uses the new reservation): + +```bash +az vm update \ + --resource-group "rg-prod" \ + --name "vm-prod-01" \ + --capacity-reservation-group "/subscriptions//resourceGroups/rg-prod/providers/Microsoft.Compute/capacityReservationGroups/crg-eastus-z1-prod-new" +``` + +3. **Verify the migration** by checking the instanceView: + +```bash +az vm show \ + --resource-group "rg-prod" \ + --name "vm-prod-01" \ + --expand "instanceview" | + jq '.capacityReservationGroup' +``` + +4. **Repeat for all workloads** until the old CRG is empty. + +### Step 4: Understand the billing impact + +During the migration window, you're paying for both the old and new capacity reservations. For example, if you're migrating 10 instances and each pays 10 vCores, you'll pay for 20 vCores across both reservations during the migration. + +**Minimize double-billing:** + +- Schedule migrations during off-peak hours to reduce the number of simultaneous VMs +- Batch VM migrations to complete within 1–2 hours rather than spreading over days +- Request a cost allocation tag or cost center split to track the migration costs separately + +### Step 5: Delete the old CRG + +Once all workloads have migrated, delete the old capacity reservation and CRG: + +```bash +az capacity reservation delete \ + --resource-group "rg-prod" \ + --capacity-reservation-group-name "crg-eastus-z1-prod" \ + --name "capres-standard-d4s-v5" + +az capacity reservation group delete \ + --resource-group "rg-prod" \ + --name "crg-eastus-z1-prod" +``` + +See [Capacity reservation overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) for more details on managing reservations across their lifecycle. + +--- + +## Exercise 6: Pull savings plan recommendations and compare rate instruments + +Capacity reservations guarantee supply at standard pay-as-you-go rates. To reduce costs further, layer pricing commitments—Azure Reservations (1-year or 3-year) or Savings Plans (1-year or 3-year)—on top of reserved capacity. + +### Step 1: Get savings plan recommendations + +Use the provided script to fetch recommendations from the Cost Management API: + +```powershell +.\scripts/rate/Get-BenefitRecommendations.ps1 ` + -BillingScope "/subscriptions/" ` + -LookBackPeriod 30 ` + -Term "P1Y" +``` + +This queries your actual usage over the past 30 days and recommends purchase quantities for a 1-year savings plan. Output includes: + +``` +SKU : Standard_D4s_v5 +RecommendedQty : 8 +RecommendedSpend : $18,000 +AnnualSavings : $4,500 +``` + +The 80% heuristic: savings plans and reservations should cover ~80% of your expected usage. The remaining 20% runs at pay-as-you-go rates, giving you flexibility without over-committing. + +### Step 2: Create a savings plan in the Azure portal + +1. Go to **Cost Management + Billing** > **Savings plans** +2. Select **Buy savings plan** +3. Choose **Compute** and configure: + - **Term:** 1-year or 3-year + - **Billing frequency:** Monthly or upfront + - **Scope:** Subscription or shared (if multi-subscription) +4. Review the recommendation and confirm purchase + +See [savings plans for compute](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/savings-plan-compute-overview) for full details. + +### Step 3: Compare rate instruments + +You now have three layers: + +1. **Capacity reservation (supply instrument):** Guarantees supply at PAYG rates. Unused slots cost money. +2. **Savings plan (pricing commitment):** Applies a discounted rate across your compute usage. Doesn't guarantee supply. +3. **Azure Reservation (pricing commitment):** Instance-based discount for 1-year or 3-year terms. Doesn't guarantee supply. + +Strategy: Use capacity reservations for SKUs and regions where you need guaranteed supply. Layer savings plans or reservations on top to reduce the effective rate. For example: + +- Reserve 80% of expected D4s_v5 demand in East US Zone 1 via a capacity reservation group +- Purchase a 1-year savings plan for 80% of the same volume to reduce the effective rate to ~25% below PAYG +- Let the remaining 20% run at PAYG rates to absorb spikes without over-committing + +### Step 4: Monitor blended cost + +Query your actual costs with and without commitments: + +```bash +az costmanagement query --type "Usage" \ + --timeframe "MonthToDate" \ + --granularity "Daily" \ + --aggregation '{"totalCost":{"name":"PreTaxCost","function":"Sum"}}' \ + --grouping '[{"type":"Dimension","name":"ChargeType"}]' +``` + +This breaks down costs by charge type, helping you see the impact of capacity reservations and savings plans. See [FinOps rate optimization](https://www.finops.org/framework/capabilities/rate-optimization/) for rate optimization strategy. + +--- + +## Exercise 7: Evaluate Spot VM placement scores + +Spot VMs run on excess Azure capacity at steep discounts (up to 90% off PAYG) but can be evicted with 30 seconds' notice. They're ideal for non-critical workloads (batch jobs, dev/test, fault-tolerant services). + +### Step 1: Check Spot placement scores + +Before deploying Spot VMs, use the Spot Placement Score API to assess deployment success likelihood: + +Via Azure CLI: + +```bash +az compute-recommender spot-placement-score \ + --location "eastus" \ + --desired-locations "eastus" "westus2" \ + --desired-sizes "[{sku:Standard_D4s_v5}]" \ + --desired-count 10 +``` + +Via REST API: + +```bash +az rest \ + --method post \ + --url "/subscriptions//providers/Microsoft.Compute/locations/eastus/placementScores/spot/generate?api-version=2025-06-05" \ + --body '{ + "desiredLocations": ["eastus", "westus2"], + "desiredSizes": [{"sku": "Standard_D4s_v5"}], + "desiredCount": 10, + "availabilityZones": false + }' +``` + +Output includes a placement score—**High**, **Medium**, or **Low**—for each SKU-region combination, along with quota availability. A score of High indicates the deployment is highly likely to succeed; Low indicates low likelihood. Scores are point-in-time recommendations and don't guarantee allocation. If a SKU isn't available for your subscription, the API returns **Restricted SKU** instead of a placement score. + +See the [Spot Placement Score documentation](https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/spot-placement-score) for details. + +### Step 2: Deploy a Spot VM + +```bash +az vm create \ + --resource-group "rg-prod" \ + --name "vm-spot-01" \ + --image "UbuntuLTS" \ + --size "Standard_D4s_v5" \ + --priority "Spot" \ + --max-price "0.50" \ + --eviction-policy "Deallocate" +``` + +Set `--max-price` to your bid. If the spot price exceeds your bid, the VM is evicted. Use `--eviction-policy "Delete"` for stateless workloads or `--eviction-policy "Deallocate"` to pause the VM and avoid re-initialization costs. + +### Step 3: Understand Spot capacity pool + +Spot VMs use a separate capacity pool from reserved or standard PAYG VMs. You can have: + +- 10 Standard_D4s_v5 instances in a capacity reservation group (supply SLA) +- 12 Standard_D4s_v5 PAYG instances (no SLA) +- 50 Standard_D4s_v5 Spot instances (no SLA, up to 90% discount) + +All three types use the same SKU but different pricing and SLA models. See [Spot VMs overview](https://learn.microsoft.com/en-us/azure/virtual-machines/spot-vms) for more detail. + +--- + +## Exercise 8: Validate quota before large procurements + +[Quota](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) limits how many vCores of each family you can allocate in a region. Before creating capacity reservations, confirm you have sufficient quota. + +### Step 1: Check current quota usage + +```powershell +.\scripts/quota/Get-AzVMQuotaUsage.ps1 ` + -SubscriptionId "" ` + -Location "eastus" +``` + +Output shows: + +``` +SKU : Standard_D4s_v5 +UsedQuota : 6 +QuotaLimit : 20 +AvailableQuota : 14 +RegionRestricted : False +ZonesRestricted : False +``` + +In this case, you've allocated 6 instances of D4s_v5 out of a 20-instance limit in East US. + +### Step 2: Request a quota increase + +If your procurement plan exceeds available quota, request an increase: + +1. Go to **Help + support** > **New support request** +2. **Issue type:** Service and subscription limits (quotas) +3. **Quota type:** Compute-VM (cores) quotas +4. **Location:** Your target region +5. **SKU:** e.g., Standard D family +6. **New limit:** Enter desired quota +7. Submit the request + +Azure reviews quota requests based on capacity availability. Requests typically complete within 1–2 business days. + +### Step 3: Plan quota for multi-region and multi-zone + +If you're procuring Standard_D4s_v5 across East US zone 1, East US zone 2, and West US zone 1, quota is counted per-region (not per-zone). A 30-instance capacity reservation in East US consumes 120 vCores from the East US Standard D quota, regardless of zone distribution. + +--- + +## Wrap-up + +Procurement is the foundation for capacity planning, cost management, and availability. The outputs of this lab feed into: + +1. **Monitoring & Observability (Deck 5):** Track actual vs. reserved utilization, alert on overallocation, and audit cost allocation across teams +2. **Governance & automation:** Enforce procurement policies (e.g., "all prod VMs must use capacity reservations"), automate quota requests, and scale procurement based on demand signals + +Key takeaways: + +- Validate SKU availability and zone alignment before committing capacity +- Use capacity reservations for supply guarantees; layer savings plans or reservations for cost reduction +- Share CRGs across subscriptions for centralized procurement, but monitor zone alignment +- Spot VMs complement reserved capacity for non-critical, cost-sensitive workloads +- Monitor utilization regularly and adjust reservations quarterly based on actual demand +- Quota is a guardrail; request increases early to avoid allocation delays during scale-outs + +### Billing scope alignment + +Cost allocation varies by your agreement type. Align CRG boundaries to match your cost structure: + +- **Enterprise Agreements (EA):** Capacity reservation purchases are visible at the billing account (enrollment) scope. If you have multiple cost centers or departments, create separate CRGs per cost center to track procurement costs separately +- **Microsoft Customer Agreement (MCA):** Capacity reservation purchases are visible at the billing profile scope. Align CRG ownership to billing profile boundaries so costs roll up correctly for chargeback or FinOps analysis + +See [Understand Cost Management scopes](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/understand-work-scopes) for guidance on mapping subscriptions, resource groups, and billing accounts to your organizational structure. + +--- + +## Beyond VMs: PaaS capacity procurement + +CRGs are VM-specific. For PaaS services, procurement uses reserved capacity pricing commitments rather than supply-side reservations. These commitments lock in discounted rates for 1-year or 3-year terms but don't guarantee physical capacity the way CRGs do. + +- **Premium SSD v2:** Provisioned IOPS and throughput are billed independently from disk size. You configure capacity by adjusting IOPS and throughput values on the managed disk resource—there's no separate reservation mechanism. Purchase through the Azure portal or `az disk create`/`az disk update` with `--disk-iops-read-write` and `--disk-mbps-read-write` parameters. See [Premium SSD v2 overview](https://learn.microsoft.com/en-us/azure/virtual-machines/disks-types#premium-ssd-v2) for provisioning details. + +- **Azure Database for PostgreSQL flexible server:** [Reserved capacity](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-reserved-capacity) provides vCore-based pricing discounts for 1-year or 3-year terms. Purchase through **Cost Management + Billing** > **Reservations** > **Add** > **Azure Database for PostgreSQL** in the portal, or use the [Reservations REST API](https://learn.microsoft.com/en-us/rest/api/reserved-vm-instances/). + +- **Azure Database for MySQL flexible server:** [Reserved capacity](https://learn.microsoft.com/en-us/azure/mysql/flexible-server/concept-reserved-pricing) works the same way as PostgreSQL—vCore-based 1-year or 3-year commitments purchased through the portal reservations blade or REST API. + +- **Azure SQL Managed Instance:** [Reserved capacity](https://learn.microsoft.com/en-us/azure/azure-sql/managed-instance/reserved-capacity?view=azuresql) provides vCore-based pricing discounts by service tier (General Purpose, Business Critical). Purchase through the portal reservations blade, selecting the service tier, region, and term. Use `az reservations reservation-order purchase` for CLI-based procurement. + +For all PaaS reserved capacity, the pricing discount applies automatically to matching resources in the reservation scope (subscription or shared). Unlike CRGs, these don't guarantee that capacity will be available at deployment time—they're cost optimization instruments only. + +--- + +## References + +- [Capacity reservation overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) +- [Capacity reservation group sharing](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share) +- [Overallocation in capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) +- [Associate VM to capacity reservation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-associate-vm) +- [Associate VMSS to capacity reservation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-associate-virtual-machine-scale-set-flex) +- [Remove VM from capacity reservation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-remove-vm) +- [Reserved Instance discounts](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations) +- [Savings plans for compute](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/savings-plan-compute-overview) +- [Spot VMs overview](https://learn.microsoft.com/en-us/azure/virtual-machines/spot-vms) +- [Spot Placement Score API](https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/spot-placement-score) +- [Get-AzComputeResourceSku cmdlet](https://learn.microsoft.com/en-us/powershell/module/az.compute/get-azcomputeresourcesku) +- [FinOps rate optimization](https://www.finops.org/framework/capabilities/rate-optimization/) +- [Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations) +- [Zonal enablement requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) +- [Region access requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) +- [VM quotas](https://learn.microsoft.com/en-us/azure/virtual-machines/quotas) +- [Understand Cost Management scopes](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/understand-work-scopes) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-05-monitoring-governance.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-05-monitoring-governance.md new file mode 100644 index 000000000..fc70d0c00 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/labs/lab-05-monitoring-governance.md @@ -0,0 +1,807 @@ +# Lab 5: Monitoring & governance + +## Overview + +This lab walks you through the operational controls that keep your Azure consumption predictable and aligned with business objectives. You'll set up quota alerts to catch capacity constraints early, deploy budgets to track spend against forecasts, implement cost anomaly detection, monitor capacity reservation utilization, suppress noisy advisor recommendations, and build dashboards that feed forecasting decisions. These controls align with the [workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) model and [cost management alerting](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending). + +We focus on the mechanics—the knobs you turn, the thresholds you set, the data you extract—not prescriptive governance models. The tools here assume you're running SaaS workloads under an EA or Microsoft Customer Agreement with multiple subscriptions organized under management groups. + +### Prerequisites + +- Access to at least two subscriptions (one for exercises 1–5, one additional for scale exercises) +- Subscriptions organized under a management group +- Contributor role on subscriptions; Advisor Contributor role for suppression exercises +- Azure CLI installed with the quota extension +- PowerShell 7+ with Azure modules (Az.CostManagement, Az.Advisor) +- Action groups already created for alerts (or create one during exercise 1) +- Read-only access to the lab script repository (scripts/ directory) + +### Lab goals + +By the end of this lab, you'll be able to: + +- configure quota usage alerts at 60%, 80%, and 90% thresholds +- deploy budgets programmatically to individual subscriptions and at scale +- activate cost anomaly detection for anomalous spend patterns +- query and interpret capacity reservation allocation states +- suppress Advisor recommendations with time-to-live (TTL) constraints +- export quota usage data and build trend dashboards +- integrate monitoring signals into your forecasting feedback loop + +--- + +## The 4-signal model + +Monitoring in this context means tracking four signals: + +- **Signal 1: Quota**—usage vs. limit by subscription, region, and VM family +- **Signal 2: Reservation**—capacity reservation group utilization and overallocation state via instanceView +- **Signal 3: Cost**—budget consumption, anomaly detection, and commitment utilization +- **Signal 4: Gate**—CI/CD pipeline pass/fail for capacity checks before stamp deployments + +Each signal maps to a different enforcement point and a different response. The exercises below cover all four signals. + +Reference: [Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) + +--- + +## Exercise 1: Create quota usage alerts + +### Goal + +Set up proactive quota alerts so you catch capacity constraints before they block deployments. You'll use the My quotas portal experience to configure thresholds and attach action groups. + +### Context + +Azure quotas limit the number of resources you can create in a subscription by type—compute cores, network interfaces, public IPs, and so on. When a quota fills up, new resource deployments fail. Quota alerts notify you at 60%, 80%, and 90% utilization so you can request quota increases before you hit the hard limit. + +The alert mechanism integrates with action groups to send emails, webhooks, or other actions when thresholds are crossed. This guidance describes [quota monitoring and alerting](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting). + +### Steps + +1. Sign in to the Azure portal and go to **Quotas** (search "quotas" in the top bar). + +2. Filter to your subscription and region. You'll see a table of resource types with current usage and limits. + +3. Select a quota you want to monitor—for example, **Standard DSv3 Family vCPUs** in East US. Select the checkbox next to it. + +4. Choose **Create alert**. The alert creation panel opens. + +5. Select or create an action group. If creating one: + - Set **Action Group Name** to something like `quota-alerts-compute` + - Set **Short Name** to `quota-cmp` + - Add a receiver (email, webhook, etc.) + +6. Configure thresholds and severity tiers: + - Enter **60** for the first threshold (Severity 3 = informational, no action) + - Enter **80** for the second (Severity 2 = plan quota action) + - Enter **90** for the third (Severity 1 = block new stamps) + - Enter **95** for the fourth (Severity 0 = critical/emergency, escalate immediately and block stamp expansion) + - Leave **100** to alert on hard limit + + Each severity tier should route to a different action group. For example: + - 60% → email to the platform team (informational) + - 80% → email to platform and finance teams (planning phase) + - 90% → email and webhook to PagerDuty on-call rotation (deployment blocker) + - 95% → immediate escalation via PagerDuty, ITSM ticket creation, and leadership notification (emergency) + +7. Enter an alert name like `quota-alert-dsvx-eastus-60pct` and select **Create**. + +8. Repeat for other quota types relevant to your workloads (vCPUs, managed disks, network interfaces). Create separate action groups for each severity level to ensure the right people get the right alerts at the right time. + +### Validation + +After 5–10 minutes, the alerts appear in **Monitor > Alerts**. When utilization crosses a threshold, the action group fires. You can test by selecting **Test action group** from the alert rule's detail page. + +--- + +## Exercise 2: Deploy subscription budgets + +### Goal + +Deploy a budget to a single subscription using the `Deploy-Budget.ps1` script, configure thresholds, and verify it tracks actual spend. + +### Context + +Budgets are subscription-scoped cost controls. They track actual and forecasted spend and trigger alerts at your chosen thresholds (50%, 75%, 90%, and optionally 100% of forecasted spend). Unlike quotas, budgets don't block resources—they notify you so you can course-correct. This guidance describes [budget alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending). + +The `Deploy-Budget.ps1` script automates budget creation. It accepts budget amounts as parameters or reads them from a subscription tag (`BudgetAmount`). This approach lets you manage per-subscription budgets without editing scripts. + +### Steps + +1. Identify or create a subscription tag called `BudgetAmount` with a value—for example, `5000` (USD). This becomes your monthly budget cap. If you omit the tag, the script defaults to `$10`. + +2. Open PowerShell and go to the lab scripts directory. + +3. Run the script with parameters: + +```powershell +$contactEmails = @("platform-team@example.com", "finance@example.com") +$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + +.\Deploy-Budget.ps1 ` + -SubscriptionId $subscriptionId ` + -ContactEmails $contactEmails ` + -Amount 5000 ` + -TimeGrain Monthly ` + -StartDate (Get-Date) ` + -FirstThreshold 50 ` + -SecondThreshold 75 ` + -ThirdThreshold 90 ` + -ForecastedThreshold 100 +``` + +4. The script creates a budget named `subscription-budget-` with action groups targeting your contact emails. + +5. Verify in the portal: go to **Cost Management > Budgets** and confirm the budget appears with correct thresholds. + +### Parameters explained + +- `-Amount`: monthly budget in currency units (USD by default) +- `-TimeGrain`: Monthly, Quarterly, or Annually +- `-ContactEmails`: array of email addresses for alerts +- `-FirstThreshold`, `-SecondThreshold`, `-ThirdThreshold`, `-ForecastedThreshold`: percentage thresholds (0–100) +- `-WhatIf`: preview changes without applying +- `-Force`: skip confirmation prompts +- `-Quiet`: suppress console output + +### Validation + +In Cost Management, select the budget and confirm it shows: + +- Start and end dates +- Threshold alerts listed +- Associated action group(s) + +Wait 24 hours for the first cost data to populate (Cost Management refreshes daily). Then check **Alerts** to see if any fire. + +--- + +## Exercise 3: Deploy budgets at scale + +### Goal + +Use `Deploy-BulkBudgets.ps1` to deploy budgets across all subscriptions under a management group. Preview changes with `-WhatIf` before applying. + +### Context + +When you have dozens or hundreds of subscriptions, deploying budgets one at a time is unsustainable. The bulk script iterates subscriptions under a management group and applies the same budget template to each. Tag-based amounts let you vary the budget per subscription without script changes. This guidance describes [budget alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending). + +### Steps + +1. Ensure all subscriptions under your target management group have the `BudgetAmount` tag set appropriately. If a subscription lacks the tag, the script uses the default amount you specify. + +2. Run the script with `-WhatIf` to preview: + +```powershell +$contactEmails = @("platform-team@example.com") +$managementGroup = "prod-workloads" # name or ID +$defaultAmount = 10000 + +.\Deploy-BulkBudgets.ps1 ` + -ManagementGroup $managementGroup ` + -ContactEmails $contactEmails ` + -Amount $defaultAmount ` + -TimeGrain Monthly ` + -WhatIf +``` + +3. Review the `-WhatIf` output. It shows each subscription and the budget that would be created. + +4. If the preview looks correct, run without `-WhatIf`: + +```powershell +.\Deploy-BulkBudgets.ps1 ` + -ManagementGroup $managementGroup ` + -ContactEmails $contactEmails ` + -Amount $defaultAmount ` + -TimeGrain Monthly ` + -Quiet +``` + +The `-Quiet` flag suppresses per-subscription output, useful for large deployments. + +5. Verify in Cost Management: filter to **Budgets** and confirm one budget per subscription appears. + +### Scale considerations + +- The script paginates subscriptions internally—no manual pagination needed +- For 100+ subscriptions, the script may take 5–10 minutes +- Each budget gets its own action group to avoid alert storms on shared groups +- If a subscription already has a budget with the same name, the script skips it (use `-Force` to overwrite) + +--- + +## Exercise 4: Deploy cost anomaly alerts + +### Goal + +Deploy cost anomaly detection to catch unusual spending patterns. You'll deploy to a single subscription first, then at enterprise scale using the bulk script. + +### Context + +Cost anomaly alerts use machine learning to detect when spending deviates from historical trends. Unlike budgets (which use fixed thresholds), anomaly detection learns your baseline spend and flags outliers. This is particularly useful for SaaS workloads with variable usage patterns. This guidance describes [analyzing unexpected charges](https://learn.microsoft.com/en-us/azure/cost-management-billing/understand/analyze-unexpected-charges) and the [scheduled actions API](https://learn.microsoft.com/en-us/rest/api/cost-management/scheduled-actions). + +The `Deploy-AnomalyAlert.ps1` script creates a scheduled action—a standing automation rule—that monitors daily cost data and notifies you when anomalies occur. + +### Steps (single subscription) + +1. Identify the target subscription and a notification email. + +2. Run the script: + +```powershell +$emailRecipients = @("platform-team@example.com", "finance-alerts@example.com") +$notificationEmail = "platform-team@example.com" +$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + +.\Deploy-AnomalyAlert.ps1 ` + -SubscriptionId $subscriptionId ` + -EmailRecipients $emailRecipients ` + -NotificationEmail $notificationEmail ` + -Quiet +``` + +3. The script deploys a Bicep template (`anomaly-alert.bicep`) that creates a `Microsoft.CostManagement/scheduledActions` resource at subscription scope. + +4. Verify in the portal: go to **Cost Management > Cost anomaly** and confirm a detection rule appears. + +### Steps (enterprise scale) + +For multiple subscriptions under a management group: + +```powershell +$tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +$managementGroup = "prod-workloads" +$emailRecipients = @("platform-team@example.com") +$notificationEmail = "platform-team@example.com" + +.\Deploy-BulkALZ.ps1 ` + -TenantId $tenantId ` + -ManagementGroup $managementGroup ` + -EmailRecipients $emailRecipients ` + -NotificationEmail $notificationEmail ` + -WhatIf +``` + +After reviewing the `-WhatIf` output, run without it to deploy. + +### How anomaly detection works + +Once deployed, the alert monitors spend each day. The system builds a baseline over the first ~10 days. After that, Cost Management's ML models detect statistically significant deviations from your baseline spending pattern and trigger notifications. Unlike budgets, anomaly thresholds don't require manual tuning for each subscription. + +### Validation + +Check **Cost Management > Alerts > Cost anomaly**. You'll see: + +- Detection rules listed per subscription or management group +- **Alert** tab showing any triggered anomalies (there won't be any until spend deviates from baseline) + +--- + +## Exercise 5: Monitor capacity reservation utilization + +### Goal + +Query capacity reservation utilization via the instanceView property, interpret allocation states, and use that data to adjust reservation sizes. + +### Context + +Capacity reservations guarantee VM instance availability in a specific zone. The instanceView property tracks three quantities: + +- **available**: reserved capacity not yet allocated to instances +- **consumed**: capacity actively in use by running instances +- **overallocated**: capacity reserved but sold beyond the limit (only possible if you explicitly enabled overallocation) + +Monitoring these three states helps you right-size reservations—keeping available capacity low without running short. This guidance describes [capacity reservation overallocation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate). + +### Steps + +1. List all capacity reservations in your subscription: + +```bash +az capacity reservation list --subscription $SUBSCRIPTION_ID -o json +``` + +2. For each reservation, get the instanceView to see allocation states: + +```bash +az capacity reservation show \ + --capacity-reservation-group myGroup \ + --name myReservation \ + --resource-group myRG \ + --subscription $SUBSCRIPTION_ID +``` + +Look for the `instanceView` object, which contains: + +```json +"instanceView": { + "statuses": [ + { + "code": "ProvisioningState/succeeded", + "level": "Info" + } + ], + "utilizationInfo": { + "virtualMachinesAllocated": [ + { + "id": "/subscriptions/sub1/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm1" + } + ] + } +} +``` + +The `sku.capacity` property on the reservation itself defines the reserved quantity. Compare `virtualMachinesAllocated` count against `sku.capacity` to calculate utilization. See the [capacity reservation overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) for the full response schema. + +3. Calculate your utilization ratio: + +``` +Utilization = count(virtualMachinesAllocated) / sku.capacity +``` + +Aim for 80–95% utilization. If utilization creeps above 95%, request a larger reservation. If it drops below 50%, consider reducing the reserved quantity. + +4. If you've enabled [overallocation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) on a reservation, the count of allocated VMs may exceed `sku.capacity`. This is intentional and allows you to pack more VMs than you reserved, accepting burst risk. + +### Interpretation guide + +| State | Meaning | Action | +|-------|---------|--------| +| allocated VMs < sku.capacity | Unused reserved capacity | Consider reducing reservation size to improve ROI | +| allocated VMs ≈ sku.capacity | Optimal utilization | No action needed | +| allocated VMs > sku.capacity | Overallocation enabled | Expected; verify burst tolerance with platform team | +| allocated VMs < 0.5 x sku.capacity | Underutilized | Reduce reservation size or consolidate workloads | + +### Export for dashboards + +You can export instanceView data via the portal or CLI: + +```bash +az capacity reservation list \ + --subscription $SUBSCRIPTION_ID \ + --query "[].{name: name, reserved: sku.capacity, allocatedVMs: length(instanceView.utilizationInfo.virtualMachinesAllocated || [])}" \ + -o table +``` + +Use this output to feed dashboards in Azure Monitor or Power BI. + +--- + +## Exercise 5b: Validate monitoring scope coverage + +### Goal + +Ensure that your cost, quota, and capacity reservation monitoring rules cover all relevant scopes so you don't miss alerts due to scope mismatches. + +### Context + +Different monitoring signal types operate at different scopes: + +- **Cost anomaly detection** operates at subscription or resource group scope +- **Quota alerts** are per subscription + region + VM family +- **Capacity reservation utilization** is per capacity reservation group (there's no built-in anomaly detection—you monitor utilization via instanceView) + +If your monitoring scopes don't align with where changes actually occur, you'll miss notifications. For example, if you configure a cost anomaly at the management group level but your actual spend variance happens at a resource group level, the aggregation might hide the signal. + +### Steps + +1. List your subscriptions and organize them by region and VM family (for quota tracking): + +```bash +az account list -o table --query "[].{name: name, subscriptionId: id}" +``` + +2. For cost anomalies, define your scope explicitly: + - Are you monitoring at subscription or resource group level? + - Document which subscriptions have cost anomalies enabled and at what scope + - Verify that all cost-critical subscriptions are covered + +3. For quota anomalies, map your subscriptions to the regions and VM families you use: + +```bash +az vm list-usage --subscription $SUBSCRIPTION_ID --location eastus -o table +``` + +Record the VM families in use. For each subscription + region + family combination, ensure you have a quota alert configured (see Exercise 1). + +4. For capacity reservations, list all CRGs and verify monitoring is enabled: + +```bash +az capacity reservation group list --subscription $SUBSCRIPTION_ID -o json | jq -r '.[].id' +``` + +Check that you're extracting instanceView data regularly for each CRG (see Exercise 5). + +5. Create a scope coverage matrix: + +| Scope Type | Scope | Anomaly Type | Coverage | Action Group | +|------------|-------|--------------|----------|--------------| +| Subscription | sub-prod-1 | Cost | Yes | cost-alerts-prod | +| Subscription + Region + VM Family | sub-prod-1, eastus, Standard_D2s_v3 | Quota | Yes | quota-alerts-compute | +| Capacity Reservation Group | crg-prod-app-tier | Overallocation | Yes | reservation-alerts | + +Document any gaps. If a scope is missing, either configure monitoring or document why it's intentionally excluded. + +### Validation + +After defining your scope boundaries: + +- Run a test anomaly detection run to verify the scope captures the signal +- Confirm that each monitoring rule fires only for its intended scope +- Review alerts from the past week to ensure scope coverage is complete + +Reference: [Capacity reservation overallocation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) + +--- + +## Exercise 6: Suppress noisy Advisor recommendations + +### Goal + +Use the Advisor suppression API to mute recommendations you've reviewed and decided not to act on. Suppressions include a TTL (time-to-live) so recommendations re-surface after investigation. + +### Context + +Azure Advisor generates recommendations across categories: cost, security, reliability, operational excellence, and performance. Some recommendations are noisy (e.g., "use reserved instances" even though you already use them for most workloads) or not applicable to your architecture. Suppression lets you silence them without losing the capability to review them later. + +Suppressions expire after a maximum of 90 days, forcing you to actively re-evaluate rather than permanently hiding recommendations. This guidance describes [Advisor suppression](https://learn.microsoft.com/en-us/azure/advisor/suppress-recommendations). + +Your account must have the **Advisor Contributor** role. This guidance describes [Advisor permissions](https://learn.microsoft.com/en-us/azure/advisor/permissions). + +### Steps + +1. Identify noisy recommendation types. Go to **Azure Advisor > Cost** and look for recommendations you want to suppress (e.g., "buy reserved instances"). + +2. Note the recommendation type ID. You can find these in the Advisor API docs or by querying the API directly: + +```bash +az rest --method get \ + --url "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/providers/Microsoft.Advisor/recommendations?api-version=2020-01-01" \ + --query "value[0].properties.recommendationType" -o tsv +``` + +Common type IDs include: +- Cost optimization recommendations (GUIDs vary by region and recommendation category) + +3. Run the suppression script with a TTL (max 90 days): + +```powershell +$managementGroupId = "prod-workloads" +$recommendationTypeIds = @( + "01234567-89ab-cdef-0123-456789abcdef", # example GUID + "fedcba98-7654-3210-fedc-ba9876543210" # another example +) +$days = 30 + +.\Suppress-AdvisorRecommendations.ps1 ` + -ManagementGroupId $managementGroupId ` + -RecommendationTypeIds $recommendationTypeIds ` + -Days $days ` + -WhatIf +``` + +4. Review the `-WhatIf` output and confirm the recommendation types you want to suppress. + +5. Run without `-WhatIf` to apply: + +```powershell +.\Suppress-AdvisorRecommendations.ps1 ` + -ManagementGroupId $managementGroupId ` + -RecommendationTypeIds $recommendationTypeIds ` + -Days $days +``` + +6. Verify in the portal: go to **Azure Advisor** and confirm suppressed recommendations no longer appear (or appear with a "suppressed" badge). + +### TTL and re-evaluation + +After 30 days (in the example above), the suppression expires and the recommendation re-surfaces. This forces periodic re-review rather than fire-and-forget. If you want permanent suppression, re-run the script periodically or increase the TTL up to 90 days. + +--- + +## Exercise 6b: CI/CD capacity gates + +### Goal + +Integrate four capacity checks into your deployment pipeline to prevent stamp deployments that would violate quota, budget, or reservation constraints. + +### Context + +The workload supply chain model uses gates to promote workloads through dev → staging → production. Capacity gates are enforcement points that verify sufficient headroom exists before a deployment proceeds. This prevents cascading failures and ensures your monitoring and governance layers are connected to operational decisions. + +### Steps + +Add the following four checks to your deployment pipeline (e.g., in your CI/CD orchestration or pre-deployment validation step): + +1. **Quota headroom check**: Verify available quota is greater than the deployment requirement for both the region and VM family + + ```bash + # Pseudocode for quota gate + REQUIRED_CORES=20 + QUOTA_FAMILY="Standard_D2s_v3" + TARGET_REGION="eastus" + + AVAILABLE=$(az vm list-usage \ + --location $TARGET_REGION \ + --subscription $SUBSCRIPTION_ID \ + --query "[?name.value=='$QUOTA_FAMILY'].{available: (limit - currentValue)}" \ + -o tsv) + + if [ "$AVAILABLE" -lt "$REQUIRED_CORES" ]; then + echo "GATE_FAILED: Insufficient quota in $TARGET_REGION for $QUOTA_FAMILY" + exit 1 + fi + ``` + +2. **Alert coverage check**: Verify that quota and cost alerts are configured for the target subscription and region + + ```bash + # Pseudocode for alert coverage gate + SUBSCRIPTION_ID="target-sub" + TARGET_REGION="eastus" + + # Check for quota alerts in this region + QUOTA_ALERTS=$(az monitor metrics alert list \ + --subscription $SUBSCRIPTION_ID \ + --query "[?contains(description, '$TARGET_REGION')].name" \ + -o tsv) + + if [ -z "$QUOTA_ALERTS" ]; then + echo "GATE_FAILED: No quota alerts configured for $TARGET_REGION" + exit 1 + fi + ``` + +3. **Capacity reservation check** (if applicable): Verify reserved quantity ≥ deployment target + + ```bash + # Pseudocode for CRG gate + TARGET_CRG="crg-prod-app-tier" + REQUIRED_INSTANCES=10 + + RESERVED=$(az capacity reservation show \ + --capacity-reservation-group $TARGET_CRG \ + --subscription $SUBSCRIPTION_ID \ + --query "instanceView.allocatedQuantity" \ + -o tsv) + + if [ "$RESERVED" -lt "$REQUIRED_INSTANCES" ]; then + echo "GATE_FAILED: Insufficient reserved capacity in $TARGET_CRG" + exit 1 + fi + ``` + +4. **Budget posture check**: Verify current spend + projected deployment spend doesn't exceed budget + + ```bash + # Pseudocode for budget gate + SUBSCRIPTION_ID="target-sub" + PROJECTED_MONTHLY_SPEND=500 # USD + + CURRENT_SPEND=$(az rest --method post \ + --url "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/providers/Microsoft.CostManagement/query?api-version=2023-11-01" \ + --body '{"type":"ActualCost","timeframe":"MonthToDate","dataset":{"granularity":"None","aggregation":{"totalCost":{"name":"Cost","function":"Sum"}}}}' \ + --query "properties.rows[0][0]" \ + -o tsv) + + BUDGET=$(az consumption budget show \ + --budget-name "subscription-budget-$SUBSCRIPTION_ID" \ + --query "amount" \ + -o tsv) + + if [ $(($CURRENT_SPEND + $PROJECTED_MONTHLY_SPEND)) -gt "$BUDGET" ]; then + echo "GATE_FAILED: Budget insufficient for deployment" + exit 1 + fi + ``` + +5. Integrate these checks as pass/fail gates in your pipeline. Each check should either pass (proceed to next stage) or fail (block deployment and alert the team). + +### Example pipeline integration (GitHub Actions) + +```yaml +name: Deploy with capacity gates + +jobs: + capacity-gates: + runs-on: ubuntu-latest + steps: + - name: Quota headroom gate + run: | + # Run quota check script + ./scripts/check-quota-headroom.sh ${{ secrets.SUBSCRIPTION_ID }} eastus + - name: Alert coverage gate + run: | + # Run alert coverage check + ./scripts/check-alert-coverage.sh ${{ secrets.SUBSCRIPTION_ID }} eastus + - name: CRG capacity gate + run: | + # Run reservation check + ./scripts/check-crg-capacity.sh ${{ secrets.SUBSCRIPTION_ID }} crg-prod-app-tier + - name: Budget posture gate + run: | + # Run budget check + ./scripts/check-budget-posture.sh ${{ secrets.SUBSCRIPTION_ID }} + - name: Deploy + if: success() + run: | + # Proceed to deployment only if all gates pass + az deployment group create --resource-group myRG --template-file main.bicep +``` + +### Validation + +After implementing capacity gates: + +- Attempt a deployment that would exceed quota—verify it blocks +- Attempt a deployment when budget is exhausted—verify it blocks +- Attempt a deployment when alert coverage is missing—verify it blocks +- Attempt a valid deployment—verify it proceeds + +Reference: [Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) + +--- + +## Exercise 7: Build a quota usage dashboard + +### Goal + +Export quota usage data and build a dashboard that shows trends over time, helping you forecast when you'll need quota increases. + +### Context + +Quota usage changes as your workloads scale. A dashboard that tracks utilization trends helps you predict when you'll hit limits and request increases proactively. The `Get-AzVMQuotaUsage.ps1` script provides multi-threaded quota data collection—fast enough for large subscriptions. + +This guidance describes the [workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) and how it connects to forecasting. + +### Steps + +1. Export quota usage for a subscription using the script: + +```powershell +.\Get-AzVMQuotaUsage.ps1 -SubscriptionId $subscriptionId +``` + +This returns a PowerShell object with quota type, current usage, limit, and percentage utilization. + +2. Export to CSV for ingestion into a dashboard tool: + +```powershell +$quotas = .\Get-AzVMQuotaUsage.ps1 -SubscriptionId $subscriptionId +$quotas | Export-Csv -Path "quota-usage-$(Get-Date -Format 'yyyy-MM-dd').csv" -NoTypeInformation +``` + +3. Collect CSV files daily or weekly via Azure Automation or a scheduled task, appending to a data store (Azure Table Storage, SQL Database, etc.). + +4. Build a dashboard in Power BI or Azure Monitor that shows: + + - Quota utilization over time (line chart with percentage on Y axis, date on X axis) + - Trends per quota type (e.g., vCPUs, managed disks) + - Forecasted utilization (using linear regression or moving averages) + - Subscriptions where utilization exceeds 80% (highlight for action) + +5. Schedule the dashboard as a daily email or embed it in your platform operations portal. + +### Example dashboard queries + +If you're storing quota data in a SQL database: + +```sql +SELECT + quota_type, + subscription_id, + current_usage, + quota_limit, + CAST(current_usage AS FLOAT) / quota_limit * 100 AS utilization_pct, + captured_date +FROM quota_usage +WHERE subscription_id = @subscriptionId + AND captured_date >= DATEADD(day, -90, GETDATE()) +ORDER BY captured_date DESC, quota_type; +``` + +Use this to build trend charts and alert thresholds in your BI tool. + +### PaaS service monitoring + +Quota groups cover IaaS compute only. For PaaS services, monitor quotas and costs through service-specific mechanisms: + +- **Azure Storage**: Storage accounts have a [per-subscription quota](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-storage-limits) (default 250 per region). Monitor account counts and configure budget alerts for storage spend. + + ```bash + az storage account list --subscription $SUBSCRIPTION_ID \ + --query "length([?location=='eastus'])" -o tsv + ``` + +- **Azure Cosmos DB**: Monitor [provisioned RU throughput](https://learn.microsoft.com/en-us/azure/cosmos-db/monitor#monitoring-overview) and set budget alerts for Cosmos DB spend. Use Azure Monitor metrics (`TotalRequestUnits`, `NormalizedRUConsumption`) to track utilization against provisioned capacity. + + ```bash + az monitor metrics list --resource $COSMOS_RESOURCE_ID \ + --metric "NormalizedRUConsumption" --interval PT1H -o table + ``` + +- **Azure Service Bus**: Monitor [messaging unit utilization](https://learn.microsoft.com/en-us/azure/service-bus-messaging/monitor-service-bus-reference) with Azure Monitor metrics (`NamespaceMemoryUsage`, `IncomingMessages`). Premium namespaces have messaging unit quotas that constrain throughput. + + ```bash + az monitor metrics list --resource $SERVICEBUS_RESOURCE_ID \ + --metric "IncomingMessages" --interval PT1H -o table + ``` + +- **Azure Key Vault**: Monitor [transaction rate limits](https://learn.microsoft.com/en-us/azure/key-vault/general/service-limits) with Azure Monitor metrics (`ServiceApiHit`, `ServiceApiLatency`). Key Vault enforces throttling at 4,000 transactions per 10 seconds for vaults in the same region. + +- **Azure Event Hubs**: Monitor [throughput units](https://learn.microsoft.com/en-us/azure/event-hubs/monitor-event-hubs-reference) with Azure Monitor metrics (`IncomingBytes`, `OutgoingBytes`). Auto-inflate can scale throughput units automatically, but set budget alerts to catch unexpected cost growth. + +Include these PaaS metrics in your quota usage dashboard alongside compute data for a complete view of your capacity posture. + +### Connecting to forecasting + +Once you have historical quota usage data, you can forecast when you'll hit limits: + +1. Calculate the rate of quota usage increase (e.g., 5% per week) +2. Extrapolate: if current utilization is 60% and you're growing at 5% per week, you'll hit 90% in 6 weeks +3. Submit quota increase requests with 2–4 weeks lead time + +This closes the feedback loop from monitoring to forecasting to capacity planning. + +--- + +## Wrap-up: Monitoring feeds forecasting + +The exercises above create a monitoring and governance backbone organized around the 4-signal model: + +1. **Signal 1: Quota**—quota alerts catch capacity constraints early (Exercises 1, 5b, 6b) +2. **Signal 2: Reservation**—capacity reservation monitoring ensures you're getting ROI on reserved capacity (Exercises 5, 5b, 6b) +3. **Signal 3: Cost**—budgets track spend against forecasts, anomaly detection surfaces unusual patterns, and dashboards drive capacity planning (Exercises 2, 3, 4, 7) +4. **Signal 4: Gate**—CI/CD pipeline gates validate quota headroom, alert coverage, reservation capacity, and budget posture before deployments proceed (Exercise 6b) + +These signals feed into a closed loop: monitoring collects the four signals, dashboards visualize them, gates enforce them at deployment time, and forecasting uses them to drive capacity and budget planning. You circle back to monitoring to validate your forecasts. + +Additionally: + +- **Advisor suppression** reduces alert fatigue while maintaining accountability (Exercise 6) +- **Workload supply chain integration**: Monitoring data feeds the promote-through-gates model. As workloads move from dev → staging → production, each stage's deployment gates enforce the same capacity checks, ensuring consistent governance across your environment. The four signals (quota, reservation, cost, gate) align with the supply chain's enforcement points, creating a unified operational model. + +The [workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) describes this full lifecycle in detail. The monitoring layer you've built is the observability component of that chain. + +Use these signals to inform your FinOps optimization strategy—cost data and quota constraints drive rate-optimization decisions. See the [FinOps rate optimization guidance](https://www.finops.org/framework/capabilities/rate-optimization/) for details. + +--- + +## Troubleshooting + +### Budget not showing spend + +- Budgets require 24–48 hours for initial cost data population +- Verify the subscription has incurred costs +- Check that the budget's scope (subscription/management group) matches your intent + +### Anomaly detection not firing + +- Machine learning baseline takes ~10 days to establish +- Verify the scheduled action is deployed and active in the target subscription +- Check that the notification email is valid and not in spam + +### Quota alert not triggering + +- Alerts fire based on actual quota utilization, not on alert configuration +- Verify you've provisioned enough resources to approach the quota +- Wait 5–10 minutes after threshold is crossed for the alert to fire + +### Suppression script fails with permission error + +- Confirm your account has **Advisor Contributor** role at the management group scope +- Confirm your account has the [required permissions](https://learn.microsoft.com/en-us/azure/advisor/permissions) + +--- + +## References + +- [Quota monitoring and alerting](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting) +- [Create quota usage alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) +- [Budget alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending) +- [Capacity reservation overallocation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) +- [Workload supply chain](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) +- [Advisor suppression](https://learn.microsoft.com/en-us/azure/advisor/suppress-recommendations) +- [Advisor permissions](https://learn.microsoft.com/en-us/azure/advisor/permissions) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/README.md new file mode 100644 index 000000000..097a7e991 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/README.md @@ -0,0 +1,31 @@ +--- +title: Capacity management +nav_order: 4 +has_children: true +--- + +# Capacity management overview + +Use this section to access subscription lifecycle guides, capacity and quota guidance, and supporting operational references. The goal is to connect estate-level Azure controls to Azure landing zone, Well-Architected, and FinOps Framework guidance without prescribing your internal operating model. [Source](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) [Source](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) [Source](https://www.finops.org/framework/) + +- [Planning and forecasting](capacity-planning/README.md)—capacity planning inputs, isolation decisions, and demand signals for Planning & Estimating and Forecasting. +- [Workload placement](quota/README.md)—billing scopes, region and zonal access, quota requests, SKU readiness, and capacity reservation constraints for Architecting & Workload Placement. +- [Usage and rate optimization](quota-groups/README.md)—quota groups, capacity reservations, and pricing-commitment coordination for Usage Optimization and Rate Optimization. +- [Governance and automation](monitoring-alerting/README.md)—quota and reservation monitoring, alerting, governance gates, and support references for Governance, Policy & Risk and Automation, Tools & Services. + +## Subscription vending context + +- [Subscription vending](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/subscription-vending#determine-subscription-placement) standardizes how platform teams capture requests, enforce approval logic, and automate placement of new landing zones so application teams can focus on workload delivery. +- The Cloud Center of Excellence defines intake requirements (budget, owner, network expectations, data classifications) and connects the approval flow to the subscription deployment pipeline to keep governance aligned with [Azure landing zone design areas](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/subscription-vending#determine-subscription-placement). + +## Programmatic subscription creation + +- Azure supports [programmatic subscription creation](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription) for Enterprise Agreements, Microsoft Customer Agreements, and Microsoft Partner Agreements via modern REST APIs. +- Legacy EA processes use enrollment accounts to scope billing, while modern MCA workflows rely on billing profiles and invoice sections. See the dedicated legacy and modern pages in this folder for detailed guides. +- When planning subscription vending product lines, align the automation entry points from the EA and MCA procedures with the [placement guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/subscription-vending#determine-subscription-placement) so workload subscriptions land in the correct management group and billing scope. + +## Support workflows + +- [Regional access requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) unblock subscriptions in restricted regions; submit quota support tickets when deployment plans require new geographies and make sure you follow up on any offer flags set at subscription creation. +- [Zonal access requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) grant restricted VM series access to targeted availability zones, preserving high-availability plans across logical mappings. +- [VM-family](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) and [regional quota increases](https://learn.microsoft.com/en-us/azure/quotas/regional-quota-requests) continue to flow through Azure's quota tooling for any needs outside pooled quota groups. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/aks-capacity/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/aks-capacity/README.md new file mode 100644 index 000000000..fa72befb5 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/aks-capacity/README.md @@ -0,0 +1,135 @@ +--- +title: AKS capacity governance +parent: Operations +nav_order: 10 +--- + +# AKS capacity governance + +> For ISVs running stamp-based SaaS on AKS, capacity governance ensures node pools can scale without hitting quota limits or availability gaps. This page covers quota management and capacity reservation patterns specific to [Azure Kubernetes Service (AKS)](https://learn.microsoft.com/en-us/azure/aks/intro-kubernetes) node pools. + +AKS node pools consume the same regional VM quota and capacity as standalone VMs. You manage quota through [quota groups](../quota-groups/README.md) and guarantee capacity through [capacity reservation groups](../capacity-reservations/README.md), but AKS enforces constraints on how node pools associate with CRGs. This guide explains those constraints and their implications for stamp provisioning workflows. + +## Quota considerations for AKS clusters + +[AKS clusters](https://learn.microsoft.com/en-us/azure/aks/quotas-skus-regions) draw from the same VM family quota as standalone VMs. When you create or scale a node pool, AKS requests quota from the `Microsoft.Compute` provider in the subscription and region where the cluster runs. + +- **Node pool scaling failures:** If regional quota is exhausted, [autoscaler operations fail](https://learn.microsoft.com/en-us/azure/aks/cluster-autoscaler) and pods remain pending until quota increases or nodes are freed elsewhere in the region. +- **Quota group integration:** Add AKS subscriptions to a [quota group](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) so node pools share quota with other workloads across your estate. This prevents isolated exhaustion in subscriptions dedicated to specific stamps. +- **VM family alignment:** Choose [VM sizes](https://learn.microsoft.com/en-us/azure/aks/quotas-skus-regions#vm-size-restrictions) that align with your quota allocation strategy. Mixing multiple VM families across node pools fragments quota and complicates capacity planning. +- **System node pool requirements:** Every AKS cluster requires a [system node pool](https://learn.microsoft.com/en-us/azure/aks/use-system-pools) to run critical control-plane components (CoreDNS, kube-proxy, metrics-server). Don't configure system node pools to scale to zero—they must maintain at least one node. + +## Capacity reservations for node pools + +AKS node pools support [capacity reservation groups (CRGs)](https://learn.microsoft.com/en-us/azure/aks/use-capacity-reservation-groups) to guarantee that VM capacity is available when the cluster scales out. CRGs for AKS work the same way as [VM capacity reservations](../capacity-reservations/README.md)—you reserve specific VM sizes in a region and zone, then associate node pools with those reservations—but AKS enforces additional constraints on association and identity. + +### Node pool association constraints + +You can't update an existing node pool to add a capacity reservation group. You must [create a new node pool](https://learn.microsoft.com/en-us/azure/aks/use-capacity-reservation-groups#create-a-new-node-pool-with-a-capacity-reservation-group) with the `--crg-id` parameter during creation. + +```bash +# This operation isn't supported +az aks nodepool update --crg-id $CRG_ID --cluster-name myCluster --name existingPool --resource-group myRG + +# Create a new node pool instead +az aks nodepool add \ + --resource-group myRG \ + --cluster-name myCluster \ + --name newPool \ + --node-count 3 \ + --node-vm-size Standard_D4s_v3 \ + --crg-id /subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.Compute/capacityReservationGroups/{crg-name} +``` + +**Implication for stamp automation:** If you create stamps through infrastructure-as-code pipelines, ensure CRG associations are embedded in the initial node pool definition. Don't expect to retrofit existing pools with CRG references after deployment. + +### Identity and permission requirements + +AKS requires a [user-assigned managed identity](https://learn.microsoft.com/en-us/azure/aks/use-capacity-reservation-groups#prerequisites) to associate node pools with CRGs. System-assigned managed identities don't work for this scenario. + +1. **Create or identify a user-assigned identity:** The identity must exist in the same subscription as the AKS cluster. +2. **Assign Contributor role on the CRG's resource group:** The identity needs `Microsoft.Compute/capacityReservationGroups/*` permissions. [Grant the role](https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal) at the resource group scope that contains the CRG. +3. **Wait for propagation:** Role assignments can take [up to 60 minutes](https://learn.microsoft.com/en-us/azure/aks/use-capacity-reservation-groups#prerequisites) to propagate. Don't create node pools immediately after assigning roles—your pipeline will fail if the identity isn't yet active. +4. **Attach the identity to the cluster:** When you [create the AKS cluster](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity), specify the user-assigned identity with `--assign-identity`. Existing clusters can't switch from system-assigned to user-assigned identity—you'd need to recreate the cluster. + +### Disassociation and lifecycle behavior + +When you delete a node pool or cluster, AKS [automatically disassociates](https://learn.microsoft.com/en-us/azure/aks/use-capacity-reservation-groups#delete-a-node-pool-or-cluster-associated-with-a-capacity-reservation-group) it from any associated CRG before completing the delete operation. This differs from standalone VMs, where you must [manually disassociate VMs](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-remove-vm) before deleting the capacity reservation. + +- **Node pool deletion:** `az aks nodepool delete` removes the pool and its CRG association in a single operation. No manual cleanup is required. +- **Cluster deletion:** `az aks delete` disassociates all node pools from their CRGs before deleting the cluster resource. +- **Warning scenarios:** If the specified CRG doesn't exist or contains no member reservations, AKS [creates the node pool with a warning](https://learn.microsoft.com/en-us/azure/aks/use-capacity-reservation-groups#limitations-for-using-capacity-reservation-groups-with-aks-node-pools) but doesn't establish the CRG association. The node pool runs without capacity guarantees until you recreate it with a valid CRG reference. + +### Zone alignment and cross-subscription sharing + +If you're using [availability zones](https://learn.microsoft.com/en-us/azure/aks/availability-zones) with AKS, ensure the CRG's zonal capacity reservations align with the physical zones where your node pool deploys. Azure assigns different logical-to-physical zone mappings per subscription, so [validate zone mappings](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share#zone-mapping-differences-across-subscriptions) if the CRG is shared from a different subscription. + +Use the [Get-AzAvailabilityZoneMapping.ps1](../tools-scripts/get-azavailabilityzonemapping.md) script to compare zone mappings across subscriptions before configuring CRG sharing. + +## Automation patterns + +### Infrastructure-as-code templates + +Embed CRG references in your Bicep or Terraform templates to ensure node pools are created with capacity guarantees from the start. + +**Bicep example:** + +```bicep +resource nodePool 'Microsoft.ContainerService/managedClusters/agentPools@2024-01-01' = { + parent: aksCluster + name: 'prodpool' + properties: { + count: 5 + vmSize: 'Standard_D4s_v3' + capacityReservationGroupID: '/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.Compute/capacityReservationGroups/{crg-name}' + mode: 'User' + osType: 'Linux' + } +} +``` + +**Terraform example:** + +```hcl +resource "azurerm_kubernetes_cluster_node_pool" "prod" { + name = "prodpool" + kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id + vm_size = "Standard_D4s_v3" + node_count = 5 + capacity_reservation_group_id = azurerm_capacity_reservation_group.crg.id +} +``` + +### Pipeline sequencing for identity propagation + +If your pipeline creates the user-assigned identity and assigns roles in the same run, add a delay before creating the AKS cluster or node pool. + +```bash +# Create identity and assign role +az identity create --name aks-crg-identity --resource-group myRG +IDENTITY_ID=$(az identity show --name aks-crg-identity --resource-group myRG --query id -o tsv) +az role assignment create --assignee $IDENTITY_ID --role Contributor --scope /subscriptions/{sub-id}/resourceGroups/{crg-rg} + +# Wait for propagation (adjust based on observed latency) +echo "Waiting 5 minutes for role propagation..." +sleep 300 + +# Create cluster with the identity +az aks create \ + --resource-group myRG \ + --name myCluster \ + --assign-identity $IDENTITY_ID \ + --enable-managed-identity +``` + +For production pipelines, poll the role assignment status instead of using fixed delays. + +## Operational checklist + +1. Verify [regional quota](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal) before creating AKS clusters in new regions. AKS doesn't provide distinct quota from `Microsoft.Compute`—both draw from the same pool. +2. Add AKS subscriptions to [quota groups](../quota-groups/README.md) if you manage multiple stamps or environments that share capacity. +3. Create [capacity reservation groups](../capacity-reservations/README.md) for critical node pools that must scale reliably during demand surges. +4. Use [user-assigned managed identities](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) for all AKS clusters that will associate with CRGs. Don't rely on system-assigned identities. +5. Embed CRG references in node pool definitions during initial creation. Don't expect to retrofit existing pools. +6. Monitor [CRG utilization](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) to ensure reserved capacity aligns with autoscaler policies. Underutilized reservations waste cost; overallocated pools lose capacity guarantees. +7. Validate [zone mappings](../tools-scripts/get-azavailabilityzonemapping.md) if sharing CRGs across subscriptions in zonal deployments. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-and-quotas/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-and-quotas/README.md new file mode 100644 index 000000000..8661803f9 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-and-quotas/README.md @@ -0,0 +1,69 @@ +--- +title: Capacity and billing operations +parent: Operational topics +nav_order: 2 +has_children: true +--- + +# Capacity and billing operations + +This hub connects Azure billing models, subscription vending, quota operations, capacity reservations, monitoring, and automation so Azure capacity evidence fits inside the canonical FinOps Framework. It maps Azure controls to Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization, Governance, Policy & Risk, and Automation, Tools & Services, while using [Well-Architected capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [reliable scaling](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling), and [workload supply chain guidance](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) as Azure implementation references. [Source](https://www.finops.org/framework/) [Source](https://www.finops.org/framework/domains/) + +Use this page as the estate-level reference for how billing scopes, subscription creation, quota groups, capacity reservations, and CI/CD gates work together for SaaS ISVs operating Azure estates under the [ISV landing zone](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/isv-landing-zone) expectations. + +## Billing models and scopes (EA vs MCA) + +Azure enterprise customers typically operate under either the historic Enterprise Agreement (EA) or the modern Microsoft Customer Agreement (MCA). Both contracts provide an enterprise footing for Azure subscriptions, but the MCA simplifies hierarchy, automation, and tenant alignment according to [MCA billing guidance](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement). + +- EA continues to use enrollments and departments to structure subscriptions, and many ISVs keep this model in place for existing estates. Subscription creation flows through enrollment accounts and automation patterns documented for Enterprise Agreements. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) +- MCA anchors the billing account to a Microsoft Entra tenant and introduces billing accounts, billing profiles, and invoice sections, which define how subscriptions inherit tenant context and how charges roll up. [Source](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement) +- MCA billing roles are designed for automation: subscription creator, Owner, or Contributor roles at the billing account, billing profile, or invoice section scope can create subscriptions through [programmatic subscription creation](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) APIs. + +From a FinOps perspective, these billing scopes define where [Azure Reservations and savings plans](https://www.finops.org/framework/capabilities/rate-optimization/) attach as pricing constructs. Reservations and savings plans deliver rate optimization at the billing account, billing profile, or subscription scope, while [capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) guarantee supply at the region or availability zone scope. Treat these as complementary instruments: pricing commitments live at billing scopes, and capacity reservations live at compute scopes. + +## Subscription vending and support workflows + +Subscription vending connects billing scopes to workload landing zones. The goal is to standardize how you collect subscription requests, apply placement rules, and connect approvals to automation so developers receive subscriptions that match landing zone design and capacity governance. [Source](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/subscription-vending) + +- Subscription vending design areas describe how platform teams capture intake data (owners, budget, network topology, data classifications) and route deployments into the correct management group and billing scope. This keeps subscriptions aligned with [Azure landing zone design areas](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/subscription-vending#determine-subscription-placement) while preserving internal governance. +- Programmatic subscription creation for EA, MCA, and partner agreements uses modern REST APIs so you can integrate vending into CI/CD or workflow engines. Align the entry points from [EA subscription creation](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) and [MCA subscription creation](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) with your subscription vending flows. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription) +- Cross-tenant subscription requests let an MCA billing owner create a subscription for a user or service principal in another tenant using the [subscription request workflow](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription-request). This pattern is important when the ISV operates multiple tenants. + +Support workflows are part of the Azure implementation surface for Architecting & Workload Placement, Planning & Estimating, Forecasting, and Governance, Policy & Risk: + +- Region access requests unblock subscriptions in restricted regions and should be planned ahead of major launches. [Source](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) +- Zonal enablement requests grant access to restricted VM series in specific availability zones and protect high-availability designs that rely on those SKUs. [Source](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) +- VM-family and regional quota increases use standard [per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) and [regional quota requests](https://learn.microsoft.com/en-us/azure/quotas/regional-quota-requests) when capacity needs fall outside quota groups or existing limits. + +## Map Azure controls to FinOps capabilities + +- Planning & Estimating and Forecasting: Size scale units or deployment stamps from telemetry, business targets, and Well-Architected capacity planning guidance before you request quota or reservations. This connects capacity assumptions to FinOps planning, budget, and forecast evidence. [Source](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) [Source](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) [Source](https://www.finops.org/framework/capabilities/) +- Architecting & Workload Placement: Get region and zonal access approved, verify SKU availability, and use quota groups at the management group scope to avoid stranded VM-family headroom. These Azure controls shape where workloads can run. [Source](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) [Source](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) [Source](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) +- Usage Optimization: Track quota, reserved capacity, and deployment-stamp utilization so unused buffers, stranded headroom, and inefficient placement decisions are visible. Capacity reservations expose reserved versus allocated capacity through instance view. [Source](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) [Source](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) [Source](https://www.finops.org/framework/capabilities/usage-optimization/) +- Rate Optimization: Coordinate Azure Reservations and savings plans with capacity reservations when workload demand is stable enough to support a pricing commitment. Capacity reservations guarantee compute supply; Reservations and savings plans reduce rate. [Source](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) [Source](https://www.finops.org/framework/capabilities/rate-optimization/) +- Governance, Policy & Risk and Automation, Tools & Services: Wire quota and reservation utilization alerts so onboarding or seasonal spikes don't stall, and connect those signals to CI/CD gates, owner routing, budgets, anomaly alerts, and exception review. [Source](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) [Source](https://www.finops.org/framework/capabilities/governance-policy-risk/) [Source](https://www.finops.org/framework/capabilities/automation-tools-services/) + +### Links by capability area + +- Planning & Estimating and Forecasting: [Capacity planning](../capacity-planning/README.md) +- Architecting & Workload Placement: [Quota operations](../quota/README.md), [Quota groups](../quota-groups/README.md), and [Deployment patterns](../../deployment/README.md) +- Usage Optimization and Rate Optimization: [Capacity reservations](../capacity-reservations/README.md) and [Billing models](../../billing/README.md) +- Governance, Policy & Risk and Automation, Tools & Services: [Monitoring & alerting](../monitoring-alerting/README.md), [Capacity governance](../capacity-governance/README.md), and [Tools & scripts index](../tools-scripts/README.md) + +## FinOps intersections + +Capacity and billing operations intersect with multiple FinOps Framework domains and capabilities. Domains are outcomes, and capabilities describe the activities that achieve those outcomes. [Source](https://www.finops.org/framework/domains/) [Source](https://www.finops.org/framework/capabilities/) + +- Understand Usage & Cost: Capacity evidence depends on Data Ingestion, Allocation, Reporting & Analytics, and Anomaly Management so teams can see utilization, headroom, and cost signals in one reporting context. [Source](https://www.finops.org/framework/domains/) +- Quantify Business Value: Planning & Estimating, Forecasting, Budgeting, KPIs & Benchmarking, and Unit Economics connect demand projections to business context, budget guardrails, and product economics. [Source](https://www.finops.org/framework/domains/) +- Optimize Usage & Cost: Architecting & Workload Placement, Usage Optimization, and Rate Optimization cover region, zone, SKU, utilization, and pricing-commitment choices. [Source](https://www.finops.org/framework/domains/) +- Manage the FinOps Practice: Governance, Policy & Risk and Automation, Tools & Services cover alerts, controls, owner routing, exception review, and tool-supported evidence collection. [Source](https://www.finops.org/framework/domains/) + +Across these capabilities, the distinction between pricing commitments and capacity guarantees is critical. Pricing constructs such as Azure Reservations and savings plans reduce unit cost but don't reserve capacity, while capacity reservations guarantee supply without changing price on their own. The capability view on this page keeps those roles clear so ISV platform, finance, and product teams can make coordinated decisions. + + +## Tools + +For operational scripts and reporting, see: + +- [Tools & scripts index](../tools-scripts/README.md) for quota, cost, and automation utilities diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-governance/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-governance/README.md new file mode 100644 index 000000000..691faf30f --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-governance/README.md @@ -0,0 +1,65 @@ +--- +title: Capacity governance program +parent: Capacity & quotas +nav_order: 6 +--- + +# Capacity governance program + +Azure guidance connects [capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [scale-unit architecture](https://learn.microsoft.com/en-us/azure/well-architected/mission-critical/application-design#scale-unit-architecture), quota management, [Azure Reservations and savings plans](https://www.finops.org/framework/capabilities/rate-optimization/), and [monitoring](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling#choose-appropriate-scale-units) into Azure capacity governance controls. This page aggregates those references so you can align the other guides in this site with the official documentation and the FinOps Framework without guessing where guidance lives. You'll see how each link maps to the guides elsewhere in this repo. [Source](https://www.finops.org/framework/capabilities/) + +> This page aggregates Azure's capacity governance surfaces so you can integrate them into Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, Rate Optimization, Governance, Policy & Risk, and Automation, Tools & Services. Each section cites Microsoft Learn and links to supporting guides. + +## Azure capacity governance surfaces + +Azure exposes these controls for capacity governance: + +- **Planning & Estimating and Forecasting:** [Capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) guidance describes demand modeling using telemetry and business context; [scale-unit architecture](https://learn.microsoft.com/en-us/azure/well-architected/mission-critical/application-design#scale-unit-architecture) and [deployment stamps](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern) show how to structure scalable capacity envelopes. +- **Architecting & Workload Placement:** [Region access](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) and [zone enablement](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) unblock restricted areas; [quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) pool vCPU limits across subscriptions for shared inventory management. +- **Usage Optimization and Rate Optimization:** [On-demand reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) guarantee VM availability for specific sizes, regions, and zones; [overallocation tracking](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) exposes utilization states beyond reserved quantities; [rate optimization](https://www.finops.org/framework/capabilities/rate-optimization/) surfaces include reservation and savings plan utilization views. +- **Governance, Policy & Risk and Automation, Tools & Services:** [Quota alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) provide usage signals as consumption approaches limits, and [Operational excellence guidance](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) describes how to integrate capacity controls into CI/CD promotion paths. + +### Quick links + +- Planning and forecasting: [Capacity planning](../capacity-planning/README.md) +- Workload placement: [Quota operations](../quota/README.md), [Quota groups](../quota-groups/README.md) +- Usage and rate optimization: [Capacity reservations](../capacity-reservations/README.md) +- Governance and automation: [Monitoring & alerting](../monitoring-alerting/README.md), [Capacity governance](../capacity-governance/README.md), [Workload supply chain guidance](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain) + +## Forecasts and scale units + +- The Well-Architected [capacity planning article](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) describes capacity planning as an iterative process that uses historical telemetry, business context, and forecasting to keep workloads reliable without overprovisioning. +- The reliable scaling guidance recommends designing around [scale units](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling#choose-appropriate-scale-units)—logical groupings of components that scale together—and notes that you can scale individual resources, full components, or entire solutions as deployment stamps. +- In the mission-critical application design guidance, a [scale unit](https://learn.microsoft.com/en-us/azure/well-architected/mission-critical/application-design#scale-unit-architecture) is defined as a logical unit or function that can be scaled independently, potentially including code components, hosting platforms, deployment stamps, and even subscriptions when multitenant requirements are involved. +- The same guidance illustrates that [scale units](https://learn.microsoft.com/en-us/azure/well-architected/mission-critical/application-design#scale-unit-architecture) can range from microservice pods to cluster nodes and regional deployment stamps, and that using scale units helps standardize how capacity is added and validated before directing user traffic. + +## Quota groups and shared quota + +- The [Azure Quota Groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) article explains that quota groups are ARM objects created at the management group scope that allow you to share procured quota between subscriptions, distribute or reallocate unused quota, and submit group-level quota increase requests. +- [Supported scenarios](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) include deallocating unused quota from subscriptions into the group, allocating quota from the group back to subscriptions, and using group-level limit increases to make quota available for future transfers. +- Documentation notes that [quota groups are independent](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#quota-group-is-an-arm-object) of subscription placement in the management group hierarchy and do not automatically synchronize subscription membership, which keeps quota management orthogonal to policy and role hierarchies. +- The [transfer](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups#transfer-quota) and [quota allocation snapshot](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups#quota-allocation-snapshot) APIs provide a view of per-subscription limits and shareable quota for VM families and regions within a group, using the same quota constructs that apply to standard subscription quota checks. + +## Capacity reservations and compute supply + +This section focuses on compute supply through capacity reservations and capacity reservation groups, which are distinct from Azure Reservations and savings plans used for pricing and discount optimization. + +- The [on-demand capacity reservation overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) describes capacity reservations as a way to reserve compute capacity for a specific VM size in a region or availability zone, managed through capacity reservation groups. +- Reservations are created for a VM size, location, and quantity, and they can be [adjusted by changing the capacity property](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview#work-with-capacity-reservation); changes such as VM size or location require creating a new reservation and migrating workloads if needed. +- The documentation explains that [deployments that reference a capacity reservation group](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview#work-with-capacity-reservation) consume from the reserved quantity and skip quota checks up to that quantity, while deployments beyond the reserved quantity are considered [overallocations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) and are not covered by the capacity reservation SLA. +- [Overallocate capacity reservation guidance](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) clarifies the states for a reservation—capacity available, fully consumed, and overallocated—and shows how instance view data can be used to understand allocated versus reserved quantities. +- The capacity reservation overview also notes that [reserved capacity can be combined automatically with reserved instances](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview#benefits-of-capacity-reservation) to apply term-commitment discounts, while capacity reservations themselves do not require a one- or three-year commitment. + +## Reservations, savings plans, and utilization + +- [FinOps rate optimization guidance](https://www.finops.org/framework/capabilities/rate-optimization/) highlights Azure Advisor recommendations, reservation purchase recommendations, and savings plan purchase recommendations as starting points for deciding when to buy reservations or savings plans based on historical usage and cost. +- After commitments are purchased, the same guidance points to [portal experiences for viewing utilization](https://www.finops.org/framework/capabilities/rate-optimization/) for reservations and savings plans, with options to adjust scope or enable instance size flexibility to increase utilization. +- The documentation also describes [reservation utilization alerts](https://www.finops.org/framework/capabilities/rate-optimization/) that can notify stakeholders when utilization drops below a desired threshold, and showback and chargeback reports for reservations and savings plans. +- These [utilization views and alerts](https://www.finops.org/framework/capabilities/rate-optimization/) complement [capacity reservation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) and quota monitoring by providing cost-side signals about how effectively reserved capacity and savings plans are being used. + +## Monitoring quotas and capacity signals + +- The [quota monitoring and alerting article](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting) describes how the Quotas experience in the Azure portal tracks resource usage against quota limits and supports configuring alerts when usage approaches those limits. +- The [Create alerts for quotas](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) documentation details how to create alert rules from the **My quotas** blade by selecting a quota name, choosing severity, and setting a usage-percentage threshold for triggering alerts. +- Together with [quota allocation snapshots](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups#quota-allocation-snapshot) for quota groups and [instance view data](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) for capacity reservations, these monitoring capabilities provide the platform-level signals referenced in Azure's guidance on [scaling and capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning). + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-planning/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-planning/README.md new file mode 100644 index 000000000..f88515f37 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-planning/README.md @@ -0,0 +1,61 @@ +--- +title: Capacity planning +parent: Capacity & quotas +nav_order: 1 +--- + +# Capacity planning framework + +Effective capacity planning combines historical usage analysis, forecasting, and scaling strategies so Azure workloads remain reliable without overspending, as described in [capacity planning in the Azure Well-Architected Framework](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) and [reliable scaling guidance](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling). Use this framework to structure planning cycles and link outputs to quota and reservation decisions, which aligns with [workload supply chain guidance](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain). + +[FinOps capability mapping](../capacity-and-quotas/README.md): Capacity planning supports Planning & Estimating and Forecasting by sizing scale units or deployment stamps, then exposing quota, region access, and reservation needs as capacity evidence. [Source](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) [Source](https://www.finops.org/framework/capabilities/) + +## Gather utilization data + +- [Collect telemetry for CPU, memory, storage, network throughput, and request latency](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#gather-capacity-data) from Azure Monitor logs or platform metrics. +- [Cleanse and normalize the data](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#gather-capacity-data)—remove anomalies, fill gaps, and align timestamps—before generating visuals or forecasts. +- [Document business context](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#gather-capacity-data) (seasonal events, marketing campaigns, product releases) to explain historical peaks and inform future scenarios. + +## Analyze existing workloads + +- [Identify peak utilization windows, transaction rates, and concurrency](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#understand-an-existing-workload) to pinpoint components that approach their limits. +- [Visualize metrics to highlight trends and anomalies](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#understand-an-existing-workload); charts show operators where bottlenecks have occurred or may emerge. +- [Map performance thresholds](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#understand-an-existing-workload) (SLA targets, response time goals) to resource utilization to determine safe operating ranges. + +## Plan for new workloads + +- When historical data is unavailable, [estimate resource demand by modeling expected user journeys, transaction volumes, and dependency behavior](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#understand-a-new-workload). +- [Incorporate buffer capacity for uncertainty](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning#understand-a-new-workload) and explicitly track assumptions so forecasts can be revised once real usage arrives. + +## Forecast demand + +- [Produce short-term (weekly/monthly) and long-term (quarterly/annual) projections](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) using historical trends or scenario planning. +- [Include confidence ranges and plan for both normal and surge conditions](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) (for example, special events, regulatory deadlines). + +> **Boundary:** Forecasting improves readiness and procurement planning, but it doesn't guarantee regional or zonal service availability by itself. If a target region or zone is restricted for a subscription, submit a [region access request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) and, where applicable, a [zonal enablement request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series). + +## Align scaling strategies + +- [Determine where horizontal scaling (additional instances) versus vertical scaling (larger SKUs) is appropriate](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling), ensuring services remain stateless where possible to support scale-out. +- [Mix scheduling, autoscale, and manual interventions](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling) to match predictable and unpredictable load patterns. Configure autoscale rules for sudden spikes while scheduling known seasonal adjustments. +- [Tie capacity plans to quota group management, capacity reservations, or savings plans](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) so infrastructure is ready when scaling triggers occur. + +## Governance cadence + +- **Monthly:** [Treat capacity planning as an iterative process](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning)—compare forecasts to actuals and adjust plans accordingly. +- **Quarterly:** [Revisit assumptions, incorporate new business initiatives, and adjust strategic investments](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) such as new regions or disaster recovery capacity. +- **Post-incident:** [When capacity shortfalls occur, update models with new data](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) and revise monitoring thresholds and escalation paths. + +## Outputs and integration + +- [Maintain a living capacity plan](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) that documents forecasts, scaling tactics, and required quota changes so adjustments can be made as conditions evolve. +- [Feed forecasted demand into budgeting and reservation purchasing cycles](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) to balance cost and performance. +- [Store charts, scripts, and assumptions in version control](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) to support knowledge sharing and future recalibration. + +## Incorporate rate optimization into capacity forecasts + +- Capacity planning must account for regional pricing differences, so include region-specific rate inputs in your forecast model using your billing and cost datasets ([FinOps Framework planning and estimating capability](https://www.finops.org/framework/capabilities/planning-estimating/), [FinOps Hubs overview](https://learn.microsoft.com/en-us/cloud-computing/finops/toolkit/hubs/finops-hubs-overview)). +- The [FinOps Framework planning and estimating capability](https://www.finops.org/framework/capabilities/planning-estimating/) provides guidance on integrating cost projections with capacity needs. +- Use the [Cost Optimization workbook](https://learn.microsoft.com/en-us/azure/advisor/advisor-workbook-cost-optimization) in Azure Advisor to identify reservation purchase recommendations aligned with your capacity forecasts. +- When forecasting capacity for new regions, query historical pricing via [FinOps Hubs](https://learn.microsoft.com/en-us/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) to project accurate unit costs. + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-reservations/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-reservations/README.md new file mode 100644 index 000000000..af45e7b01 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/capacity-reservations/README.md @@ -0,0 +1,75 @@ +--- +title: Capacity reservations +parent: Capacity & quotas +nav_order: 2 +--- + +# Capacity reservation operations + +> FinOps capability mapping: Capacity reservations support Architecting & Workload Placement, Usage Optimization, Rate Optimization coordination, Planning & Estimating, and Automation, Tools & Services. Use them after access and quota are staged, so critical SKUs, regions, and zones are covered before you onboard or surge. [Source](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) [Source](https://www.finops.org/framework/capabilities/) + +On-demand capacity reservations guarantee that compute capacity is available when critical workloads scale out. This guide explains how to create, share, monitor, and automate capacity reservation groups (CRGs) so platform teams can coordinate with quota and deployment workflows, and it reminds you where the platform enforces prerequisites. + +## Cost implications of capacity allocation + +- Capacity reservations are billed at pay-as-you-go rates for the reserved VM size whether or not VMs are deployed against them—unused reservations still incur cost. +- Regional pricing varies: the same VM SKU costs different amounts in different regions. Check [Azure pricing by region](https://azure.microsoft.com/en-us/pricing/details/virtual-machines/linux/) before committing capacity to a specific location. +- Use [FinOps Hubs](https://learn.microsoft.com/en-us/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) to analyze historical pricing across regions before allocating; see the [FinOps Toolkit query index](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md) for available queries. +- Capacity reservations are eligible for [Reserved Instance discounts](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations)—layer rate commitments on top of capacity commitments to maximize savings. +- Factor both capacity cost and rate optimization into unit economics before allocating; unused capacity reservations without RI coverage pay full PAYG rates. +- Run [reservation-recommendation-breakdown](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md) to evaluate whether reserved instances reduce costs for capacity you've already reserved. +- Use [commitment-discount-utilization](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md) to track whether capacity reservation costs are offset by reservation discounts. +- Use [savings-summary-report](https://github.com/microsoft/finops-toolkit/blob/main/src/queries/INDEX.md) to calculate your effective savings rate across both capacity and rate commitments. + +## Prerequisites and access + +- **Quota:** Creating [reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) consumes the same regional quota used by standard VM deployments. If the requested VM size, region, or zone lacks quota or inventory, the reservation request fails and must be retried after adjusting the request or increasing quota. +- **Permission scope:** The subscription that owns the CRG manages reservation creation, resizing, deletion, and [sharing](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share) (preview). Sharing requires two sets of rights: the ODCR owner in the consumer subscription needs `Microsoft.Compute/capacityReservationGroups/share/action`; the VM owner in the consumer subscription needs `Microsoft.Compute/capacityReservationGroups/read`, `Microsoft.Compute/capacityReservationGroups/deploy`, `Microsoft.Compute/capacityReservationGroups/capacityReservations/read`, and `Microsoft.Compute/capacityReservationGroups/capacityReservations/deploy`. +- **Supported SKUs:** Only specific [VM series](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) are eligible for capacity reservations; confirm support through the `ResourceSkus` API before planning rollouts. + +## Create and manage reservations + +1. **Create a CRG:** In the Azure portal, select **Virtual machines > Capacity reservations > Add**. Provide the subscription, resource group, region, and optional [availability zone](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview). +2. **Add member reservations:** Within the CRG, specify VM size (for example, `Standard_D2s_v3`) and quantity. Azure immediately attempts to [reserve capacity](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview); if it's unavailable the deployment fails and must be retried after adjusting parameters. +3. **Associate workloads:** When deploying a VM or scale set, set the `capacityReservationGroup.id` property so the workload [consumes the reservation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) and receives the capacity SLA. +4. **Adjust quantities:** Update the reservation to increase or reduce the quantity. [Reducing to zero](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) releases the capacity but retains metadata, which is useful when pausing workloads temporarily. +5. **Delete reservations:** Remove all associated VMs and reduce the quantity to zero before [deleting a member reservation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) or its CRG to avoid orphaned associations. + +## Sharing across subscriptions (preview) + +> This feature is in public preview. Portal support isn't available; use CLI, PowerShell, or REST API. See [preview terms](https://azure.microsoft.com/support/legal/preview-supplemental-terms/). **Source**: [Share a capacity reservation group](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share) + +Sharing lets a central subscription guarantee capacity for dependent workloads: + +1. **Designate roles:** Assign an [On-demand Capacity Reservation (ODCR) owner](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share?tabs=api-1%2Capi-2%2Capi-3%2Capi-4%2Capi-5%2Capi-6%2Cportal-7) in the consumer subscription with share permissions and VM owners with deploy permissions as required. +2. **Grant access:** From the producer subscription, add consumer subscription IDs to the [CRG share list](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share?tabs=api-1%2Capi-2%2Capi-3%2Capi-4%2Capi-5%2Capi-6%2Cportal-7). You can share individual CRGs or all CRGs in the provider subscription, and up to 100 consumer subscriptions can be granted access per group. If you're sharing zonal capacity reservations, [validate zone alignment between producer and consumer subscriptions](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share) because Azure assigns different logical-to-physical zone mappings per subscription and mismatched zones won't fail at deployment time but will result in workloads landing in the wrong physical zones. +3. **Deploy from consumers:** Consumer subscriptions enumerate shared CRGs and specify the `capacityReservationGroup` field during VM deployment. [Capacity usage is billed](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share?tabs=api-1%2Capi-2%2Capi-3%2Capi-4%2Capi-5%2Capi-6%2Cportal-7) to the provider subscription, while VM runtime usage is billed to the consuming subscription. +4. **Revoke:** Remove the consumer subscription or associated identities from the share list to stop new deployments. [Existing VMs must be disassociated](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share?tabs=api-1%2Capi-2%2Capi-3%2Capi-4%2Capi-5%2Capi-6%2Cportal-7) or deallocated before revocation completes. + +## Overallocating and utilization states + +CRGs support temporary overallocations to absorb burst traffic: + +- **Reserved capacity available:** Allocated VM count is lower than reserved quantity. Consider [reducing quantity](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) if the buffer is no longer required. +- **Reservation consumed:** Allocated VM count equals reserved quantity. [Additional workloads deploy without SLA](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) until capacity increases. +- **Reservation overallocated:** Allocated VM count exceeds reserved quantity. [Excess VMs run without the capacity SLA](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) and won't regain it after deallocation unless capacity is increased. + +![Diagram that shows capacity reservation with the third VM allocated.](https://learn.microsoft.com/en-us/azure/virtual-machines/media/capacity-reservation-overview/capacity-reservation-3.jpg) + +Use the [CRG Instance View](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) (`$expand=instanceview`) to track utilization and determine whether to right-size or overprovision reservations. + +## Monitoring and reporting + +- Export [Instance View data](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) regularly to track allocated versus reserved quantities per member reservation. +- Correlate reservation usage with [quota audits](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) (for example, `az quota usage list --resource-provider Microsoft.Compute`) to ensure reservation growth aligns with available regional quota. + +## Automation patterns + +- **Create/update reservations:** Use the [`Microsoft.Compute/capacityReservationGroups` REST API](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) or `az resource` commands within CI/CD pipelines to create CRGs and member reservations with declarative templates. +- **Associate workloads:** Embed the [`capacityReservationGroup` property](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) in ARM/Bicep templates or Terraform modules so deployments automatically consume the reservation when promoted to production. +- **Sharing automation:** Script [share assignments](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share?tabs=api-1%2Capi-2%2Capi-3%2Capi-4%2Capi-5%2Capi-6%2Cportal-7) by calling the `share` action with the desired consumer subscription list, ensuring idempotent operations during pipeline runs. + +## Operational checklist + +1. Validate required [quota and inventory](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) before reserving capacity for new regions or VM sizes. +2. Review [reservation utilization](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate) regularly; adjust quantities when buffers consistently remain unused or when overallocations persist. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/escalation/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/escalation/README.md new file mode 100644 index 000000000..f67498f6e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/escalation/README.md @@ -0,0 +1,33 @@ +--- +title: Support escalation +parent: Support & reference +nav_order: 1 +--- + +# Support escalation guide + +Self-service quota tooling resolves most requests, but some capacity problems still require Microsoft intervention. Use this guide to recognize when escalation is necessary and how to submit a support ticket with the required context so you don't lose time gathering details after the ticket opens. + +## When to escalate + +- **Restricted regions or zones:** Subscriptions cannot deploy to a region or zone because of [access restrictions](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) that only Microsoft can lift. +- **Non-adjustable quotas:** The **My quotas** blade flags the target quota as [non-adjustable](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal) or the automated request is denied. +- **Service-specific limits:** Services such as Azure Cosmos DB require engineering review to raise [account/container limits or throughput ceilings](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). +- **Capacity SLA claims:** [Capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) fail to meet the SLA despite available quantity, requiring investigation and potential credits. + +## Pre-submission checklist + +- Confirm you have Owner, Contributor, or Support Request Contributor rights on the subscription; without appropriate RBAC the portal blocks [ticket creation](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request). + +## Creating the request + +1. Open the Azure portal, select the **?** icon, and choose [**Create a support request**](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request). +2. On the **Problem description** tab, select [**Service and subscription limits (quotas)**](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request), choose the subscription, and pick the relevant quota type (for example, `Compute-VM (cores-vCPUs)`, [`Azure Cosmos DB`](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase), or `Microsoft Fabric`). +3. Provide detailed [problem statements](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process), including region, VM series, desired quota value, and [deployment blockers](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). +4. Attach [supporting files](https://learn.microsoft.com/en-us/azure/azure-portal/supportability/how-to-create-azure-support-request) (screenshots, export logs) and specify severity and preferred contact method. +5. Submit and capture the support request ID for tracking. + +## Region and zone access workflow + +- When requesting [region or zone enablement](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process), list all regions, VM series, and logical zones required for upcoming deployments within the ticket. +- Reference [prior approvals](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) if recycling subscriptions so Microsoft can reconnect previously granted access. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/glossary.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/glossary.md new file mode 100644 index 000000000..5964b4e53 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/glossary.md @@ -0,0 +1,49 @@ +--- +title: Glossary & FAQ +parent: Support & reference +nav_order: 3 +--- + +# Glossary & FAQ + +Common terminology used across the quota and capacity management guides. Each entry links to the authoritative Microsoft documentation so you're never guessing which article to cite. + +## Glossary + +- **Capacity and billing operations:** Unified concept for estate-level capacity planning, quota governance, capacity reservations, and Azure billing models (EA and MCA), aligned with [Well-Architected capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning), [workload supply chain guidance](https://learn.microsoft.com/en-us/azure/well-architected/operational-excellence/workload-supply-chain), and the [FinOps Framework](https://www.finops.org/framework/). See [capacity and billing operations](capacity-and-quotas/README.md) for the full reference. +- **Capacity reservation group (CRG):** A logical container that holds one or more [on-demand capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) for specific VM sizes, regions, and zones. CRGs guarantee capacity and can be shared across subscriptions. +- **Capacity reservation:** A compute object that reserves capacity for a specific VM size in a region or availability zone, managed through a capacity reservation group, as described in the [on-demand capacity reservations overview](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview). Capacity reservations protect supply but do not change pricing on their own. +- **Azure Reservation:** A pricing construct that applies term-commitment discounts to eligible compute usage over one- or three-year terms, as described in the [FinOps rate optimization guidance](https://www.finops.org/framework/capabilities/rate-optimization/) and [Azure Reservations documentation](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/save-compute-costs-reservations). Azure Reservations reduce cost but don't guarantee capacity. +- **Azure savings plan:** A flexible pricing construct that applies discounts to eligible compute usage across services and regions over a fixed term, as described in [Azure savings plan for compute](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/). Savings plans optimize rates but do not guarantee capacity. +- **FinOps Hubs:** Data pipeline infrastructure from the [FinOps Toolkit](https://learn.microsoft.com/en-us/cloud-computing/finops/toolkit/hubs/finops-hubs-overview) that ingests cost and usage data into Azure Data Explorer via Data Factory. Hubs support KQL queries against normalized cost data using the [FOCUS schema](https://focus.finops.org/). +- **Quota group:** An Azure Resource Manager object created under a management group that [aggregates compute quota](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) across eligible subscriptions, allowing transfers and group-level increase requests. +- **Logical availability zone:** Subscription-specific mapping to [physical datacenter zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support); mappings can differ across subscriptions and must be queried via Azure Resource Manager APIs. +- **Quota alert:** An Azure Monitor alert triggered when [quota usage crosses a configured threshold](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) in the **My quotas** experience. +- **Budget alert:** A Cost Management alert generated when [actual or forecasted spend exceeds defined budget thresholds](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending). +- **Deployment stamp:** A self-contained unit of infrastructure that deploys a full copy of an application along with its supporting services, following the [Deployment Stamps pattern](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/approaches/overview#deployment-stamps-pattern). ISVs use stamps to isolate tenants, control blast radius, and scale independently across regions and zones. Each stamp is a quota and capacity consumer. +- **MACC (Microsoft Azure Consumption Commitment):** A contractual commitment to spend a minimum dollar amount on Azure over a defined period, as described in the [Microsoft Azure Consumption Commitment benefit](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/azure-consumption-commitment-benefit). Qualifying Azure services count toward MACC drawdown; marketplace purchases may or may not count depending on the offer. +- **Offer restriction:** A constraint on a VM series that blocks deployment in a subscription until the restriction is lifted via a support request. Offer restrictions differ from regional quota: quota limits how much you can deploy; offer restrictions prevent any deployment of the restricted SKU. Submit a [zonal enablement request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) or a [region access request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) to clear an offer restriction. +- **Overallocation:** The state in which more VMs are associated with a capacity reservation group than its reserved quantity, as described in [capacity reservation overallocation](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overallocate). Overallocated VMs run without a capacity SLA and don't regain it after deallocation unless the reserved quantity is increased. +- **Scale unit:** A pre-defined, deployable increment of capacity that delivers a target service level for a specific customer or tenant count. Platform teams size scale units from load-testing and telemetry, then use scale units as the unit of demand in capacity forecasting. See [capacity planning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/capacity-planning) and [Well-Architected reliable scaling](https://learn.microsoft.com/en-us/azure/well-architected/reliability/scaling). +- **Subscription request:** Workflow that allows an MCA billing owner to [create a subscription for a user or service principal in another tenant](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription-request), requiring the recipient to accept ownership. +- **Quota:** A per-subscription limit on the number of resources (typically vCPUs per VM family) that can be deployed in a given region, managed through [per-VM quota requests](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) or [regional quota requests](https://learn.microsoft.com/en-us/azure/quotas/regional-quota-requests). +- **Management group:** An Azure Resource Manager scope above subscriptions that organizes subscriptions for [RBAC, policy, and governance](https://learn.microsoft.com/en-us/azure/governance/management-groups/overview). Quota groups are created under management groups but don't inherit their policy or access controls. +- **Subscription vending:** A design pattern that standardizes how platform teams collect subscription requests, apply placement rules, and connect approvals to automation, as described in the [subscription vending design area](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/subscription-vending). +- **Anomaly alert:** A Cost Management alert that uses machine learning to detect [unexpected spending patterns](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending) and flag deviations from historical baselines. +- **Region access:** A support workflow that unblocks a subscription in a restricted Azure region. Submit a [region access support request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) when a subscription can't deploy to a specific region. Region access differs from quota: quota limits how much you can deploy; region access controls whether you can deploy at all. +- **Zonal enablement:** A support workflow that grants access to restricted VM series in specific availability zones. Submit a [zonal enablement request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) to clear the restriction. +- **FinOps:** A cloud financial management discipline that combines systems, best practices, and culture to increase an organization's ability to understand cloud costs and make informed trade-offs, as described in the [FinOps Framework](https://www.finops.org/framework/). + +## FAQ + +**When should we request a region access ticket instead of increasing quota?** +Quota groups and standard increases manage capacity within already-enabled regions. If the subscription cannot deploy to a specific region because access is restricted, submit a [region access support request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process). + +**How do we recycle a subscription without losing zone enablement?** +Reclaim quota and billing ownership but keep the subscription active. Zone access flags remain in place; deleting the subscription may require repeating the [access request workflow](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) for future projects. + +**What is the difference between capacity reservations, Azure Reservations, and savings plans?** +[Capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) ensure availability of specific VM capacity in a region or availability zone through capacity reservation groups. Azure Reservations and [Azure savings plans](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/) provide pricing discounts over a defined term, as described in [FinOps rate optimization guidance](https://www.finops.org/framework/capabilities/rate-optimization/), but they do not guarantee capacity. + +**Do quota alerts and budget alerts require different permissions?** +[Quota alerts](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) rely on Azure Monitor alert permissions (Reader or higher on the subscription), while [budget alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending) follow Cost Management RBAC (Owner, Contributor, Cost Management roles). Configure both to ensure quota usage and cost trends reach the right stakeholders. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/legacy/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/legacy/README.md new file mode 100644 index 000000000..5a0c583d4 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/legacy/README.md @@ -0,0 +1,30 @@ +--- +title: EA subscription creation (billing scope) +parent: Subscription operations +nav_order: 2 +--- + +# Enterprise Agreement subscription creation (billing scope) + +Use this guide when you're scripting Enterprise Agreement (EA) subscription creation and need reminders about which enrollment scopes and roles drive the subscription alias APIs. In EA, the control surface for creating a subscription is the enrollment account, not the subscription itself. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) + +## Scope boundaries + +- Enrollment scopes: Enrollment accounts determine billing ownership and who can create subscriptions. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) +- Subscription scope: The `Microsoft.Subscription/aliases` request returns a subscription ID, after which subscription-scoped automation applies landing zone policies, networking, and budgets. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) + +## Roles and prerequisites + +- Only Enterprise Administrators or Enrollment Account owners (or their delegated owners) can [programmatically create EA subscriptions](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest); service principals must receive the same enrollment account role assignment before calling the APIs. +- The enrollment account relationship determines where usage is billed, so automation should [authenticate in the account owner's home directory](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) before issuing API calls. + +## Provisioning flow + +1. List accessible [enrollment accounts](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) through `Microsoft.Billing/billingAccounts` to capture the enrollment and account identifiers required for new subscriptions. +2. Create or reuse a [subscription alias](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) with the target account owner and desired display metadata using the `Microsoft.Subscription/aliases` API. +3. [Assign Azure RBAC roles](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) (owner, contributor, reader) to the subscription during creation to ensure landing zone automation can immediately configure policies, networking, and budget controls. + +## Automation considerations + +- Keep [enrollment-account ownership](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) in sync with subscription vending approval workflows so the platform team can audit who can mint new EA subscriptions. +- When migrating from the legacy 2015-07-01 APIs, reissue [enrollment role assignments](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-enterprise-agreement?tabs=rest) with API version `2019-10-01-preview` to support the latest alias operations. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/modern/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/modern/README.md new file mode 100644 index 000000000..8f7e211bd --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/modern/README.md @@ -0,0 +1,35 @@ +--- +title: MCA subscription creation (billing scope) +parent: Subscription operations +nav_order: 1 +--- + +# Microsoft Customer Agreement subscription creation (billing scope) + +Use this guide when you're automating Microsoft Customer Agreement (MCA) subscription creation and need reminders about which billing identifiers and scopes feed the subscription alias APIs. In MCA, the control surface for creating a subscription lives at the billing account, billing profile, and invoice section scopes—not at the subscription scope itself. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) + +## Scope boundaries + +- Billing scopes: Billing account, billing profile, and invoice section determine where charges roll up and which identities can create subscriptions. [Source](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/azure-billing-microsoft-customer-agreement) [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) +- Subscription scope: The `Microsoft.Subscription/aliases` request returns a subscription ID, after which subscription-scoped automation applies landing zone policies, networking, and budgets. [Source](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) + +## Roles and prerequisites + +- [Billing account, billing profile, invoice section, and Azure subscription creator roles](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) can programmatically mint MCA subscriptions; the same roles can be delegated to service principals for automation. +- Automation should capture [billing account, billing profile, and invoice section identifiers](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) before provisioning so the subscription alias points to the correct billing scope. + +## Standard provisioning flow + +1. [Enumerate accessible billing accounts](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) via `Microsoft.Billing/billingAccounts` and confirm the `agreementType` is `MicrosoftCustomerAgreement`. +2. [Retrieve billing profiles and invoice sections](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) within the target account to determine the billing scope path used during alias creation. +3. [Submit a `Microsoft.Subscription/aliases` request](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement?tabs=rest) with the destination tenant, owner object ID, workload classification, and billing scope. Azure returns the subscription ID after the alias is ready. + +## Associated billing tenant scenario + +- When the destination tenant is associated to the billing account, [register an application in that tenant, grant it the required billing role, and then call the alias API directly from the destination tenant's service principal](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-customer-agreement-associated-billing-tenants). +- This [streamlined method transfers creation permissions to the destination tenant](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-customer-agreement-associated-billing-tenants), which is useful for SaaS platforms or regulated environments that still need centralized billing. + +## Two-phase cross-tenant scenario + +- For tighter governance, use the [dual-application pattern: register apps in both source (billing) and destination tenants, assign billing roles in the source, and have the destination app accept the subscription during alias creation](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement-across-tenants). +- The [two-phase flow lets the source tenant retain approval authority](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/programmatically-create-subscription-microsoft-customer-agreement-across-tenants) while allowing workloads to exist in isolated Entra tenants tied back to the same MCA billing account. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/monitoring-alerting/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/monitoring-alerting/README.md new file mode 100644 index 000000000..612c5ef1d --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/monitoring-alerting/README.md @@ -0,0 +1,32 @@ +--- +title: Monitoring & alerting +parent: Capacity & quotas +nav_order: 7 +--- + +# Monitoring & alerting guide + +> FinOps capability mapping: Quota and reservation alerts support Automation, Tools & Services, Forecasting, Anomaly Management, Budgeting, and Governance, Policy & Risk. Alert on quota and reservation utilization before saturation so releases and onboarding don't stall. [Source](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) [Source](https://www.finops.org/framework/capabilities/) + +Proactive monitoring prevents quota exhaustion and cost overruns from surprising application teams. This guide outlines how to turn on quota monitoring, author alert rules, and align quota telemetry with cost guardrails so you don't miss leading indicators. + +## Turn on quota monitoring + +- From the Azure portal, open **Quotas** and select **My quotas**. When [monitoring is turned on](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting) for a provider, adjustable quotas become highlighted and clickable, exposing usage details and alert creation shortcuts. +- Ensure administrators hold the [required Azure RBAC permissions](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting)—typically Owner, Contributor, or a custom role with alert authoring rights—before configuring monitoring and alert rules. + +## Create quota usage alerts + +1. **Select quota:** In **My quotas**, choose the [resource provider](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) (for example, `Microsoft.Compute`, `Microsoft.Storage`, or `Microsoft.Web`) and select the quota to monitor. +2. **Launch alert wizard:** Select the quota name to open the [**Create usage alert rule**](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) experience. Quota-specific dimensions (subscription, region, quota name) are pre-populated. +3. **Configure thresholds:** Set the [usage percentage trigger](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) (for example, 70%, 85%, 95%) and choose the evaluation cadence (5–15 minutes) to balance responsiveness and noise. +4. **Notifications:** Define [action groups](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) (email, Teams, ITSM) to route alerts to responders. Confirm the managed identity or user configuring the alert has Reader access on the subscription. + +## Quota dashboards + +- Export quota usage via [`az quota usage list`](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) for each provider and ingest into Log Analytics or Power BI for trend dashboards. Consistent exports allow teams to visualize approaching limits and correlate with deployment events. + +## Cost management guardrails + +- [Configure budget alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending) at the subscription, billing profile, or invoice section level to warn stakeholders when actual or forecasted spend approaches agreed thresholds. Budget alerts deliver notifications in tandem with quota alerts to reinforce accountability. +- Set [cost anomaly alerts](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending) to detect unexpected spikes that may indirectly signal runaway deployments consuming quota faster than planned. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/non-compute-quotas/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/non-compute-quotas/README.md new file mode 100644 index 000000000..dca314c53 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/non-compute-quotas/README.md @@ -0,0 +1,93 @@ +--- +title: Non-compute quotas +parent: Capacity & quotas +nav_order: 3 +--- + +# Non-compute quota guide + +## When to use this guide + +Azure capacity planning extends well beyond vCPU cores. Storage accounts, App Service plans, Azure Cosmos DB accounts, and emerging platform services all impose limits that can block customer onboarding if they are not tracked and increased ahead of demand. This guide captures the baseline limits, monitoring patterns, and escalation paths for the most common non-compute services so operations teams can manage quota holistically without juggling separate notes. + +## Service quick reference + +| Service | Default scope & notable limits | How to check usage | How to request more | +| --- | --- | --- | --- | +| **Azure Storage** | [250 standard storage accounts per subscription and region (increaseable to 500)](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests); [per-account throughput and egress limits vary by SKU](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview#scalability-targets-for-standard-storage-accounts). | [`az storage account show-usage`, `Get-AzStorageUsage`](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests), or [`az quota usage list --resource-provider Microsoft.Storage`](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest). | Use [**My quotas > Storage** to submit a numeric limit](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests); [fallback to support ticket if auto-approval fails](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal). | +| **Azure App Service** | [App Service plans capped per region (10 Free/Shared, 100 per resource group for higher tiers); storage quota enforced per plan and per region/resource group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-app-service-limits). | [`az quota usage list --resource-provider Microsoft.Web`](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) to export plan counts; portal usage charts per plan. | [Submit App Service quota adjustments through **My quotas > Web**; escalate via support when non-adjustable](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal). | +| **Azure Cosmos DB** | [500 databases/containers per account, request throughput change limits per 5-minute window; higher limits require support review](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). | Monitor provisioned throughput and request units in portal/metrics; track account limits manually. | [Create a support request (Quota type: Azure Cosmos DB) with workload details and desired limits](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). | + +If your workloads depend on other services (for example, Azure OpenAI, Dev Box, Azure Deployment Environments), extend this guide by adding their limits, monitoring commands, and support workflows so everyone's using the same reference. + +## Azure Storage quota operations + +### Key limits and dependencies + +- [Each subscription can hold up to 250 standard storage accounts per region by default; increases up to 500 require approval](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests). +- [Per-account scalability targets (aggregate ingress/egress, request rate, replication constraints) depend on the account kind](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-overview#scalability-targets-for-standard-storage-accounts). Include these constraints when forecasting storage demand. + +### Usage and tooling + +- Run [`az storage account show-usage --location ` to list the current count versus limit for storage accounts in a region](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests). +- [PowerShell administrators can retrieve the same data with `Get-AzStorageUsage` for automation pipelines](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests). +- Use [`az quota usage list --scope /subscriptions/ --resource-provider Microsoft.Storage` to generate machine-readable quota snapshots](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) that align with other quota reporting scripts. + +### Request workflow + +1. [Open **Azure portal > Quotas > Storage** and select the subscription](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests). +2. [Choose the region and select the pencil icon under **Request adjustment** to enter a new limit (up to 500)](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests). +3. [Submit the request; most approvals complete within minutes](https://learn.microsoft.com/en-us/azure/quotas/storage-account-quota-requests). +4. [If the request is denied or the limit is non-adjustable, use the **Create support request** link presented in **My quotas** to route the request to Microsoft support](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal). + + +## Azure App Service quota operations + +### Key limits and dependencies + +- [Free and Shared plans are limited to 10 instances per region, while Basic, Standard, Premium, and Isolated tiers allow up to 100 plans per resource group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-app-service-limits). +- [Storage quotas are enforced per App Service plan (10 GB Basic, 50 GB Standard, 250 GB Premium, 1 TB Isolated) and aggregated across plans within the same region/resource group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-app-service-limits). +- [Scale-out ceilings range from 3 instances (Basic) to 30 instances (Premium v2/v3/v4) and 100 instances (Isolated)](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-app-service-limits). + +### Usage and tooling + +- Use [`az quota usage list --resource-provider Microsoft.Web --scope /subscriptions/` to pull plan counts and limits for automation or dashboards](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest). +- [Review per-plan metrics (connections, storage consumption) in the App Service blade to anticipate when plan-level storage limits approach exhaustion](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#azure-app-service-limits). + +### Request workflow + +1. [Navigate to **Azure portal > Quotas > Web** and locate the target region](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal). +2. [Select the relevant quota row (for example, `AppServicePlanCount`) and choose **New quota request**](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal). +3. [Enter the desired limit and submit. Azure applies the increase automatically when capacity is available](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal). +4. [If the quota is non-adjustable or the request fails, generate a support ticket from the same blade with justification and deployment timelines](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal). + + +## Azure Cosmos DB quota operations + +### Key limits and dependencies + +- [Each account supports up to 500 databases and containers combined, and provisioned throughput changes are limited to 25 updates per five-minute interval](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). +- [Azure Cosmos DB enforces additional request limits (for example, list/get keys operations) that can throttle automation if not accounted for](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). + +### Request workflow + +1. [From **Help + Support**, create a new support request with Issue type **Service and subscription limits (quotas)** and Quota type **Azure Cosmos DB**](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). +2. [Provide workload context, current limits, desired values, and any diagnostic artifacts requested on the Additional details tab](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). +3. [Specify severity and preferred contact, then submit. The Cosmos DB engineering team typically responds within 24 hours to confirm or gather more information](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). + +[Because increases require manual approval, plan requests well ahead of large onboarding waves and track throughput usage via Azure Monitor to justify the ask](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase). + +## Monitoring and alerting + +- [Turn on quota monitoring in the Azure portal; adjustable quotas become clickable, allowing you to open the alert rule wizard directly from **My quotas**](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting). +- [Create usage alert rules with thresholds (for example, 70/85/95 percent) and severity levels aligned to escalation procedures](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting). +- [Integrate alerts with cost monitoring by configuring budget alerts for the same subscriptions, ensuring cost anomalies and quota exhaustion trigger complementary notifications](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/cost-mgt-alerts-monitor-usage-spending). + +## Extend this guide + +Maintain a backlog of additional services the community relies on (Azure OpenAI, Azure SQL, Azure Deployment Environments). For each addition, document: + +- Default limits and any preview restrictions. +- CLI/PowerShell/REST commands to retrieve usage. +- The portal or support path required for increases. +- Monitoring hooks and escalation timelines. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota-groups/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota-groups/README.md new file mode 100644 index 000000000..ffbb21f20 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota-groups/README.md @@ -0,0 +1,63 @@ +--- +title: Quota groups reference +parent: Capacity & quotas +nav_order: 5 +--- + +# Azure quota groups reference + +> FinOps capability mapping: Quota groups support Planning & Estimating, Forecasting, Architecting & Workload Placement, Usage Optimization, and Automation, Tools & Services by pooling eligible compute quota across subscriptions after region and zonal access are available. [Source](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) [Source](https://www.finops.org/framework/capabilities/) + +[Azure quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) are Azure Resource Manager (ARM) objects that let you share and self-manage compute quota across a set of subscriptions. This page aggregates key prerequisites, limitations, lifecycle behavior, and monitoring options from the official documentation so you can reason about quota groups alongside the other guides in this site, and you'll see where each Microsoft article fits. + +## Feature overview + +- [Quota groups elevate quota](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) from a per-subscription construct to a group-level ARM resource created under a management group, while quota enforcement at deployment time still occurs at the subscription level. +- The feature supports [quota sharing across subscriptions](https://learn.microsoft.com/en-us/azure/quotas/quota-groups), self-service reallocation of unused quota, and group-level quota increase requests that can later be allocated to individual subscriptions. +- [Supported scenarios](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) in the documentation include deallocating unused quota from subscriptions into the group, allocating quota from the group back to target subscriptions, and submitting quota group limit increase requests for specific regions and VM families. + +## Prerequisites + +- The [`Microsoft.Quota` and `Microsoft.Compute` resource providers must be registered](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#prerequisites) on all subscriptions you plan to add to a quota group. +- [A management group is required](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#prerequisites) to create a quota group. The group is created at the [management group scope](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#quota-group-is-an-arm-object) and inherits read and write permissions from that parent. +- [Subscriptions from different management groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#prerequisites) can be added to the same quota group; [subscription membership is independent](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#quota-group-is-an-arm-object) of the management group hierarchy as long as permissions allow it. +- The official guidance calls out the following [roles for operating quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#permissions): + - Assign the GroupQuota Request Operator role on the management group where the quota group is created. + - Assign the Quota Request Operator role on participating subscriptions for users or applications that perform quota operations. + - Assign Reader on participating subscriptions for users or applications that need to view quota group resources in the portal. + +## Limitations and scope + +- [Quota groups are available](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#limitations) only for Enterprise Agreement, Microsoft Customer Agreement, and internal subscriptions. +- They currently [support IaaS compute resources only](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#limitations) and are available in public cloud regions. +- [A subscription can belong to only one quota group](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#limitations) at a time, as noted in both the [limitations](https://learn.microsoft.com/en-us/azure/quotas/add-remove-subscriptions-quota-group#add-subscriptions-to-a-quota-group) and subscription management documentation. +- Quota groups focus on quota management; they [don't grant regional or zonal access](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#limitations). [Region and zonal access still require separate support requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process), and quota transfers or deployments can fail if the target subscription lacks region or zone access. +- [Management group deletion affects access](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#limitations) to the quota group limit. You must clear out group limits and delete the quota group object before deleting the management group, or recreate the management group with the same ID to regain access. + +## ARM object and lifecycle behavior + +- [Quota groups are global ARM resources](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#quota-group-is-an-arm-object) created at the management group scope and designed as an orthogonal grouping mechanism for quota management, separate from subscription placement in the management group hierarchy. +- [Subscription lists aren't automatically synchronized](https://learn.microsoft.com/en-us/azure/quotas/quota-groups#quota-group-is-an-arm-object) from management groups; instead, you [explicitly add and remove subscriptions](https://learn.microsoft.com/en-us/azure/quotas/add-remove-subscriptions-quota-group#add-subscriptions-to-a-quota-group) to control which ones participate in group-level quota operations. + +![Diagram of Management Group hierarchy with sample Quota Groups created under Management Group.](https://learn.microsoft.com/en-us/azure/quotas/media/quota-groups/sample-management-group-quota-group-hierarchy.png) + +- [Creating or deleting a quota group](https://learn.microsoft.com/en-us/azure/quotas/create-quota-groups) requires the GroupQuota Request Operator role on the management group. +- When you [add subscriptions to a quota group](https://learn.microsoft.com/en-us/azure/quotas/add-remove-subscriptions-quota-group#add-subscriptions-to-a-quota-group), they carry their existing quota and usage; adding them doesn't change their subscription limits or usage values. +- When you [remove subscriptions from a quota group](https://learn.microsoft.com/en-us/azure/quotas/add-remove-subscriptions-quota-group#remove-subscriptions-from-a-quota-group), they retain their existing quota and usage. The group limit isn't automatically changed by removal operations. +- At creation time, the [quota group limit is set to zero](https://learn.microsoft.com/en-us/azure/quotas/quota-groups). You must either transfer quota from a subscription in the group or [submit a quota group limit increase request](https://learn.microsoft.com/en-us/azure/quotas/quota-group-limit-increase) and wait for approval before the group can allocate capacity. +- [Before deleting a quota group](https://learn.microsoft.com/en-us/azure/quotas/create-quota-groups), all subscriptions must be removed from it, as described in the create/delete guidance. + +## Quota transfers and allocation snapshots + +- The ["Transfer quota within an Azure Quota Group" article](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups#transfer-quota) describes how to move unused quota from a subscription to the group (deallocation) or from the group to a subscription (allocation) using the quota group ARM object. +- [Quota allocation snapshots](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups#quota-allocation-snapshot) expose, for each subscription in the group, a Limit value (current subscription limit) and a Shareable quota value that reflects how many cores have been deallocated or transferred between the subscription and the group. +- The [example in the snapshot section](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups#quota-allocation-snapshot) shows a shareable quota of `-10` to indicate that 10 cores were given from the subscription to the group, alongside a new subscription limit of 50 cores for the corresponding VM family and region. +- These documented fields give you a [consistent view of how quota is distributed](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) between the group and its member subscriptions without changing how [deployments are evaluated](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups#quota-allocation-snapshot) against per-subscription limits. + +## Monitoring and alerting + +- The [Quotas experience in the Azure portal](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting) includes a **My quotas** view that continuously tracks resource usage against quota limits for providers such as Microsoft.Compute, and supports alerting when usage approaches limits. +- The [quota monitoring and alerting documentation](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting) explains that quota alerts are notifications triggered when resource usage nears the predefined quota limit, and that you can create multiple alert rules across quotas in a subscription. +- The ["Create alerts for quotas" article](https://learn.microsoft.com/en-us/azure/quotas/how-to-guide-monitoring-alerting) documents how to create alert rules from the Quotas page by selecting a quota name in **My quotas**, choosing an alert severity, and configuring a usage-percentage threshold for triggering alerts. +- While [quota group operations](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) are scoped to a management group, the [quota monitoring and alerting features](https://learn.microsoft.com/en-us/azure/quotas/monitoring-alerting) give you a way to observe usage and quota consumption trends for the underlying subscriptions that participate in the group. + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota/README.md new file mode 100644 index 000000000..692e36acb --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/quota/README.md @@ -0,0 +1,145 @@ +--- +title: Quota operations +parent: Capacity & quotas +nav_order: 4 +--- + +# Quota operations guide + +Use this guide when you're auditing or increasing Azure quotas so every request pulls from the same reference. + +[FinOps capability mapping](../capacity-and-quotas/README.md): Quota, region access, zonal enablement, and SKU readiness support Architecting & Workload Placement, Planning & Estimating, Forecasting, and Governance, Policy & Risk. Use this guide to verify those Azure constraints before moving quota into groups or reserving capacity. [Source](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) [Source](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) [Source](https://www.finops.org/framework/capabilities/) + +## Understand default quotas and enforcement + +- Azure enforces [quotas per subscription and region](https://learn.microsoft.com/en-us/azure/virtual-machines/quotas), tracking both total regional vCPUs and per VM-family vCPUs; deployments must stay within both limits or the [platform blocks the request](https://learn.microsoft.com/en-us/azure/quotas/regional-quota-requests). +- Default vCPU quotas vary by offer type. [Enterprise Agreement subscriptions default to 350 cores](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/ea-portal-agreements#resource-prepayment-and-requesting-quota-increases) for both the total regional quota and each VM family (D-series, E-series, etc.), while pay-as-you-go subscriptions default to 20 cores per region. Validate your actual limits in the [**Quotas**](https://learn.microsoft.com/en-us/azure/quotas/view-quotas) blade to confirm no offer restrictions are reducing your baseline. +- All quotas can be increased through support requests, regardless of the initial default assigned to your offer type. +- [Quota calculations](https://learn.microsoft.com/en-us/azure/virtual-machines/quotas) include allocated and deallocated virtual machines, so idle cores still count against the quota until resources are deleted or quota is increased. + +## Understand offer restrictions + +Azure applies [SKU restrictions based on your subscription's offer type](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-sku-not-available), blocking deployment of certain VM families in specific regions or zones even when quota is available. These restrictions exist independently of quota limits and you'll need to request access before deploying to affected areas. + +### What offer restrictions are + +- SKU restrictions tie to the subscription's offer type (pay-as-you-go, trial, student, MSDN, EA, or MCA Enterprise) and determine which VM families can deploy in each region and zone. +- Azure imposes two types of restrictions: [location restrictions](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-sku-not-available) block the SKU from an entire region, while zone restrictions block specific availability zones within an otherwise accessible region. +- When [`Get-AzComputeResourceSku`](https://learn.microsoft.com/en-us/powershell/module/az.compute/get-azcomputeresourcesku) shows `NotAvailableForSubscription` in the `Restriction` column, the SKU isn't available for this subscription's offer type, regardless of quota availability. + +### Why restrictions exist + +- Azure uses restrictions to [control capacity distribution](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-sku-not-available) across subscription tiers and manage datacenter resource allocation. +- Trial, student, and MSDN subscriptions face more restrictions because they're designed for development and learning scenarios rather than production workloads. +- Enterprise-tier subscriptions (EA and MCA Enterprise) have fewer restrictions, reflecting their use for production SaaS estates and mission-critical workloads. + +### Error messages you'll see + +When deployments fail because of offer restrictions, you'll encounter these error codes: + +- [`SkuNotAvailable`](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-sku-not-available)—the primary error when the requested SKU isn't available in the target region or zone. When triggered via ARM templates, this surfaces as `InvalidTemplateDeployment` during validation, and [no deployment history is created](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/find-error-code)—check the activity log instead. +- `ZonalAllocationFailed`—Azure can't allocate resources in the specific zone you requested, often because of zone restrictions or transient capacity constraints. +- `AllocationFailed`—a general allocation failure indicating capacity issues, restrictions, or other constraints preventing deployment. +- [`OverconstrainedAllocationRequest`](https://learn.microsoft.com/en-us/troubleshoot/azure/virtual-machines/windows/allocation-failure)—too many constraints (VM size, availability zone, accelerated networking, proximity placement group, ephemeral disk, Ultra disk) prevent Azure from finding available capacity. Remove constraints incrementally to identify the blocker. + +### Detect restrictions before deployment + +- Run [`Get-AzVMQuotaUsage.ps1`](https://github.com/microsoft/azcapman/tree/main/scripts/quota) to check restrictions before deploying. The script outputs `RegionRestricted` (True/False indicating whether the SKU is blocked for the entire region) and `ZonesRestricted` (comma-separated list of logical zones where the SKU is unavailable) columns for each subscription and location. +- Use [`Get-AzComputeResourceSku`](https://learn.microsoft.com/en-us/powershell/module/az.compute/get-azcomputeresourcesku) directly to inspect the `Restrictions` property for specific SKUs, which exposes location and zone restrictions along with the reason code. +- Always check restrictions before filing quota increase requests, because increased quota won't help if the offer type blocks access to the SKU in your target region or zone. + +### Remediate restrictions + +- Submit a [zonal enablement request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) when you need access to specific zones for restricted VM families; the support workflow lets you select regions, logical zones, and VM series. +- File a [region access request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) when entire regions are blocked for your subscription, ensuring quotas and offer flags match your deployment plan before attempting scale-outs or quota transfers. +- Plan ahead for these requests—there's no guaranteed SLA for approval times, so factor enablement lead time into your capacity planning and deployment schedules. + +### Special case: Spot VM capacity + +- [Azure Spot VMs](https://learn.microsoft.com/en-us/azure/virtual-machines/spot-vms) use a [separate capacity pool](https://learn.microsoft.com/en-us/azure/virtual-machines/spot-vms#frequently-asked-questions) from on-demand VMs, so a SKU can be available for regular deployments but have zero Spot capacity. +- The `Get-AzComputeResourceSku` cmdlet doesn't show Spot-specific availability. Use the [Spot Placement Score API](https://learn.microsoft.com/en-us/azure/virtual-machine-scale-sets/spot-placement-score) to evaluate deployment likelihood before committing to Spot-based architectures. +- Spot VMs have [no availability guarantees or SLA](https://learn.microsoft.com/en-us/azure/architecture/guide/spot/spot-eviction)—Azure can evict them whenever on-demand capacity is needed, providing [30 seconds total for detection and graceful shutdown](https://learn.microsoft.com/en-us/azure/architecture/guide/spot/spot-eviction), not 30 seconds after notification. +- Don't rely on Spot capacity for workloads where you've committed SLAs to your customers; use [on-demand capacity reservations](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) instead for guaranteed availability. + +## Quota analysis scripts + +> [!IMPORTANT] +> This repository includes PowerShell scripts for quota analysis developed through ISV engagements. These tools address quota management scenarios for organizations not yet using Quota Groups. + +### Available scripts + +| Script | Purpose | Use Case | +|--------|---------|----------| +| **Get-AzVMQuotaUsage.ps1** | Multi-threaded quota analysis with zone restrictions | Large-scale enterprise analysis across 100+ subscriptions | +| **Show-AzVMQuotaReport.ps1** | Single-threaded quota reporting | Smaller deployments or learning scenarios | +| **Get-AzAvailabilityZoneMapping.ps1** | Logical-to-physical zone mapping | Critical for multi-subscription architectures | + +### Quick start + +Download and run the multi-threaded quota analyzer: + +```powershell +# Download the script +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/microsoft/azcapman/main/scripts/quota/Get-AzVMQuotaUsage.ps1" -OutFile "Get-AzVMQuotaUsage.ps1" + +# Analyze specific SKUs and regions +.\Get-AzVMQuotaUsage.ps1 -SKUs @('Standard_D2s_v5', 'Standard_E2s_v5') -Locations @('eastus', 'westus2') -Threads 4 +``` + +### Script capabilities + +**Get-AzVMQuotaUsage.ps1** (Recommended for production): +- Analyzes quota usage across multiple subscriptions in parallel +- Reports zone restrictions for VM SKUs +- Maps logical zones to physical datacenters +- Outputs comprehensive CSV for further analysis +- Supports 4+ concurrent threads for faster processing + +**Get-AzAvailabilityZoneMapping.ps1** (Essential for multi-subscription deployments): +- Shows how logical zones (1,2,3) map to physical zones per subscription +- Critical because Azure randomizes zone mappings per subscription +- Required for ensuring true zone alignment across subscriptions +- Outputs zone peering data for cross-subscription planning + +[View complete script documentation →](https://github.com/microsoft/azcapman/tree/main/scripts/quota) + +## Audit regional quota and zone access + +- Run `scripts/quota/Get-AzVMQuotaUsage.ps1` for comprehensive multi-threaded analysis or `scripts/quota/Show-AzVMQuotaReport.ps1` for simpler single-threaded reporting to enumerate VM family usage versus limits per subscription and region. +- Include `-UsePhysicalZones` when you need cross-subscription mapping, because [Azure maps physical datacenters to logical availability zones](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) differently per subscription and the `checkZonePeers` API exposes the authoritative mapping. +- Use `scripts/quota/Get-AzAvailabilityZoneMapping.ps1` to generate a complete zone mapping matrix before planning multi-subscription deployments that require zone alignment. +- Scope the scripts with `-SubscriptionIds` and `-Locations` to focus on business-critical subscriptions or surge regions, then export the CSV output and compare against [`az quota usage list`](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) to validate the data against the Microsoft.Quota service. +- When you need to file a quota increase from automation, submit the request with [`az quota create`](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) and record the request ID so you can track approvals and retry deployments deterministically. +- Flag regions where the report shows restricted or missing zones and initiate the [zonal enablement workflow](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) to request access for the required VM series and zones before attempting redeployments. +- If entire regions are unavailable for a subscription, raise a [region access request](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) so that quota transfers or scale-outs do not fail when you move capacity between subscriptions. + +## Regional and zonal access workflows + +- [Region enablement requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) grant access to restricted geographies and ensure quotas and offer flags match planned deployments; submit through Azure support when the portal limits block deployments in new regions. +- [Zonal enablement requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) authorize deployments into specific availability zones for restricted VM families; use the support workflow to select regions, logical zones, and VM series before scaling out. +- Each subscription receives a [unique logical-to-physical zone mapping](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) at creation time, so use `checkZonePeers` when planning multi-subscription resilience to align physical fault domains. + +## Create and govern quota groups + +- Establish [quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) under the management group that owns your shared capacity so you can pool vCPU limits across EA and MCA subscriptions without filing support requests for every transfer. [Quota groups](https://learn.microsoft.com/en-us/azure/quotas/quota-groups) have Azure-enforced constraints: they support only EA and MCA Enterprise subscriptions, apply exclusively to compute quota (VM cores), and require registration of the `Microsoft.Quota` resource provider. +- [Create the group](https://learn.microsoft.com/en-us/azure/quotas/create-quota-groups?tabs=rest-1%2Crest-2) via the Microsoft.Quota REST API or Azure portal once the GroupQuota Request Operator role is assigned at the management group scope. +- [Add newly provisioned or recycled subscriptions](https://learn.microsoft.com/en-us/azure/quotas/add-remove-subscriptions-quota-group?tabs=rest-1%2Crest-2) to the quota group so their existing limits are tracked centrally while retaining subscription-level enforcement at deployment time. + +## Reallocate and increase capacity + +- Increase compute capacity with [capacity reservation groups](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview) when you need guaranteed VM availability, reserving specific VM sizes in targeted regions or zones with pay-as-you-go billing. +- [Share capacity reservation groups](https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-group-share) with up to 100 consumer subscriptions (preview) so platform teams own the reservation and consumer subscriptions consume capacity; unused reservations bill to the owner while VM usage accrues to consumers. +- Use [quota allocations to transfer unused cores](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups?tabs=rest-1) from retiring subscriptions back into the group and push them to surge subscriptions that need immediate capacity. +- Submit [group-level limit increase requests](https://learn.microsoft.com/en-us/azure/quotas/quota-group-limit-increase?tabs=rest-1) when aggregate demand outpaces the pooled limit; approved increases stamp capacity on the quota group so you can redistribute it without additional tickets. +- Continue to request [VM-family quota increases](https://learn.microsoft.com/en-us/azure/quotas/per-vm-quota-requests) for edge cases directly from **Quotas** when you need adjustments outside of the pooled families or regions. + +## Reclaim and recycle subscriptions + +- Recycle subscriptions with zonal or regional access rather than deleting them. There's no documented SLA for [zonal](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) or [regional enablement requests](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process)—the Azure engineering team manually reviews each request. If you offer SLAs to your customers, you can't guarantee infrastructure availability without pre-approved access flags in place. +- Before decommissioning a workload, [return its quota to the group](https://learn.microsoft.com/en-us/azure/quotas/transfer-quota-groups?tabs=rest-1) and keep the subscription for future use so that existing [zonal](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series) and [regional access flags](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) remain in place and you avoid repeating the support-ticket workflow. +- When onboarding a new subscription, check the quota report and [`az quota list`](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) output to confirm the baseline allocations before moving workloads or transferring additional quota. + +## Operational tips + +- Schedule the [quota report](https://learn.microsoft.com/en-us/azure/virtual-machines/quotas) and [CLI usage checks](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) to run after major deployments so the platform team has an auditable history of usage, available capacity, and zone coverage. +- If subscriptions span multiple tenants, pair the quota audits with the [`checkZonePeers` API](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) to ensure logical zone identifiers align before you redistribute workload placements. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/README.md new file mode 100644 index 000000000..feb46a7d6 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/README.md @@ -0,0 +1,10 @@ +--- +title: Support & reference +parent: Operational topics +nav_order: 3 +has_children: true +--- + +# Support & reference + +[Azure region access](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process), [zonal enablement](https://learn.microsoft.com/en-us/troubleshoot/azure/general/zonal-enablement-request-for-restricted-vm-series), and [quota support processes](https://learn.microsoft.com/en-us/azure/quotas/quickstart-increase-quota-portal), together with glossary material, underpin the support and reference content in this section. Use this section to find escalation guidance, tenant hygiene practices, and glossary entries so you don't piece together your own reference guide. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/citation-matrix.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/citation-matrix.md new file mode 100644 index 000000000..23d188f96 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/support-and-reference/citation-matrix.md @@ -0,0 +1,144 @@ +--- +title: Citation traceability matrix +parent: Support & Reference +nav_order: 4 +--- + +# Citation traceability matrix + +This matrix lists external links used across the documentation, along with the files that reference them. + +**Total unique URLs:** 132 + +| URL | Label | Used in | +| --- | --- | --- | +| | Azure Pricing Calculator | docs/billing/modern/README.md | +| | Azure pricing by region | docs/operations/capacity-reservations/README.md | +| | FOCUS schema | docs/operations/glossary.md | +| | View full script source → | docs/operations/tools-scripts/deploy-anomalyalert.md | +| | View full script source → | docs/operations/tools-scripts/deploy-bulkalz.md | +| | anomaly-alert.bicep | docs/operations/tools-scripts/deploy-anomalyalert.md, docs/operations/tools-scripts/deploy-bulkalz.md | +| | View full script source → | docs/operations/tools-scripts/get-azavailabilityzonemapping.md | +| | View full script source → | docs/operations/tools-scripts/get-azvmquotausage.md | +| | View full script source → | docs/operations/tools-scripts/show-azvmquotareport.md | +| | View full script source → | docs/operations/tools-scripts/get-benefitrecommendations.md | +| | GitHub repository | docs/operations/tools-scripts/README.md | +| | Suppress-AdvisorRecommendations.ps1 | docs/operations/tools-scripts/README.md | +| | `Get-AzVMQuotaUsage.ps1` | docs/operations/quota/README.md | +| | FinOps Toolkit query index | docs/billing/modern/README.md, docs/operations/capacity-reservations/README.md | +| | Azure Advisor rightsizing and shutdown recommendations use retail (pay-as-you-go) prices | docs/billing/modern/README.md | +| | Cost Optimization workbook | docs/operations/capacity-planning/README.md | +| | Source | docs/operations/tools-scripts/README.md | +| | Deployment Stamps pattern | docs/deployment/multi-tenant/README.md, docs/deployment/single-tenant/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md | +| | no availability guarantees or SLA | docs/operations/quota/README.md | +| | ticket creation | docs/operations/escalation/README.md | +| | Azure subscription service limits | docs/deployment/multi-tenant/README.md | +| | App Service plans capped per region (10 Free/Shared, 100 per resource group for higher tiers); storage quota enforced per plan and per region/resource group | docs/operations/non-compute-quotas/README.md | +| | SKU restrictions based on your subscription's offer type | docs/operations/quota/README.md | +| | no deployment history is created | docs/operations/quota/README.md | +| | Source | docs/billing/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/modern/README.md | +| | Source | docs/operations/capacity-and-quotas/README.md | +| | Subscription vending | docs/operations/README.md, docs/operations/capacity-and-quotas/README.md | +| | Microsoft's landing zone guidance | docs/deployment/README.md, docs/deployment/multi-tenant/README.md, docs/deployment/single-tenant/README.md, docs/operations/README.md, docs/operations/capacity-and-quotas/README.md | +| | account/container limits or throughput ceilings | docs/operations/escalation/README.md, docs/operations/non-compute-quotas/README.md | +| | Cost anomaly detection | docs/operations/tools-scripts/deploy-anomalyalert.md, docs/operations/tools-scripts/deploy-bulkalz.md | +| | budget alerts | docs/operations/capacity-and-quotas/README.md, docs/operations/glossary.md, docs/operations/monitoring-alerting/README.md, docs/operations/non-compute-quotas/README.md | +| | Tag inheritance policies | docs/deployment/single-tenant/README.md | +| | reservation utilization alerts | docs/billing/modern/README.md | +| | Cost Management scheduled actions | docs/operations/tools-scripts/deploy-anomalyalert.md | +| | Scheduled exports | docs/deployment/single-tenant/README.md | +| | **SubscriptionCreator** role | docs/billing/legacy/README.md | +| | create EA subscriptions | docs/billing/legacy/README.md | +| | subscription-request workflow | docs/billing/modern/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/glossary.md, docs/operations/tenant-hygiene/README.md | +| | active account | docs/billing/legacy/README.md | +| | Enrollment policies | docs/billing/legacy/README.md | +| | Enterprise Agreement subscriptions default to 350 cores | docs/operations/quota/README.md | +| | Reservation prices can be negotiated | docs/billing/modern/README.md | +| | negotiated price sheet | docs/billing/modern/README.md | +| | customer price sheet | docs/billing/modern/README.md | +| | invoice section | docs/billing/modern/README.md | +| | register an application in that tenant, grant it the required billing role, and then call the alias API directly from the destination tenant's service principal | docs/operations/modern/README.md | +| | programmatic subscription creation | docs/operations/README.md, docs/operations/capacity-and-quotas/README.md | +| | Source | docs/billing/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/legacy/README.md | +| | dual-application pattern: register apps in both source (billing) and destination tenants, assign billing roles in the source, and have the destination app accept the subscription during alias creation | docs/operations/modern/README.md | +| | create subscriptions | docs/billing/modern/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/modern/README.md | +| | track your MACC progress | docs/billing/modern/README.md | +| | Enterprise Agreement (EA) | docs/billing/legacy/README.md | +| | Microsoft Customer Agreement (MCA) | docs/billing/modern/README.md | +| | up to 10,000 subscriptions | docs/billing/modern/README.md | +| | associate additional tenants and link subscriptions across directories | docs/billing/modern/README.md, docs/operations/tenant-hygiene/README.md | +| | Reservations allow unlimited exchanges and $50,000/year in refunds | docs/billing/modern/README.md | +| | some reservations can't be exchanged or refunded | docs/billing/modern/README.md | +| | Azure Reservations | docs/billing/modern/README.md | +| | Cost Management + Billing reservation recommendations | docs/billing/modern/README.md, docs/operations/tools-scripts/get-benefitrecommendations.md | +| | Reserved Instance discounts | docs/operations/capacity-reservations/README.md | +| | Azure savings plan for compute | docs/operations/glossary.md | +| | Savings plans can't be canceled or exchanged | docs/billing/modern/README.md | +| | automatically applies whichever discount is better | docs/billing/modern/README.md | +| | Savings plan purchase recommendations | docs/operations/tools-scripts/get-benefitrecommendations.md | +| | Savings Plans | docs/billing/modern/README.md | +| | MCA billing hierarchy | docs/billing/modern/README.md | +| | Microsoft Customer Agreement billing hierarchy diagram | docs/billing/modern/README.md | +| | wire transfer or ACH | docs/billing/modern/README.md | +| | Management groups | docs/operations/tools-scripts/deploy-bulkalz.md | +| | Azure Resource Graph overview | docs/operations/tools-scripts/deploy-bulkalz.md | +| | limitations | docs/operations/quota-groups/README.md | +| | remove subscriptions from a quota group | docs/operations/quota-groups/README.md | +| | Add newly provisioned or recycled subscriptions | docs/operations/quota/README.md | +| | Creating or deleting a quota group | docs/operations/quota-groups/README.md | +| | Create the group | docs/operations/quota/README.md | +| | Source | docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/glossary.md, docs/operations/monitoring-alerting/README.md, docs/operations/non-compute-quotas/README.md, docs/operations/quota-groups/README.md | +| | Diagram of Management Group hierarchy with sample Quota Groups created under Management Group. | docs/operations/quota-groups/README.md | +| | quota monitoring and alerting article | docs/operations/capacity-governance/README.md, docs/operations/monitoring-alerting/README.md, docs/operations/non-compute-quotas/README.md, docs/operations/quota-groups/README.md | +| | Quota API | docs/deployment/single-tenant/README.md, docs/operations/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/quota/README.md | +| | non-adjustable | docs/operations/escalation/README.md, docs/operations/non-compute-quotas/README.md, docs/operations/support-and-reference/README.md | +| | submit a quota group limit increase request | docs/operations/quota-groups/README.md | +| | group-level limit increase requests | docs/operations/quota/README.md | +| | Source | docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/glossary.md, docs/operations/quota-groups/README.md, docs/operations/quota/README.md | +| | Quota groups are available | docs/operations/quota-groups/README.md | +| | roles for operating quota groups | docs/operations/quota-groups/README.md | +| | `Microsoft.Quota` and `Microsoft.Compute` resource providers must be registered | docs/operations/quota-groups/README.md | +| | quota groups are independent | docs/operations/capacity-governance/README.md, docs/operations/quota-groups/README.md | +| | regional quota increases | docs/operations/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/quota/README.md | +| | 250 standard storage accounts per subscription and region (increaseable to 500) | docs/operations/non-compute-quotas/README.md | +| | quota allocation snapshot | docs/operations/capacity-governance/README.md, docs/operations/quota-groups/README.md | +| | transfer | docs/operations/capacity-governance/README.md, docs/operations/quota-groups/README.md | +| | quota allocations to transfer unused cores | docs/operations/quota/README.md | +| | **Quotas** | docs/operations/quota/README.md | +| | physical datacenter zones | docs/operations/glossary.md, docs/operations/quota/README.md, docs/operations/tenant-hygiene/README.md | +| | per-account throughput and egress limits vary by SKU | docs/operations/non-compute-quotas/README.md | +| | Spot Placement Score API | docs/operations/quota/README.md | +| | validate zone alignment between producer and consumer subscriptions | docs/operations/capacity-reservations/README.md, docs/operations/quota/README.md | +| | sharing | docs/operations/capacity-reservations/README.md | +| | Source | docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/capacity-reservations/README.md | +| | capacity reservations | docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/capacity-reservations/README.md, docs/operations/escalation/README.md, docs/operations/glossary.md, docs/operations/quota/README.md | +| | reserved capacity can be combined automatically with reserved instances | docs/operations/capacity-governance/README.md | +| | adjusted by changing the capacity property | docs/operations/capacity-governance/README.md | +| | Diagram that shows capacity reservation with the third VM allocated. | docs/operations/capacity-reservations/README.md | +| | quotas per subscription and region | docs/operations/quota/README.md | +| | Azure Spot VMs | docs/operations/quota/README.md | +| | separate capacity pool | docs/operations/quota/README.md | +| | scale-unit architecture | docs/operations/capacity-governance/README.md | +| | workload supply chain guidance | docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/glossary.md | +| | Source | docs/operations/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/capacity-planning/README.md, docs/operations/glossary.md | +| | Collect telemetry for CPU, memory, storage, network throughput, and request latency | docs/operations/capacity-planning/README.md | +| | estimate resource demand by modeling expected user journeys, transaction volumes, and dependency behavior | docs/operations/capacity-planning/README.md | +| | Identify peak utilization windows, transaction rates, and concurrency | docs/operations/capacity-planning/README.md | +| | reliable scaling | docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-planning/README.md | +| | monitoring | docs/operations/capacity-governance/README.md | +| | noisy-neighbor risk | docs/deployment/multi-tenant/README.md, docs/deployment/single-tenant/README.md | +| | transactional data stores | docs/deployment/multi-tenant/README.md, docs/deployment/single-tenant/README.md | +| | tenant experience | docs/deployment/multi-tenant/README.md | +| | quota audits | docs/operations/capacity-reservations/README.md, docs/operations/monitoring-alerting/README.md, docs/operations/non-compute-quotas/README.md, docs/operations/quota/README.md | +| | FinOps Framework | docs/operations/capacity-and-quotas/README.md, docs/operations/glossary.md | +| | rate optimization capability | docs/billing/modern/README.md | +| | FinOps rate optimization | docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/glossary.md, docs/operations/monitoring-alerting/README.md | +| | FinOps Framework planning and estimating capability | docs/operations/capacity-planning/README.md | +| | FinOps Hubs | docs/billing/modern/README.md, docs/deployment/single-tenant/README.md, docs/operations/capacity-planning/README.md, docs/operations/capacity-reservations/README.md, docs/operations/glossary.md | +| | Microsoft Azure Consumption Commitment (MACC) | docs/billing/modern/README.md | +| | `Get-AzComputeResourceSku` | docs/operations/quota/README.md | +| | Azure Cost Management API | docs/operations/tools-scripts/get-benefitrecommendations.md | +| | Microsoft style guide | docs/operations/support-and-reference/citation-matrix.md | +| | region access | docs/deployment/single-tenant/README.md, docs/operations/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/escalation/README.md, docs/operations/glossary.md, docs/operations/quota-groups/README.md, docs/operations/quota/README.md, docs/operations/support-and-reference/README.md, docs/operations/tenant-hygiene/README.md | +| | zonal enablement requests | docs/deployment/single-tenant/README.md, docs/operations/README.md, docs/operations/capacity-and-quotas/README.md, docs/operations/capacity-governance/README.md, docs/operations/quota/README.md, docs/operations/support-and-reference/README.md | +| | `OverconstrainedAllocationRequest` | docs/operations/quota/README.md | diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tenant-hygiene/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tenant-hygiene/README.md new file mode 100644 index 000000000..4807b24ed --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tenant-hygiene/README.md @@ -0,0 +1,31 @@ +--- +title: Tenant & subscription hygiene +parent: Support & reference +nav_order: 2 +--- + +# Tenant & subscription hygiene + +ISVs commonly manage subscriptions across multiple tenants while centralizing billing and governance. This guide documents best practices for maintaining clean tenant relationships, recycling subscriptions, and preserving zone mappings so you aren't surprised by access gaps. + +## Align tenant and billing structures + +- Each [Microsoft Customer Agreement (MCA) billing account](https://learn.microsoft.com/en-us/azure/cost-management-billing/microsoft-customer-agreement/manage-tenants) links to a primary Microsoft Entra tenant but can associate additional tenants for billing operations. +- [Billing owners](https://learn.microsoft.com/en-us/azure/cost-management-billing/microsoft-customer-agreement/manage-tenants) can create, transfer, or link subscriptions across associated tenants without changing the resource tenant. Track which tenants are authorized for each billing profile and invoice section to avoid orphaned access. +- Invite guest users or [associate tenant relationships](https://learn.microsoft.com/en-us/azure/cost-management-billing/microsoft-customer-agreement/manage-tenants) before assigning billing roles to external teams, and ensure invitations are accepted to activate access. + +## Subscription lifecycle hygiene + +- **Onboarding:** Use the [subscription request workflow](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription-request) to provision subscriptions for other tenants while maintaining billing control. Capture required roles (Owner, Contributor, Azure subscription creator) and management group placement as part of the intake checklist. +- **Recycling vs. deletion:** When workloads retire, reclaim quota and billing ownership but keep the subscription if zone enablement or [region access](https://learn.microsoft.com/en-us/troubleshoot/azure/general/region-access-request-process) was previously granted. Deleting the subscription can force new access requests, delaying future projects. + +## Preserve zone consistency + +- [Logical-to-physical zone mappings](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) differ per subscription and are assigned at creation. Export mappings through the `List Locations` API or the `checkZonePeers` API to document how subscriptions align across tenants. +- When planning cross-tenant high availability, compare zone mappings early to avoid placing redundant components in the same physical zone. + +## Automation opportunities + +- Script [subscription request creation and acceptance](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription-request) for cross-tenant provisioning to reduce manual errors. +- Automate [zone mapping exports](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) and store results in source control for auditability. + diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/toc.yml b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/toc.yml new file mode 100644 index 000000000..f500c0b52 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/toc.yml @@ -0,0 +1,91 @@ +- name: Capacity management + href: README.md + items: + - name: Overview + href: README.md + - name: Planning and forecasting + href: capacity-planning/README.md + items: + - name: Capacity and billing operations + href: capacity-and-quotas/README.md + - name: Capacity planning + href: capacity-planning/README.md + - name: Customer isolation + href: ../deployment/README.md + items: + - name: Overview + href: ../deployment/README.md + - name: Single-tenant + href: ../deployment/single-tenant/README.md + - name: Multi-tenant + href: ../deployment/multi-tenant/README.md + - name: Workload placement + href: quota/README.md + items: + - name: Billing models + href: ../billing/README.md + items: + - name: Overview + href: ../billing/README.md + - name: Microsoft Customer Agreement + href: ../billing/modern/README.md + items: + - name: Overview + href: ../billing/modern/README.md + - name: Subscription creation (billing scope) + href: modern/README.md + - name: Enterprise Agreement + href: ../billing/legacy/README.md + items: + - name: Overview + href: ../billing/legacy/README.md + - name: Subscription creation (billing scope) + href: legacy/README.md + - name: Quota operations + href: quota/README.md + - name: Capacity reservations + href: capacity-reservations/README.md + - name: AKS capacity governance + href: aks-capacity/README.md + - name: Non-compute quotas + href: non-compute-quotas/README.md + - name: Usage and rate optimization + href: quota-groups/README.md + items: + - name: Quota groups + href: quota-groups/README.md + - name: Governance and automation + href: monitoring-alerting/README.md + items: + - name: Monitoring and alerting + href: monitoring-alerting/README.md + - name: Capacity governance + href: capacity-governance/README.md + - name: Tools and scripts + href: tools-scripts/README.md + items: + - name: Overview + href: tools-scripts/README.md + - name: Get-AzVMQuotaUsage.ps1 + href: tools-scripts/get-azvmquotausage.md + - name: Get-AzAvailabilityZoneMapping.ps1 + href: tools-scripts/get-azavailabilityzonemapping.md + - name: Show-AzVMQuotaReport.ps1 + href: tools-scripts/show-azvmquotareport.md + - name: Get-BenefitRecommendations.ps1 + href: tools-scripts/get-benefitrecommendations.md + - name: Deploy-AnomalyAlert.ps1 + href: tools-scripts/deploy-anomalyalert.md + - name: Deploy-BulkALZ.ps1 + href: tools-scripts/deploy-bulkalz.md + - name: Support and reference + href: support-and-reference/README.md + items: + - name: Overview + href: support-and-reference/README.md + - name: Support escalation + href: escalation/README.md + - name: Tenant hygiene + href: tenant-hygiene/README.md + - name: Glossary + href: glossary.md diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/README.md new file mode 100644 index 000000000..3c8de0d27 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/README.md @@ -0,0 +1,52 @@ +--- +title: Tools & scripts +parent: Operational topics +nav_order: 15 +--- + +# Tools & scripts + +Scripts that extend Azure's native capabilities for ISV capacity management. + +## Quota management + +| Script | Description | +|--------|-------------| +| [Get-AzVMQuotaUsage.ps1](get-azvmquotausage.md) | Multi-threaded quota analysis across 100+ subscriptions | +| [Get-AzAvailabilityZoneMapping.ps1](get-azavailabilityzonemapping.md) | Logical-to-physical zone mapping for cross-subscription alignment | +| [Show-AzVMQuotaReport.ps1](show-azvmquotareport.md) | Single-threaded quota reporting for smaller deployments | + +## Cost optimization + +| Script | Description | +|--------|-------------| +| [Get-BenefitRecommendations.ps1](get-benefitrecommendations.md) | Extract savings plan recommendations from Cost Management API | +| [Deploy-AnomalyAlert.ps1](deploy-anomalyalert.md) | Deploy cost anomaly alerts to individual subscriptions | +| [Deploy-BulkALZ.ps1](deploy-bulkalz.md) | Bulk deploy anomaly alerts across management groups | + +## Budget management + +| Script | Description | +|--------|-------------| +| [Deploy-Budget.ps1](deploy-budget.md) | Deploy a cost budget to a single subscription with tag-based amount configuration | +| [Deploy-BulkBudgets.ps1](deploy-bulkbudgets.md) | Bulk deploy budgets to all subscriptions in a management group | + +## Storage analysis + +| Tool | Description | +|------|-------------| +| [Serverless SQL storage audit](https://github.com/microsoft/azcapman/tree/main/scripts/serverless-sql-storage) | Azure Monitor workbook that surfaces allocated vs. used storage across Azure SQL serverless databases; identifies `DBCC SHRINKDATABASE` candidates to reclaim billing waste | + +## Advisor recommendations + +| Script | Description | +|--------|-------------| +| [Suppress-AdvisorRecommendations.ps1](suppress-advisorrecommendations.md) | Suppress specified Azure Advisor recommendation types across a management group for up to 90 days; useful when FinOps teams manage spend centrally | + +## Utilities + +| Tool | Description | +|------|-------------| +| [calculator.py](https://github.com/microsoft/azcapman/tree/main/scripts/calculator) | Python calculator using SymPy for safe evaluation of mathematical expressions from string input; designed for LLM tool use in cost and quota calculations | + +**Source**: [GitHub repository](https://github.com/microsoft/azcapman/tree/main/scripts) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-anomalyalert.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-anomalyalert.md new file mode 100644 index 000000000..7b5a20424 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-anomalyalert.md @@ -0,0 +1,245 @@ +--- +title: Deploy-AnomalyAlert.ps1 +parent: Tools & scripts +nav_order: 6 +--- + +# Deploy-AnomalyAlert.ps1 + +Deploy cost anomaly alert configuration to individual Azure subscriptions with interactive features and validation. + +## Overview + +This PowerShell script deploys the anomaly alert Bicep template to create a subscription-level scheduled action for cost anomaly monitoring. It provides interactive subscription selection, parameter validation, and deployment options suitable for individual subscription management or CI/CD integration. + +### Key capabilities + +- **Interactive subscription selection**: Choose target subscription from available list +- **Email validation**: Validates email format before deployment +- **What-if deployment**: Preview changes without actual deployment +- **Color-coded logging**: Timestamped output with visual status indicators +- **Force mode**: Skip confirmations for automation scenarios +- **Quiet mode**: Suppress verbose output for cleaner logs + +### When to use this script + +- Deploying anomaly alerts to individual subscriptions +- Testing alert configurations before bulk deployment +- CI/CD pipeline integration for specific subscriptions +- Interactive deployment with validation +- Small-scale deployments (1-10 subscriptions) + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Force -AllowClobber + +# Authenticate to Azure +Connect-AzAccount + +# Verify permissions (Contributor or Owner required) +Get-AzRoleAssignment | Where-Object { + $_.RoleDefinitionName -eq "Contributor" -or + $_.RoleDefinitionName -eq "Owner" +} + +# List available subscriptions +Get-AzSubscription | Select-Object Name, Id, State +``` + +## Parameters + +| Parameter | Type | Description | Required | +|-----------|------|-------------|----------| +| **SubscriptionId** | String | Target subscription ID (GUID format) | No (interactive) | +| **EmailRecipients** | String[] | Array of recipient email addresses | Yes | +| **NotificationEmail** | String | Primary notification email | Yes | +| **DeploymentName** | String | Custom deployment name | No (auto-generated) | +| **Location** | String | Deployment metadata location | No (West US) | +| **Force** | Switch | Skip confirmation prompts | No | +| **Quiet** | Switch | Suppress deployment progress | No | + +## Usage examples + +### Interactive subscription selection + +```powershell +# Select subscription interactively +.\Deploy-AnomalyAlert.ps1 ` + -EmailRecipients @("platform@company.com", "finops@company.com") ` + -NotificationEmail "alerts@company.com" +``` + +### Specific subscription deployment + +```powershell +# Deploy to specific subscription +.\Deploy-AnomalyAlert.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" +``` + +### What-if preview + +```powershell +# Preview deployment without making changes +.\Deploy-AnomalyAlert.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" ` + -WhatIf +``` + +### Automated deployment + +```powershell +# Skip all prompts for automation +.\Deploy-AnomalyAlert.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" ` + -Force ` + -Quiet +``` + +### Multiple recipients + +```powershell +# Send alerts to multiple email addresses +.\Deploy-AnomalyAlert.ps1 ` + -EmailRecipients @( + "platform-team@company.com", + "finance@company.com", + "cloudops@company.com" + ) ` + -NotificationEmail "azure-alerts@company.com" +``` + +## Deployment process + +1. **Subscription validation**: Verifies subscription exists and is accessible +2. **Email validation**: Checks email format for all recipients +3. **Parameter collection**: Gathers required parameters +4. **Confirmation prompt**: Shows deployment summary (unless -Force) +5. **Template deployment**: Deploys anomaly-alert.bicep template +6. **Status reporting**: Shows success/failure with deployment ID + +## What gets deployed + +The script deploys: +- **Cost Management scheduled action** named "AnomalyAlert" +- **Anomaly detection** at subscription level +- **Email notifications** to specified recipients + +This uses the Azure public Bicep registry module: +``` +br/public:cost/subscription-scheduled-action:1.0.2 +``` + +## Error handling + +The script includes comprehensive error handling: +- Validates subscription ID format (GUID) +- Validates email address formats +- Checks Azure authentication status +- Verifies subscription access permissions +- Handles deployment failures gracefully + +## Troubleshooting + +### Authentication issues + +```powershell +# Clear and re-authenticate +Clear-AzContext -Force +Connect-AzAccount + +# Verify current context +Get-AzContext | Select-Object Account, Subscription, Tenant +``` + +### Permission errors + +```powershell +# Check role assignments +Get-AzRoleAssignment -Scope "/subscriptions/YOUR-SUB-ID" | + Select-Object DisplayName, RoleDefinitionName + +# Minimum required: Contributor or Owner role +``` + +### Subscription not found + +```powershell +# List all accessible subscriptions +Get-AzSubscription | Format-Table Name, Id, State + +# Ensure subscription is enabled +Get-AzSubscription -SubscriptionId "YOUR-SUB-ID" | + Select-Object State +``` + +### Deployment failures + +```powershell +# Check deployment history +Get-AzSubscriptionDeployment -Name "YOUR-DEPLOYMENT-NAME" | + Select-Object ProvisioningState, Timestamp + +# Get detailed error +$deployment = Get-AzSubscriptionDeploymentOperation ` + -DeploymentName "YOUR-DEPLOYMENT-NAME" +$deployment.Properties.StatusMessage +``` + +## CI/CD integration + +### Azure DevOps pipeline + +```yaml +- task: AzurePowerShell@5 + displayName: 'Deploy Anomaly Alert' + inputs: + azureSubscription: 'ServiceConnection' + ScriptType: 'FilePath' + ScriptPath: '$(System.DefaultWorkingDirectory)/Deploy-AnomalyAlert.ps1' + ScriptArguments: > + -SubscriptionId $(SubscriptionId) + -EmailRecipients @("$(EmailRecipients)") + -NotificationEmail "$(NotificationEmail)" + -Force + -Quiet + azurePowerShellVersion: 'LatestVersion' +``` + +### GitHub Actions + +```yaml +- name: Deploy Anomaly Alert + uses: azure/powershell@v1 + with: + inlineScript: | + .\Deploy-AnomalyAlert.ps1 ` + -SubscriptionId "${{ secrets.AZURE_SUBSCRIPTION_ID }}" ` + -EmailRecipients @("${{ vars.ALERT_RECIPIENTS }}") ` + -NotificationEmail "${{ vars.NOTIFICATION_EMAIL }}" ` + -Force ` + -Quiet + azPSVersion: "latest" +``` + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/anomaly-alerts/Deploy-AnomalyAlert.ps1) + +## Related scripts + +- [Deploy-BulkALZ.ps1](deploy-bulkalz.md) - Enterprise bulk deployment +- [anomaly-alert.bicep](https://github.com/microsoft/azcapman/blob/main/scripts/anomaly-alerts/anomaly-alert.bicep) - Bicep template + +## Related documentation + +- [Cost anomaly detection](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/anomaly-detection) +- [Cost Management scheduled actions](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/save-share-views) \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-budget.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-budget.md new file mode 100644 index 000000000..8ff3ab06e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-budget.md @@ -0,0 +1,178 @@ +--- +title: Deploy-Budget.ps1 +parent: Tools & scripts +nav_order: 8 +--- + +# Deploy-Budget.ps1 + +Deploy a cost budget to a single Azure subscription with tag-based amount configuration and configurable notification thresholds. + +## Overview + +This PowerShell script deploys a `Microsoft.Consumption/budgets` resource to an Azure subscription. Budget amounts can be set via explicit parameter or read from a `BudgetAmount` subscription tag, letting different subscriptions carry different spending limits without modifying the script. + +### Key capabilities + +- **Tag-based amounts**: Reads `BudgetAmount` tag from the subscription to set per-subscription limits +- **Interactive selection**: Prompts for subscription when no ID is provided +- **Threshold configuration**: Configures actual and forecasted notification thresholds +- **What-if mode**: Preview deployment without making changes +- **Force mode**: Skip confirmation for automation scenarios + +### When to use this script + +- Deploying a budget to a single subscription +- Testing budget configuration before bulk deployment +- Onboarding a new subscription to cost governance +- CI/CD pipeline integration for subscription-level budgets + +### Budget amount priority + +The script resolves the budget amount in this order: + +1. **`-Amount` parameter** — explicit value takes precedence +2. **`BudgetAmount` subscription tag** — tag-based per-subscription configuration +3. **Default** — falls back to $10/month + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Repository PSGallery -Force + +# Authenticate to Azure +Connect-AzAccount + +# Verify subscription access +Get-AzSubscription | Select-Object Name, Id, State +``` + +## Parameters + +| Parameter | Type | Description | Default | +|-----------|------|-------------|---------| +| **SubscriptionId** | String | Target subscription GUID | Interactive selection | +| **ContactEmails** | String[] | Email addresses for notifications | Required | +| **Amount** | Decimal | Budget amount (overrides tag) | Tag or $10 | +| **BudgetName** | String | Name of the budget resource | `SubscriptionBudget` | +| **TimeGrain** | String | Reset period: Monthly, Quarterly, or Annually | Monthly | +| **StartDate** | String | Budget start date (YYYY-MM-DD) | 1st of next month | +| **EndDate** | String | Budget end date (YYYY-MM-DD) | 1 year from start | +| **ContactRoles** | String[] | Azure roles to notify | Owner, Contributor | +| **FirstThreshold** | Int | First notification threshold % | 50 | +| **SecondThreshold** | Int | Second notification threshold % | 75 | +| **ThirdThreshold** | Int | Third notification threshold % | 90 | +| **ForecastedThreshold** | Int | Forecasted cost threshold % | 100 | +| **Force** | Switch | Skip confirmation prompt | False | +| **Quiet** | Switch | Suppress verbose output | False | +| **WhatIf** | Switch | Preview without deploying | False | + +## Usage examples + +### Interactive subscription selection + +```powershell +.\Deploy-Budget.ps1 -ContactEmails "admin@company.com" +``` + +### Specific subscription + +```powershell +.\Deploy-Budget.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -ContactEmails "admin@company.com" +``` + +### Override budget amount + +```powershell +.\Deploy-Budget.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -ContactEmails "finops@company.com" ` + -Amount 5000 +``` + +### What-if preview + +```powershell +.\Deploy-Budget.ps1 ` + -ContactEmails "admin@company.com" ` + -WhatIf +``` + +### Automated deployment (no prompts) + +```powershell +.\Deploy-Budget.ps1 ` + -SubscriptionId "12345678-1234-1234-1234-123456789012" ` + -ContactEmails "admin@company.com" ` + -Force -Quiet +``` + +## Setting the BudgetAmount tag + +Set the `BudgetAmount` tag on a subscription to control its per-subscription limit without changing script parameters: + +```powershell +# PowerShell +Update-AzTag -ResourceId "/subscriptions/" ` + -Tag @{BudgetAmount = "500"} ` + -Operation Merge +``` + +```bash +# Azure CLI +az tag update \ + --resource-id "/subscriptions/" \ + --operation merge \ + --tags BudgetAmount=500 +``` + +## Notification thresholds + +By default, notifications are sent at these percentages of the configured budget amount: + +| Threshold | Type | Default | +|-----------|------|---------| +| First | Actual | 50% | +| Second | Actual | 75% | +| Third | Actual | 90% | +| Forecasted | Forecasted | 100% | + +All four thresholds are configurable via parameters. Actual thresholds trigger when actual spend crosses the percentage; the forecasted threshold triggers when projected spend is expected to cross it. + +## Troubleshooting + +### Subscription not found + +```powershell +# List accessible subscriptions +Get-AzSubscription | Where-Object State -eq 'Enabled' | Select-Object Name, Id +``` + +### Budget already exists + +The script uses `New-AzConsumptionBudget` with upsert behavior. Re-running against the same subscription updates the existing budget rather than creating a duplicate. + +### Authentication errors + +```powershell +# Re-authenticate +Clear-AzContext -Force +Connect-AzAccount -Tenant 'your-tenant-id' +``` + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/budgets/Deploy-Budget.ps1) + +## Related scripts + +- [Deploy-BulkBudgets.ps1](deploy-bulkbudgets.md) - Bulk budget deployment across a management group +- [Deploy-AnomalyAlert.ps1](deploy-anomalyalert.md) - Deploy anomaly alerts to individual subscriptions + +## Related documentation + +- [Azure budgets overview](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/tutorial-acm-create-budgets) +- [Microsoft.Consumption/budgets API](https://learn.microsoft.com/en-us/azure/templates/microsoft.consumption/budgets) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkalz.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkalz.md new file mode 100644 index 000000000..8b02377e9 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkalz.md @@ -0,0 +1,265 @@ +--- +title: Deploy-BulkALZ.ps1 +parent: Tools & scripts +nav_order: 7 +--- + +# Deploy-BulkALZ.ps1 + +Enterprise-scale deployment of anomaly alerts to all subscriptions in a management group with intelligent pagination support. + +## Overview + +This PowerShell script deploys cost anomaly alerts across entire Azure Landing Zone management groups, handling hundreds or thousands of subscriptions efficiently. It uses Azure Resource Graph for subscription discovery and implements intelligent pagination to work within Azure's query limits. + +### Key capabilities + +- **Management group targeting**: Deploy to entire hierarchy at once +- **Azure Resource Graph integration**: Efficient subscription discovery +- **Intelligent pagination**: Automatically handles Azure's 1,000 result limit +- **Progressive discovery**: Real-time progress reporting +- **Performance optimization**: Quiet mode for faster bulk operations +- **Safety confirmations**: Prevents accidental enterprise-wide changes + +### When to use this script + +- Enterprise-scale anomaly alert deployment +- Management group-wide rollouts +- Automated governance implementation +- Large estates with 100+ subscriptions +- Azure Landing Zone (ALZ) implementations + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Force -AllowClobber + +# Install Azure Resource Graph module (required) +Install-Module -Name Az.ResourceGraph -Force -AllowClobber + +# Authenticate to Azure +Connect-AzAccount -Tenant "YOUR-TENANT-ID" + +# Verify management group access +Get-AzManagementGroup | Select-Object Name, DisplayName + +# Verify Resource Graph access +Search-AzGraph -Query "resourcecontainers | where type == 'microsoft.resources/subscriptions' | limit 1" +``` + +## Parameters + +| Parameter | Type | Description | Required | +|-----------|------|-------------|----------| +| **TenantId** | String | Azure tenant ID (GUID) | Yes | +| **ManagementGroup** | String | Target management group name | Yes | +| **EmailRecipients** | String[] | Alert recipient email addresses | Yes | +| **NotificationEmail** | String | Primary notification email | Yes | +| **WhatIf** | Switch | Preview mode without deployment | No | +| **Quiet** | Switch | Suppress Azure warnings | No | + +## Usage examples + +### Basic deployment to management group + +```powershell +.\Deploy-BulkALZ.ps1 ` + -TenantId "12345678-1234-1234-1234-123456789012" ` + -ManagementGroup "ALZ" ` + -EmailRecipients @("platform@company.com", "finops@company.com") ` + -NotificationEmail "alerts@company.com" +``` + +### Preview deployment (what-if) + +```powershell +# See what would be deployed without making changes +.\Deploy-BulkALZ.ps1 ` + -TenantId "12345678-1234-1234-1234-123456789012" ` + -ManagementGroup "Production" ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" ` + -WhatIf +``` + +### Quiet mode for automation + +```powershell +# Suppress warnings for cleaner output +.\Deploy-BulkALZ.ps1 ` + -TenantId "12345678-1234-1234-1234-123456789012" ` + -ManagementGroup "ALZ" ` + -EmailRecipients @("admin@company.com") ` + -NotificationEmail "alerts@company.com" ` + -Quiet +``` + +### Deploy to specific environment + +```powershell +# Target specific management group like Dev, Test, or Prod +.\Deploy-BulkALZ.ps1 ` + -TenantId "12345678-1234-1234-1234-123456789012" ` + -ManagementGroup "Development" ` + -EmailRecipients @("dev-team@company.com") ` + -NotificationEmail "dev-alerts@company.com" +``` + +## Pagination system + +The script implements intelligent pagination to handle Azure Resource Graph's 1,000 result limit: + +1. **Automatic page detection**: Determines if pagination is needed +2. **Progressive queries**: Fetches subscriptions in 1,000-item batches +3. **Skip token handling**: Uses Azure's continuation tokens +4. **Real-time progress**: Reports each page as it's processed + +### How pagination works + +```powershell +# Internal process (handled automatically): +# Page 1: Subscriptions 1-1000 +# Page 2: Subscriptions 1001-2000 +# Page 3: Subscriptions 2001-3000 +# Continues until all subscriptions are discovered +``` + +## Deployment process + +1. **Tenant connection**: Authenticates to specified tenant +2. **Subscription discovery**: Queries Resource Graph for all subscriptions in management group +3. **Pagination handling**: Processes results in batches if needed +4. **Confirmation prompt**: Shows total count and asks for confirmation +5. **Sequential deployment**: Deploys to each subscription with progress tracking +6. **Summary report**: Shows success/failure counts + +## Performance considerations + +- **Query optimization**: Uses Resource Graph for fast discovery +- **Batch size**: Fixed at 1,000 subscriptions per query (Azure limit) +- **Sequential deployment**: Deploys one subscription at a time to avoid throttling +- **Warning suppression**: Use `-Quiet` to reduce output overhead + +### Estimated deployment times + +| Subscriptions | Estimated Time | +|---------------|----------------| +| 10 | ~1 minute | +| 100 | ~10 minutes | +| 1,000 | ~100 minutes | +| 5,000 | ~8 hours | + +## Error handling + +The script includes explicit error handling: +- Validates tenant ID format +- Verifies management group exists +- Handles pagination failures +- Reports deployment failures per subscription +- Continues deployment despite individual failures + +## Troubleshooting + +### Management group not found + +```powershell +# List available management groups +Get-AzManagementGroup | Format-Table Name, DisplayName + +# Verify exact name (case-sensitive) +Get-AzManagementGroup -GroupName "YOUR-MG-NAME" +``` + +### Resource Graph errors + +```powershell +# Test Resource Graph access +Search-AzGraph -Query "resourcecontainers | where type == 'microsoft.resources/subscriptions' | limit 1" + +# Check module installation +Get-Module -ListAvailable Az.ResourceGraph +``` + +### Authentication issues + +```powershell +# Clear all contexts +Clear-AzContext -Force + +# Connect to specific tenant +Connect-AzAccount -Tenant "YOUR-TENANT-ID" + +# Verify tenant context +Get-AzContext | Select-Object Tenant +``` + +### No subscriptions found + +```powershell +# Test query directly +$query = "resourcecontainers | where type == 'microsoft.resources/subscriptions'" +$mgScope = "/providers/Microsoft.Management/managementGroups/YOUR-MG" +Search-AzGraph -Query $query -ManagementGroup "YOUR-MG" +``` + +## Security considerations + +- **Tenant isolation**: Explicitly connects to specified tenant +- **Confirmation prompts**: Requires confirmation before bulk changes +- **What-if mode**: Always test with `-WhatIf` first +- **Audit trail**: Each deployment creates audit log entries + +## Integration patterns + +### Scheduled deployment + +```powershell +# PowerShell scheduled task +$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 2am +$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument @" + -File C:\Scripts\Deploy-BulkALZ.ps1 ` + -TenantId 'TENANT-ID' ` + -ManagementGroup 'ALZ' ` + -EmailRecipients @('admin@company.com') ` + -NotificationEmail 'alerts@company.com' ` + -Quiet +"@ +Register-ScheduledTask -TaskName "WeeklyAnomalyAlerts" -Trigger $trigger -Action $action +``` + +### Azure Automation script + +```powershell +# Runbook script +param( + [Parameter(Mandatory=$true)] + [string]$ManagementGroup +) + +# Use managed identity for authentication +Connect-AzAccount -Identity + +# Deploy alerts +.\Deploy-BulkALZ.ps1 ` + -TenantId $env:AZURE_TENANT_ID ` + -ManagementGroup $ManagementGroup ` + -EmailRecipients @($env:ALERT_RECIPIENTS -split ',') ` + -NotificationEmail $env:NOTIFICATION_EMAIL ` + -Quiet +``` + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/anomaly-alerts/Deploy-BulkALZ.ps1) + +## Related scripts + +- [Deploy-AnomalyAlert.ps1](deploy-anomalyalert.md) - Individual subscription deployment +- [anomaly-alert.bicep](https://github.com/microsoft/azcapman/blob/main/scripts/anomaly-alerts/anomaly-alert.bicep) - Bicep template + +## Related documentation + +- [Azure Resource Graph overview](https://learn.microsoft.com/en-us/azure/governance/resource-graph/overview) +- [Management groups](https://learn.microsoft.com/en-us/azure/governance/management-groups/overview) +- [Cost anomaly detection](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/anomaly-detection) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkbudgets.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkbudgets.md new file mode 100644 index 000000000..88a4bb7ef --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/deploy-bulkbudgets.md @@ -0,0 +1,187 @@ +--- +title: Deploy-BulkBudgets.ps1 +parent: Tools & scripts +nav_order: 9 +--- + +# Deploy-BulkBudgets.ps1 + +Deploy cost budgets to all subscriptions in a management group with per-subscription tag-based amount configuration. + +## Overview + +This PowerShell script uses Azure Resource Graph to discover all subscriptions in a management group, then deploys a `Microsoft.Consumption/budgets` resource to each. Each subscription can carry a different budget amount via its `BudgetAmount` tag, so a single bulk run respects per-subscription spending limits without manual intervention. + +### Key capabilities + +- **Management group targeting**: Discover and deploy to all subscriptions in a hierarchy +- **Tag-based amounts**: Reads `BudgetAmount` tag from each subscription for per-subscription limits +- **What-if mode**: Preview deployment scope without making changes +- **Force mode**: Skip confirmation for automation and CI/CD pipelines +- **Quiet mode**: Suppress output for cleaner pipeline logs + +### When to use this script + +- Applying cost governance across a management group at once +- Onboarding a new management group to budget monitoring +- Refreshing budgets after fiscal year changes +- Environments with 10+ subscriptions requiring consistent budget coverage + +## Prerequisites + +```powershell +# Install Azure PowerShell modules +Install-Module -Name Az -Force -AllowClobber +Install-Module -Name Az.ResourceGraph -Force -AllowClobber + +# Authenticate to Azure +Connect-AzAccount + +# Verify management group access +Get-AzManagementGroup | Select-Object Name, DisplayName +``` + +## Parameters + +| Parameter | Type | Description | Default | +|-----------|------|-------------|---------| +| **ManagementGroup** | String | Management group to query for subscriptions | Required | +| **ContactEmails** | String[] | Email addresses for notifications | Required | +| **Amount** | Decimal | Budget amount (overrides all subscription tags) | Per-sub tag or $10 | +| **BudgetName** | String | Name of the budget resource | `SubscriptionBudget` | +| **TimeGrain** | String | Reset period: Monthly, Quarterly, or Annually | Monthly | +| **StartDate** | String | Budget start date (YYYY-MM-DD) | 1st of next month | +| **EndDate** | String | Budget end date (YYYY-MM-DD) | 1 year from start | +| **ContactRoles** | String[] | Azure roles to notify | Owner, Contributor | +| **FirstThreshold** | Int | First notification threshold % | 50 | +| **SecondThreshold** | Int | Second notification threshold % | 75 | +| **ThirdThreshold** | Int | Third notification threshold % | 90 | +| **ForecastedThreshold** | Int | Forecasted cost threshold % | 100 | +| **Force** | Switch | Skip confirmation prompt | False | +| **Quiet** | Switch | Suppress verbose output | False | +| **WhatIf** | Switch | Preview without deploying | False | + +## Usage examples + +### Deploy to all subscriptions in a management group + +```powershell +.\Deploy-BulkBudgets.ps1 ` + -ManagementGroup "ALZ" ` + -ContactEmails "admin@company.com" +``` + +### Override amount for all subscriptions + +```powershell +.\Deploy-BulkBudgets.ps1 ` + -ManagementGroup "ALZ" ` + -ContactEmails "admin@company.com" ` + -Amount 5000 +``` + +### What-if preview + +```powershell +.\Deploy-BulkBudgets.ps1 ` + -ManagementGroup "Production" ` + -ContactEmails "finops@company.com" ` + -WhatIf +``` + +### Automated deployment + +```powershell +.\Deploy-BulkBudgets.ps1 ` + -ManagementGroup "ALZ" ` + -ContactEmails "finops@company.com","alerts@company.com" ` + -Force -Quiet +``` + +### Production management group with custom thresholds + +```powershell +.\Deploy-BulkBudgets.ps1 ` + -ManagementGroup "Production" ` + -ContactEmails "finops@company.com","alerts@company.com" ` + -FirstThreshold 70 ` + -SecondThreshold 85 ` + -ThirdThreshold 95 ` + -ForecastedThreshold 100 +``` + +## Tag-based amount configuration + +Set the `BudgetAmount` tag on individual subscriptions before running bulk deployment to control per-subscription limits: + +```powershell +# Tag a dev subscription with a low budget +Update-AzTag ` + -ResourceId "/subscriptions/" ` + -Tag @{BudgetAmount = "50"} ` + -Operation Merge + +# Tag a production subscription with a higher budget +Update-AzTag ` + -ResourceId "/subscriptions/" ` + -Tag @{BudgetAmount = "10000"} ` + -Operation Merge +``` + +When `-Amount` is provided at the command line, it overrides all subscription tags. + +## Deployment process + +1. **Management group query**: Uses Resource Graph to discover all enabled subscriptions +2. **Confirmation prompt**: Shows subscription count and asks for confirmation (unless `-Force`) +3. **Sequential deployment**: Deploys to each subscription with progress output +4. **Summary report**: Shows success and failure counts at completion + +## Troubleshooting + +### Management group not found + +```powershell +# List available management groups +Get-AzManagementGroup | Format-Table Name, DisplayName + +# Verify exact name (case-sensitive) +Get-AzManagementGroup -GroupName "YOUR-MG-NAME" +``` + +### Resource Graph module missing + +```powershell +Install-Module -Name Az.ResourceGraph -Force -AllowClobber +``` + +### No subscriptions found + +```powershell +# Test the Resource Graph query directly +Search-AzGraph ` + -Query "resourcecontainers | where type == 'microsoft.resources/subscriptions'" ` + -ManagementGroup "YOUR-MG" +``` + +### Authentication errors + +```powershell +Clear-AzContext -Force +Connect-AzAccount -Tenant 'your-tenant-id' +``` + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/budgets/Deploy-BulkBudgets.ps1) + +## Related scripts + +- [Deploy-Budget.ps1](deploy-budget.md) - Single subscription budget deployment +- [Deploy-BulkALZ.ps1](deploy-bulkalz.md) - Bulk anomaly alert deployment pattern + +## Related documentation + +- [Azure budgets overview](https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/tutorial-acm-create-budgets) +- [Azure Resource Graph overview](https://learn.microsoft.com/en-us/azure/governance/resource-graph/overview) +- [Microsoft.Consumption/budgets API](https://learn.microsoft.com/en-us/azure/templates/microsoft.consumption/budgets) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azavailabilityzonemapping.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azavailabilityzonemapping.md new file mode 100644 index 000000000..fddc0be82 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azavailabilityzonemapping.md @@ -0,0 +1,209 @@ +--- +title: Get-AzAvailabilityZoneMapping.ps1 +parent: Tools & scripts +nav_order: 2 +--- + +# Get-AzAvailabilityZoneMapping.ps1 + +Maps logical availability zones to physical datacenters across Azure subscriptions to ensure proper fault domain alignment. + +## Overview + +Azure randomizes the mapping between logical zones (1, 2, 3) and physical datacenters for each subscription. This means logical zone 1 in subscription A might map to a completely different physical datacenter than zone 1 in subscription B. This script reveals these mappings, which is critical for multi-subscription architectures requiring true zone alignment. + +### Key capabilities + +- **Physical zone discovery**: Reveals actual physical datacenter identifiers +- **Cross-subscription mapping**: Shows how zones align across multiple subscriptions +- **Compliance validation**: Ensures deployments meet data residency requirements +- **Architecture planning**: Essential data for multi-subscription deployment patterns + +### When to use this script + +- Planning multi-subscription deployments with zone redundancy +- Verifying zone alignment before deployment stamp creation +- Troubleshooting zone-related deployment failures +- Compliance audits requiring physical datacenter documentation +- Capacity reservation planning across subscriptions + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Repository PSGallery -Force + +# Authenticate to Azure +Connect-AzAccount + +# Verify subscription access +Get-AzSubscription | Select-Object Name, Id, State + +# Ensure you have Reader access to target subscriptions +Get-AzRoleAssignment | Where-Object {$_.RoleDefinitionName -like "*Reader*"} +``` + +## Parameters + +| Parameter | Type | Description | Default | +|-----------|------|-------------|---------| +| **SubscriptionIds** | String[] | Array of subscription IDs to analyze | All accessible subscriptions | +| **OutputFile** | String | CSV output filename | ZonePeers.csv | + +## Usage examples + +### Basic usage - all subscriptions + +```powershell +.\Get-AzAvailabilityZoneMapping.ps1 +``` + +### Specific subscriptions for deployment planning + +```powershell +.\Get-AzAvailabilityZoneMapping.ps1 ` + -SubscriptionIds @('prod-sub-guid', 'dr-sub-guid') ` + -OutputFile "ProdDRZoneAlignment.csv" +``` + +### Multi-subscription stamp validation + +```powershell +# Get all production subscription IDs +$prodSubs = Get-AzSubscription | Where-Object Name -like "Prod-*" | Select-Object -ExpandProperty Id + +# Analyze zone mappings +.\Get-AzAvailabilityZoneMapping.ps1 ` + -SubscriptionIds $prodSubs ` + -OutputFile "ProductionZoneMappings_$(Get-Date -Format 'yyyyMMdd').csv" +``` + +## Sample output + +Running the script across multiple subscriptions produces output like this: + +```csv +TenantId,SubscriptionId,SubscriptionName,Location,LogicalZone,PhysicalZone,PhysicalZoneName +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Production-Primary,eastus,1,2,eastus-az2 +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Production-Primary,eastus,2,3,eastus-az3 +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Production-Primary,eastus,3,1,eastus-az1 +12345678-1234-1234-1234-123456789012,efgh5678-90ab-cdef-1234-567890abcdef,Production-Secondary,eastus,1,3,eastus-az3 +12345678-1234-1234-1234-123456789012,efgh5678-90ab-cdef-1234-567890abcdef,Production-Secondary,eastus,2,1,eastus-az1 +12345678-1234-1234-1234-123456789012,efgh5678-90ab-cdef-1234-567890abcdef,Production-Secondary,eastus,3,2,eastus-az2 +12345678-1234-1234-1234-123456789012,ijkl9012-3456-7890-abcd-ef1234567890,Development,eastus,1,1,eastus-az1 +12345678-1234-1234-1234-123456789012,ijkl9012-3456-7890-abcd-ef1234567890,Development,eastus,2,2,eastus-az2 +12345678-1234-1234-1234-123456789012,ijkl9012-3456-7890-abcd-ef1234567890,Development,eastus,3,3,eastus-az3 +``` + +### Understanding the output + +- **TenantId**: Microsoft Entra tenant identifier +- **SubscriptionId**: Unique subscription identifier +- **SubscriptionName**: Friendly subscription name +- **Location**: Azure region +- **LogicalZone**: The zone number applications see (1, 2, 3) +- **PhysicalZone**: Actual physical datacenter identifier +- **PhysicalZoneName**: Full physical datacenter name + +### Critical findings from sample + +In this example: +- **Production-Primary**: Logical zone 1 → Physical zone 2 +- **Production-Secondary**: Logical zone 1 → Physical zone 3 +- **Development**: Logical zone 1 → Physical zone 1 + +This means deploying to "zone 1" across these subscriptions would actually spread resources across three different physical datacenters, defeating zone alignment goals. + +## Real-world implications + +### Incorrect assumption +```plaintext +Deploy to Zone 1 in all subscriptions = Same physical datacenter ❌ +``` + +### Reality revealed by script +```plaintext +Subscription A Zone 1 = Physical Datacenter 2 +Subscription B Zone 1 = Physical Datacenter 3 +Subscription C Zone 1 = Physical Datacenter 1 +Result: No actual zone alignment! ⚠️ +``` + +### Correct approach +```plaintext +Use script output to map deployments: +- Subscription A: Deploy to Zone 3 (Physical DC 1) +- Subscription B: Deploy to Zone 2 (Physical DC 1) +- Subscription C: Deploy to Zone 1 (Physical DC 1) +Result: True zone alignment ✅ +``` + +## Troubleshooting + +### No zone data returned + +```powershell +# Verify the region supports availability zones +Get-AzLocation | Where-Object Location -eq 'eastus' | Select-Object -ExpandProperty Zones + +# Check if subscription has zone access +Get-AzComputeResourceSku -Location 'eastus' | + Where-Object {$_.LocationInfo.Zones.Count -gt 0} | + Select-Object -First 5 +``` + +### Access denied errors + +```powershell +# Verify role assignments +Get-AzRoleAssignment -SignInName (Get-AzContext).Account.Id + +# Switch to correct subscription context +Set-AzContext -SubscriptionId 'target-subscription-id' +``` + +### Performance optimization + +For large numbers of subscriptions: +```powershell +# Process in batches +$allSubs = Get-AzSubscription | Select-Object -ExpandProperty Id +$batchSize = 10 + +for ($i = 0; $i -lt $allSubs.Count; $i += $batchSize) { + $batch = $allSubs[$i..([Math]::Min($i + $batchSize - 1, $allSubs.Count - 1))] + .\Get-AzAvailabilityZoneMapping.ps1 ` + -SubscriptionIds $batch ` + -OutputFile "ZoneMapping_Batch_$($i / $batchSize + 1).csv" +} +``` + +## Integration patterns + +### Excel analysis +1. Import CSV into Excel +2. Create pivot table by Physical Zone +3. Filter by Location +4. Identify subscription groups with matching physical zones + +### Automated deployment alignment +```powershell +# Load zone mappings +$zoneMappings = Import-Csv "ZonePeers.csv" + +# Find subscriptions where logical zone 1 maps to physical zone 1 +$alignedSubs = $zoneMappings | + Where-Object {$_.LogicalZone -eq 1 -and $_.PhysicalZone -eq 1} | + Select-Object -Unique SubscriptionId, SubscriptionName + +# Deploy to these subscriptions in zone 1 for alignment +``` + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/quota/Get-AzAvailabilityZoneMapping.ps1) + +## Related scripts + +- [Get-AzVMQuotaUsage.ps1](get-azvmquotausage.md) - Comprehensive quota analysis with zone restrictions +- [Show-AzVMQuotaReport.ps1](show-azvmquotareport.md) - Single-threaded quota reporting \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azvmquotausage.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azvmquotausage.md new file mode 100644 index 000000000..7da986e09 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-azvmquotausage.md @@ -0,0 +1,177 @@ +--- +title: Get-AzVMQuotaUsage.ps1 +parent: Tools & scripts +nav_order: 1 +--- + +# Get-AzVMQuotaUsage.ps1 + +Multi-threaded Azure VM quota analysis script that provides comprehensive quota visibility across your subscription estate. + +## Overview + +This PowerShell script analyzes Azure VM quota usage and availability zone restrictions across multiple subscriptions and regions in parallel. It addresses the challenge of understanding quota consumption at scale when managing hundreds of subscriptions without Quota Groups. + +### Key capabilities + +- **Parallel processing**: Multi-threaded execution across subscriptions for faster analysis +- **Zone restriction detection**: Identifies which availability zones are restricted for specific VM SKUs +- **Physical zone mapping**: Maps logical zones to physical datacenters for cross-subscription alignment +- **Comprehensive reporting**: Outputs detailed CSV with quota usage, limits, and zone availability + +### When to use this script + +- Quarterly capacity planning reviews +- Pre-deployment quota validation +- Cross-subscription deployment planning +- Zone alignment verification for multi-subscription architectures +- Identifying restricted SKUs and zones before scaling + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Repository PSGallery -Force + +# PowerShell 7+ recommended for multi-threading +$PSVersionTable.PSVersion # Should be 7.0 or higher + +# Authenticate to Azure +Connect-AzAccount + +# Verify you have Reader access to target subscriptions +Get-AzSubscription | Select-Object Name, Id, State +``` + +## Parameters + +| Parameter | Type | Description | Default | +|-----------|------|-------------|---------| +| **SKUs** | String[] | Array of VM SKU names to analyze | Downloads all SKUs | +| **Locations** | String[] | Array of Azure regions to query | All regions | +| **SubscriptionIds** | String[] | Array of subscription IDs to analyze | All accessible subscriptions | +| **Threads** | Int | Number of concurrent threads | 2 (0 for auto-detect) | +| **UsePhysicalZones** | Switch | Normalize output to physical zones | False | +| **OutputFile** | String | CSV output filename | VMQuotaUsage.csv | +| **MeterDataUri** | String | URL for VM SKU metadata | Azure public data | + +## Usage examples + +### Basic usage - analyze specific SKUs + +```powershell +.\Get-AzVMQuotaUsage.ps1 -SKUs @('Standard_D4s_v5', 'Standard_E4s_v5') -Locations @('eastus', 'westus2') +``` + +### Multi-threaded analysis across all subscriptions + +```powershell +.\Get-AzVMQuotaUsage.ps1 -SKUs @('Standard_D4s_v5', 'Standard_E4s_v5') ` + -Locations @('eastus', 'westus2', 'northeurope') ` + -Threads 4 ` + -OutputFile "QuotaAnalysis_$(Get-Date -Format 'yyyyMMdd').csv" +``` + +### Physical zone mapping for cross-subscription deployment + +```powershell +.\Get-AzVMQuotaUsage.ps1 -SKUs @('Standard_D4s_v5') ` + -Locations @('eastus') ` + -SubscriptionIds @('sub1-guid', 'sub2-guid') ` + -UsePhysicalZones ` + -OutputFile "CrossSubZoneAlignment.csv" +``` + +### Full estate analysis with auto-threading + +```powershell +.\Get-AzVMQuotaUsage.ps1 -Threads 0 -OutputFile "FullEstateQuota.csv" +``` + +## Sample output + +Running the script in a production environment produces output like this: + +```csv +TenantId,SubscriptionId,SubscriptionName,Location,Family,Size,RegionRestricted,ZonesPresent,ZonesRestricted,CoresUsed,CoresTotal +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Production-East,eastus,standardDSv5Family,Standard_D4s_v5,False,"1,2,3",,24,350 +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Production-East,eastus,standardESv5Family,Standard_E4s_v5,False,"1,2,3",,16,350 +12345678-1234-1234-1234-123456789012,efgh5678-90ab-cdef-1234-567890abcdef,Production-West,westus2,standardDSv5Family,Standard_D4s_v5,False,"1,2,3",,48,350 +12345678-1234-1234-1234-123456789012,efgh5678-90ab-cdef-1234-567890abcdef,Production-West,westus2,standardESv5Family,Standard_E4s_v5,False,"1,2,3",,0,350 +12345678-1234-1234-1234-123456789012,ijkl9012-3456-7890-abcd-ef1234567890,Development,northeurope,standardDSv5Family,Standard_D4s_v5,True,"1,2,3","2,3",0,100 +``` + +### Understanding the output + +- **TenantId**: Your Microsoft Entra tenant identifier +- **SubscriptionId**: Unique subscription identifier +- **SubscriptionName**: Friendly subscription name +- **Location**: Azure region +- **Family**: VM family for quota calculation +- **Size**: Specific VM SKU +- **RegionRestricted**: Whether the SKU has regional restrictions (True/False) +- **ZonesPresent**: Available availability zones (comma-separated) +- **ZonesRestricted**: Restricted zones requiring enablement request (comma-separated) +- **CoresUsed**: Current vCPU consumption +- **CoresTotal**: Total vCPU quota limit + +## Troubleshooting + +### Common issues + +**PowerShell version error** +```powershell +# Check version +$PSVersionTable.PSVersion + +# Install PowerShell 7 if needed +winget install Microsoft.PowerShell +``` + +**Authentication failures** +```powershell +# Clear cached credentials +Clear-AzContext -Force + +# Re-authenticate +Connect-AzAccount -Tenant 'your-tenant-id' +``` + +**Throttling with high thread count** +```powershell +# Reduce threads if seeing 429 errors +.\Get-AzVMQuotaUsage.ps1 -Threads 2 # Lower thread count +``` + +**No data returned** +```powershell +# Verify subscription access +Get-AzSubscription | Where-Object State -eq 'Enabled' + +# Check region availability +Get-AzLocation | Select-Object Location, DisplayName +``` + +## Performance considerations + +- **Thread optimization**: Start with 2-4 threads, increase gradually +- **Regional filtering**: Specify `-Locations` to reduce API calls +- **SKU filtering**: Target specific SKUs rather than analyzing all +- **Output size**: Large estates may produce CSV files over 10MB + +## Integration with other tools + +This script output integrates with: +- Excel pivot tables for quota analysis +- Power BI for visualization +- Azure Monitor for alerting +- Capacity planning spreadsheets + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/quota/Get-AzVMQuotaUsage.ps1) + +## Related scripts + +- [Get-AzAvailabilityZoneMapping.ps1](get-azavailabilityzonemapping.md) - Map logical to physical zones +- [Show-AzVMQuotaReport.ps1](show-azvmquotareport.md) - Single-threaded alternative \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-benefitrecommendations.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-benefitrecommendations.md new file mode 100644 index 000000000..34b2c6825 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/get-benefitrecommendations.md @@ -0,0 +1,223 @@ +--- +title: Get-BenefitRecommendations.ps1 +parent: Tools & scripts +nav_order: 5 +--- + +# Get-BenefitRecommendations.ps1 + +Queries the Azure Cost Management API to retrieve detailed benefit recommendations that aren't fully exposed in the Azure portal. + +## Overview + +This PowerShell script extracts comprehensive savings plan and reserved instance recommendations directly from the Azure Cost Management API. The API returns additional details and granular data that the portal interface doesn't display, providing deeper insights for cost optimization decisions. + +### Key capabilities + +- **API-level detail extraction**: Accesses recommendation data not visible in portal +- **Flexible lookback periods**: Analyze 7, 30, or 60 days of historical usage +- **Multiple commitment terms**: Compare 1-year vs 3-year savings plans +- **Billing scope flexibility**: Works at subscription or billing account level + +### When to use this script + +- Extracting detailed recommendation data for FinOps reporting +- Comparing savings opportunities across different commitment terms +- Analyzing recommendations based on different usage windows +- Accessing API data fields not shown in portal views +- Building automated cost optimization workflows + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Repository PSGallery -Force + +# Authenticate to Azure +Connect-AzAccount + +# Verify Cost Management Reader permissions +Get-AzRoleAssignment | Where-Object {$_.RoleDefinitionName -like "*Cost Management*"} + +# Find your billing account (for MCA) +Get-AzBillingAccount | Select-Object Name, Id + +# List available subscriptions +Get-AzSubscription | Select-Object Name, Id +``` + +## Parameters + +| Parameter | Type | Description | Default | +|-----------|------|-------------|---------| +| **BillingScope** | String | Billing scope path (required) | None | +| **LookBackPeriod** | String | Historical period to analyze | Last7Days | +| **Term** | String | Commitment term: P1Y or P3Y | P3Y | + +### BillingScope format + +For subscriptions: +``` +subscriptions/12345678-1234-1234-1234-123456789012 +``` + +For billing accounts: +``` +providers/Microsoft.Billing/billingAccounts/12345678 +``` + +### LookBackPeriod values + +- `Last7Days` - Analyze last 7 days of usage +- `Last30Days` - Analyze last 30 days of usage +- `Last60Days` - Analyze last 60 days of usage + +### Term values + +- `P1Y` - 1-year commitment term +- `P3Y` - 3-year commitment term + +## Usage examples + +### Basic subscription analysis + +```powershell +# Get 3-year recommendations based on last 7 days +.\Get-BenefitRecommendations.ps1 ` + -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" +``` + +### Extended analysis period + +```powershell +# Analyze 30 days of usage for 1-year commitments +.\Get-BenefitRecommendations.ps1 ` + -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" ` + -LookBackPeriod "Last30Days" ` + -Term "P1Y" +``` + +### Billing account level + +```powershell +# Get billing account ID +$billingAccount = Get-AzBillingAccount | Select-Object -First 1 + +# Analyze entire billing account +.\Get-BenefitRecommendations.ps1 ` + -BillingScope "providers/Microsoft.Billing/billingAccounts/$($billingAccount.Name)" ` + -LookBackPeriod "Last60Days" ` + -Term "P3Y" +``` + +### Export results for analysis + +```powershell +# Run script and capture output +$result = .\Get-BenefitRecommendations.ps1 ` + -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" ` + -LookBackPeriod "Last30Days" + +# The script outputs raw JSON and formatted tables +# Capture and process as needed for your workflows +``` + +## Output format + +The script provides three types of output: + +1. **Raw JSON output** - Complete API response for processing +2. **Recommended savings plan** - Primary recommendation in table format +3. **All savings plan recommendations** - Full list of recommendations + +## API endpoint + +The script calls the Cost Management API: +``` +https://management.azure.com/{BillingScope}/providers/Microsoft.CostManagement/benefitRecommendations +``` + +With parameters: +- `$filter`: Filters by lookback period and term +- `$expand`: Includes usage and recommendation details +- `api-version`: 2024-08-01 + +## Troubleshooting + +### No recommendations returned + +```powershell +# Verify you have usage data in the period +Get-AzConsumptionUsageDetail ` + -StartDate (Get-Date).AddDays(-7) ` + -EndDate (Get-Date) | + Measure-Object + +# Check permissions +Get-AzRoleAssignment -Scope "/subscriptions/YOUR-SUB-ID" | + Where-Object {$_.RoleDefinitionName -like "*Cost Management*"} +``` + +### Authentication errors + +```powershell +# Clear cached credentials +Clear-AzContext -Force + +# Re-authenticate +Connect-AzAccount + +# Set specific subscription context +Set-AzContext -SubscriptionId "YOUR-SUB-ID" +``` + +### API access issues + +```powershell +# Test direct API access +$scope = "subscriptions/YOUR-SUB-ID" +$uri = "https://management.azure.com/$scope/providers/Microsoft.CostManagement/query?api-version=2024-08-01" +Invoke-AzRestMethod -Uri $uri -Method POST +``` + +## Integration patterns + +### Scheduled analysis + +```powershell +# Weekly analysis across all subscriptions +$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled" + +foreach ($sub in $subscriptions) { + Write-Host "Analyzing subscription: $($sub.Name)" + .\Get-BenefitRecommendations.ps1 ` + -BillingScope "subscriptions/$($sub.Id)" ` + -LookBackPeriod "Last30Days" +} +``` + +### CI/CD integration + +```yaml +# Azure DevOps pipeline +- task: AzurePowerShell@5 + inputs: + azureSubscription: 'ServiceConnection' + ScriptType: 'FilePath' + ScriptPath: '$(System.DefaultWorkingDirectory)/Get-BenefitRecommendations.ps1' + ScriptArguments: > + -BillingScope "subscriptions/$(SubscriptionId)" + -LookBackPeriod "Last30Days" + -Term "P3Y" + azurePowerShellVersion: 'LatestVersion' +``` + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/rate/Get-BenefitRecommendations.ps1) + +## Related documentation + +- [Azure Cost Management API](https://learn.microsoft.com/en-us/rest/api/cost-management/) +- [Savings plan purchase recommendations](https://learn.microsoft.com/en-us/azure/cost-management-billing/savings-plan/purchase-recommendations) +- [Understanding reservation recommendations](https://learn.microsoft.com/en-us/azure/cost-management-billing/reservations/reserved-instance-purchase-recommendations) \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/show-azvmquotareport.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/show-azvmquotareport.md new file mode 100644 index 000000000..676313d4a --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/show-azvmquotareport.md @@ -0,0 +1,244 @@ +--- +title: Show-AzVMQuotaReport.ps1 +parent: Tools & scripts +nav_order: 3 +--- + +# Show-AzVMQuotaReport.ps1 + +Single-threaded Azure VM quota reporting script that provides streamlined quota analysis for smaller deployments or learning scenarios. + +## Overview + +This PowerShell script offers a simplified approach to Azure VM quota analysis. Unlike its multi-threaded counterpart, it processes subscriptions sequentially and displays results in a formatted table, making it ideal for smaller estates or when you're learning how Azure quota management works. + +### Key capabilities + +- **Sequential processing**: Straightforward single-threaded execution for easier debugging +- **Formatted output**: Displays results in a clean table format at completion +- **Zone restriction detection**: Identifies which availability zones are restricted for specific VM SKUs +- **Physical zone mapping**: Optional mapping of logical to physical zones for cross-subscription planning +- **Educational design**: Simpler code structure for understanding quota analysis patterns + +### When to use this script + +- Learning Azure quota management concepts +- Analyzing smaller subscription counts (< 10 subscriptions) +- Debugging quota issues with verbose output +- Quick ad-hoc quota checks for specific SKUs/regions +- Teaching quota analysis patterns to new team members + +### Comparison with Get-AzVMQuotaUsage.ps1 + +| Feature | Show-AzVMQuotaReport | Get-AzVMQuotaUsage | +|---------|----------------------|--------------------| +| Threading | Single-threaded | Multi-threaded (configurable) | +| Best for | < 10 subscriptions | 100+ subscriptions | +| Performance | Sequential | Parallel processing | +| Code complexity | Simpler | Production-optimized | +| Output format | Table + CSV | CSV only | +| Use case | Learning/debugging | Production analysis | + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Repository PSGallery -Force + +# Authenticate to Azure +Connect-AzAccount + +# Verify subscription access +Get-AzSubscription | Select-Object Name, Id, State + +# Check Reader permissions +Get-AzRoleAssignment | Where-Object {$_.RoleDefinitionName -like "*Reader*"} +``` + +## Parameters + +| Parameter | Type | Description | Default | +|-----------|------|-------------|---------| +| **SKUs** | String[] | Array of VM SKU names to analyze | Catalogs API-first discovery; falls back to deprecated CSV only if API lookup fails and `-SKUs` is omitted | +| **Locations** | String[] | Array of Azure regions to query | All regions | +| **SubscriptionIds** | String[] | Array of subscription IDs to analyze | All accessible subscriptions | +| **CatalogLocation** | String | Azure region used for Catalogs API lookup | eastus | +| **OutputFile** | String | CSV output filename | QuotaQuery.csv | +| **UsePhysicalZones** | Switch | Map logical zones to physical datacenters | False | +| **MeterDataUri** | String | Deprecated fallback source URI for VM SKU metadata, used only when Catalogs API lookup fails and `-SKUs` is not provided | Azure public data | + +## Usage examples + +### Basic quota check for specific SKUs + +```powershell +.\Show-AzVMQuotaReport.ps1 -SKUs @('Standard_D2s_v5', 'Standard_E4s_v5') -Locations @('eastus', 'westus2') +``` + +### Analyze specific subscriptions with physical zone mapping + +```powershell +.\Show-AzVMQuotaReport.ps1 ` + -SubscriptionIds @('sub1-guid', 'sub2-guid') ` + -UsePhysicalZones ` + -OutputFile "DevSubscriptionQuota.csv" +``` + +### Quick quota audit for a single region + +```powershell +.\Show-AzVMQuotaReport.ps1 ` + -SKUs @('Standard_D4s_v5') ` + -Locations @('eastus') ` + -OutputFile "EastUSQuotaCheck_$(Get-Date -Format 'yyyyMMdd').csv" +``` + +### Full analysis with default SKU discovery + +```powershell +.\Show-AzVMQuotaReport.ps1 -OutputFile "CompleteQuotaAnalysis.csv" +``` + +## Sample output + +Running the script produces both console output and a CSV file: + +### Console output +```plaintext +Querying Azure Catalogs API for VM SKU details in eastus +Retrieved 412 unique VM SKUs from Catalogs API +Listing Subscriptions +Processing subscription: Development (12345678-abcd-1234-5678-123456789012) + Analyzing location: eastus + Checking SKU: Standard_D2s_v5 + Checking SKU: Standard_E4s_v5 + Analyzing location: westus2 + Checking SKU: Standard_D2s_v5 + Checking SKU: Standard_E4s_v5 + +Results saved to: QuotaQuery.csv + +Summary Table: +Subscription Location SKU CoresUsed/Total Zones Available +------------ -------- --------------- --------------- --------------- +Development eastus Standard_D2s_v5 8/100 1,2,3 +Development eastus Standard_E4s_v5 0/100 1,2,3 +Development westus2 Standard_D2s_v5 4/100 1,2,3 +Development westus2 Standard_E4s_v5 16/100 1,2,3 +``` + +### CSV output +```csv +TenantId,SubscriptionId,SubscriptionName,Location,Family,Size,RegionRestricted,ZonesPresent,ZonesRestricted,CoresUsed,CoresTotal +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Development,eastus,standardDSv5Family,Standard_D2s_v5,False,"1,2,3",,8,100 +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Development,eastus,standardESv5Family,Standard_E4s_v5,False,"1,2,3",,0,100 +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Development,westus2,standardDSv5Family,Standard_D2s_v5,False,"1,2,3",,4,100 +12345678-1234-1234-1234-123456789012,abcd1234-5678-90ab-cdef-123456789012,Development,westus2,standardESv5Family,Standard_E4s_v5,False,"1,2,3",,16,100 +``` + +### Understanding the output + +- **TenantId**: Microsoft Entra tenant identifier +- **SubscriptionId**: Unique subscription identifier +- **SubscriptionName**: Friendly subscription name +- **Location**: Azure region +- **Family**: VM family for quota calculation +- **Size**: Specific VM SKU +- **RegionRestricted**: Whether the SKU has regional restrictions +- **ZonesPresent**: Available availability zones +- **ZonesRestricted**: Zones requiring enablement request +- **CoresUsed**: Current vCPU consumption +- **CoresTotal**: Total vCPU quota limit + +## Troubleshooting + +### Script runs slowly + +This is expected behavior for the single-threaded version. For faster processing: +```powershell +# Use the multi-threaded version instead +.\Get-AzVMQuotaUsage.ps1 -Threads 4 +``` + +### Catalogs API returns no SKU data + +The script now uses the Catalogs API as the primary SKU source. If SKU discovery fails: + +```powershell +# Verify the selected catalog location +Get-AzLocation | Where-Object Location -eq 'eastus' + +# Verify the Catalogs API permission is available +Get-AzRoleAssignment | + Where-Object { $_.RoleDefinitionName -like '*Reader*' } +``` + +If you already know the SKU names, pass them with `-SKUs` to skip catalog discovery. + +### Authentication or permission errors + +Catalog lookup requires an authenticated Az session and the `Microsoft.Capacity/catalogs/read` +permission in addition to subscription read access. + +```powershell +# Clear and re-authenticate +Clear-AzContext -Force +Connect-AzAccount -Tenant 'your-tenant-id' + +# Verify current context +Get-AzContext | Select-Object Account, Subscription, Tenant +``` + +If the script reports an authorization failure from the Catalogs API, ask your Azure administrator +to grant access that includes `Microsoft.Capacity/catalogs/read`. + +### CSV fallback behavior + +If the Catalogs API lookup fails and you do not pass `-SKUs`, the script falls back to the +deprecated meter data CSV source. That fallback helps older workflows continue, but it may not +include the latest SKU catalog changes. + +```powershell +# Check whether the default local fallback CSV exists after a failed Catalogs API lookup +Test-Path "AutofitComboMeterData.csv" +``` + +### Empty zones data + +```powershell +# Some regions don't support availability zones +Get-AzLocation | Where-Object Location -eq 'westus' | + Select-Object -ExpandProperty Zones + +# If empty, the region doesn't support zones +``` + +## Educational value + +This script serves as a learning tool for understanding: +- How Azure organizes quota by VM family +- The relationship between logical and physical zones +- Sequential API interaction patterns +- CSV export for further analysis + +For production use with large subscription counts, use Get-AzVMQuotaUsage.ps1 which provides: +- Parallel processing for 10x faster execution +- Configurable thread counts +- Better error handling for large-scale analysis + +## Performance comparison + +| Subscriptions | Show-AzVMQuotaReport | Get-AzVMQuotaUsage (4 threads) | +|---------------|----------------------|----------------------------------| +| 5 | ~2 minutes | ~30 seconds | +| 25 | ~10 minutes | ~3 minutes | +| 100 | ~40 minutes | ~10 minutes | + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/blob/main/scripts/quota/Show-AzVMQuotaReport.ps1) + +## Related scripts + +- [Get-AzVMQuotaUsage.ps1](get-azvmquotausage.md) - Multi-threaded version for production use +- [Get-AzAvailabilityZoneMapping.ps1](get-azavailabilityzonemapping.md) - Dedicated zone mapping analysis diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/suppress-advisorrecommendations.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/suppress-advisorrecommendations.md new file mode 100644 index 000000000..29a8e1a6b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/operations/tools-scripts/suppress-advisorrecommendations.md @@ -0,0 +1,144 @@ +--- +title: Suppress-AdvisorRecommendations.ps1 +parent: Tools & scripts +nav_order: 10 +--- + +# Suppress-AdvisorRecommendations.ps1 + +Suppress specific Azure Advisor recommendation types across all subscriptions in a management group for up to 90 days. + +## Overview + +Azure Policy can't disable Advisor recommendations. Advisor exposes a [suppression API](https://learn.microsoft.com/en-us/azure/advisor/suppress-recommendations?tabs=rest) with a TTL of up to 90 days. This script iterates over a management group's subscriptions and calls that API for each specified recommendation type, so FinOps or platform teams can bulk-suppress noise without navigating the portal subscription by subscription. + +### Key capabilities + +- **Management group scope**: Suppress across all subscriptions in a hierarchy +- **Recommendation type targeting**: Suppress by recommendation type GUID +- **TTL control**: Configurable suppression duration up to 90 days +- **What-if mode**: Preview scope without writing suppressions + +### When to use this script + +- Suppressing recommendations that your team manages centrally (e.g., reserved instance purchases handled by a FinOps team, not individual subscription owners) +- Quieting noise for known workload patterns that Advisor doesn't understand +- Temporary suppression during migrations or planned outages +- Weekly automation to maintain suppression across a large subscription estate + +> **Note**: Suppression TTL is capped at 90 days per the [Advisor suppressions API](https://learn.microsoft.com/en-us/rest/api/advisor/suppressions/create?tabs=HTTP). Run the script on a weekly or bi-weekly schedule to maintain coverage. + +## Prerequisites + +```powershell +# Install Azure PowerShell module +Install-Module -Name Az -Repository PSGallery -Force + +# Authenticate to Azure +Connect-AzAccount + +# Verify management group access +Get-AzManagementGroup | Select-Object Name, DisplayName +``` + +**Permissions**: Advisor Contributor or higher on the management group and its subscriptions. See [Advisor permissions](https://learn.microsoft.com/en-us/azure/advisor/permissions). + +## Parameters + +| Parameter | Type | Description | Required | +|-----------|------|-------------|----------| +| **ManagementGroupId** | String | Management group name to target | Yes | +| **RecommendationTypeIds** | String[] | Array of recommendation type GUIDs to suppress | Yes | +| **Days** | Int | Suppression duration in days (1–90) | Yes | +| **WhatIf** | Switch | Preview scope without writing suppressions | No | + +## Usage examples + +### Dry run — preview scope + +```powershell +.\Suppress-AdvisorRecommendations.ps1 ` + -ManagementGroupId "your-mg" ` + -RecommendationTypeIds @( + "89515250-1243-43d1-b4e7-f9437cedffd8", + "84b1a508-fc21-49da-979e-96894f1665df", + "48eda464-1485-4dcf-a674-d0905df5054a" + ) ` + -Days 30 ` + -WhatIf +``` + +### Execute suppression + +```powershell +.\Suppress-AdvisorRecommendations.ps1 ` + -ManagementGroupId "your-mg" ` + -RecommendationTypeIds @( + "89515250-1243-43d1-b4e7-f9437cedffd8", + "84b1a508-fc21-49da-979e-96894f1665df", + "48eda464-1485-4dcf-a674-d0905df5054a" + ) ` + -Days 30 +``` + +## Finding recommendation type GUIDs + +Advisor recommendation type GUIDs aren't displayed in the portal. Retrieve them via the [Advisor REST API](https://learn.microsoft.com/en-us/rest/api/advisor/recommendations/list?tabs=HTTP): + +```bash +# List recommendations with their type GUIDs for a subscription +az rest --method GET \ + --url "https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Advisor/recommendations?api-version=2023-01-01" +``` + +Look for the `recommendationTypeId` field in the response. + +## Scheduling + +Suppression TTL tops out at 90 days. To maintain continuous suppression, schedule this script on a weekly cadence via Azure Automation or a CI/CD pipeline: + +```powershell +# Azure Automation runbook pattern (using managed identity) +Connect-AzAccount -Identity + +.\Suppress-AdvisorRecommendations.ps1 ` + -ManagementGroupId $env:MANAGEMENT_GROUP_ID ` + -RecommendationTypeIds ($env:RECOMMENDATION_TYPE_IDS -split ',') ` + -Days 30 +``` + +**Source**: [Suppressions API reference](https://learn.microsoft.com/en-us/rest/api/advisor/suppressions/create?tabs=HTTP) + +## Troubleshooting + +### Permission errors + +```powershell +# Check current role assignments +Get-AzRoleAssignment -SignInName (Get-AzContext).Account.Id | + Where-Object { $_.Scope -like "*/managementGroups/*" } +``` + +You need Advisor Contributor or higher. Reader alone isn't sufficient—write access to the suppression resource is required. + +### No subscriptions found + +```powershell +# Verify management group access and name +Get-AzManagementGroup -GroupName "your-mg" -Expand -Recurse | + Select-Object -ExpandProperty Children +``` + +### Suppression not persisting + +Verify the TTL hasn't expired. Suppressions older than `Days` are automatically cleared by Advisor. Check the [Advisor portal](https://portal.azure.com/#blade/Microsoft_Azure_Expert/AdvisorMenuBlade/overview) > Settings > Suppressions to confirm active suppression records. + +## Script source + +[View full script source →](https://github.com/microsoft/azcapman/tree/main/scripts/advisor) + +## Related documentation + +- [Suppress Azure Advisor recommendations](https://learn.microsoft.com/en-us/azure/advisor/suppress-recommendations?tabs=rest) +- [Advisor suppressions API](https://learn.microsoft.com/en-us/rest/api/advisor/suppressions/create?tabs=HTTP) +- [Advisor permissions](https://learn.microsoft.com/en-us/azure/advisor/permissions) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/toc.yml b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/toc.yml new file mode 100644 index 000000000..be391facc --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/docs/toc.yml @@ -0,0 +1,104 @@ +- name: Overview + href: index.md +- name: Labs + href: labs/lab-02-forecasting.md + items: + - name: Planning and forecasting + href: labs/lab-02-forecasting.md + - name: Workload placement + href: labs/lab-03-allocation.md + - name: Capacity guarantees + href: labs/lab-04-procurement.md + - name: Governance and automation + href: labs/lab-05-monitoring-governance.md +- name: Capacity management + href: operations/README.md + items: + - name: Overview + href: operations/README.md + - name: Planning and forecasting + href: operations/capacity-planning/README.md + items: + - name: Capacity and billing operations + href: operations/capacity-and-quotas/README.md + - name: Capacity planning + href: operations/capacity-planning/README.md + - name: Customer isolation + href: deployment/README.md + items: + - name: Overview + href: deployment/README.md + - name: Single-tenant + href: deployment/single-tenant/README.md + - name: Multi-tenant + href: deployment/multi-tenant/README.md + - name: Workload placement + href: operations/quota/README.md + items: + - name: Billing models + href: billing/README.md + items: + - name: Overview + href: billing/README.md + - name: Microsoft Customer Agreement + href: billing/modern/README.md + items: + - name: Overview + href: billing/modern/README.md + - name: Subscription creation (billing scope) + href: operations/modern/README.md + - name: Enterprise Agreement + href: billing/legacy/README.md + items: + - name: Overview + href: billing/legacy/README.md + - name: Subscription creation (billing scope) + href: operations/legacy/README.md + - name: Quota operations + href: operations/quota/README.md + - name: Capacity reservations + href: operations/capacity-reservations/README.md + - name: AKS capacity governance + href: operations/aks-capacity/README.md + - name: Non-compute quotas + href: operations/non-compute-quotas/README.md + - name: Usage and rate optimization + href: operations/quota-groups/README.md + items: + - name: Quota groups + href: operations/quota-groups/README.md + - name: Governance and automation + href: operations/monitoring-alerting/README.md + items: + - name: Monitoring and alerting + href: operations/monitoring-alerting/README.md + - name: Capacity governance + href: operations/capacity-governance/README.md + - name: Tools and scripts + href: operations/tools-scripts/README.md + items: + - name: Overview + href: operations/tools-scripts/README.md + - name: Get-AzVMQuotaUsage.ps1 + href: operations/tools-scripts/get-azvmquotausage.md + - name: Get-AzAvailabilityZoneMapping.ps1 + href: operations/tools-scripts/get-azavailabilityzonemapping.md + - name: Show-AzVMQuotaReport.ps1 + href: operations/tools-scripts/show-azvmquotareport.md + - name: Get-BenefitRecommendations.ps1 + href: operations/tools-scripts/get-benefitrecommendations.md + - name: Deploy-AnomalyAlert.ps1 + href: operations/tools-scripts/deploy-anomalyalert.md + - name: Deploy-BulkALZ.ps1 + href: operations/tools-scripts/deploy-bulkalz.md + - name: Support and reference + href: operations/support-and-reference/README.md + items: + - name: Overview + href: operations/support-and-reference/README.md + - name: Support escalation + href: operations/escalation/README.md + - name: Tenant hygiene + href: operations/tenant-hygiene/README.md + - name: Glossary + href: operations/glossary.md diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts deleted file mode 120000 index 487d8d51b..000000000 --- a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts +++ /dev/null @@ -1 +0,0 @@ -../../../../../../submodules/azcapman/scripts \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/README.md new file mode 100644 index 000000000..3c5a8cd81 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/README.md @@ -0,0 +1,27 @@ +# Azure Advisor suppression + +Azure Policy cannot disable Advisor recommendations; Advisor provides suppression APIs with TTL up to 90 days. Use this script to suppress specific recommendation types across a management group. [Source](https://learn.microsoft.com/en-us/azure/advisor/suppress-recommendations?tabs=rest) + +## Usage + +```powershell +# Dry run +.\Suppress-AdvisorRecommendations.ps1 -ManagementGroupId "your-mg" ` + -RecommendationTypeIds @( + "89515250-1243-43d1-b4e7-f9437cedffd8", + "84b1a508-fc21-49da-979e-96894f1665df", + "48eda464-1485-4dcf-a674-d0905df5054a" + ) -Days 30 -WhatIf + +# Execute +.\Suppress-AdvisorRecommendations.ps1 -ManagementGroupId "your-mg" ` + -RecommendationTypeIds @(...) -Days 30 +``` + +## Schedule + +Run weekly via Azure Automation or CI/CD pipeline; suppression TTL is capped at 90 days. [Source](https://learn.microsoft.com/en-us/rest/api/advisor/suppressions/create?tabs=HTTP) + +## Permissions + +Advisor Contributor (or higher) on the management group and subscriptions. [Source](https://learn.microsoft.com/en-us/azure/advisor/permissions) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/Suppress-AdvisorRecommendations.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/Suppress-AdvisorRecommendations.ps1 new file mode 100644 index 000000000..acc45f178 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/advisor/Suppress-AdvisorRecommendations.ps1 @@ -0,0 +1,79 @@ +<# +.SYNOPSIS + Suppress Azure Advisor recommendations across a management group. + +.EXAMPLE + .\Suppress-AdvisorRecommendations.ps1 -ManagementGroupId "ALZ" -Days 30 -WhatIf +#> + +[CmdletBinding(SupportsShouldProcess)] +param( + [Parameter(Mandatory)] + [string]$ManagementGroupId, + + [string[]]$RecommendationTypeIds = @( + "89515250-1243-43d1-b4e7-f9437cedffd8", + "84b1a508-fc21-49da-979e-96894f1665df", + "48eda464-1485-4dcf-a674-d0905df5054a" + ), + + [ValidateRange(1,90)] + [int]$Days = 30 +) + +$ErrorActionPreference = 'Stop' + +# Advisor suppression TTL uses ISO 8601 duration and max 90 days. +function Get-TtlString([int]$days) { + return "P{0}D" -f $days +} + +# Get all subscriptions under management group +$mg = Get-AzManagementGroup -GroupId $ManagementGroupId -Expand -Recurse +$subs = @() +function Get-Subs($node) { + if ($node.Children) { + foreach ($c in $node.Children) { + if ($c.Type -eq '/subscriptions') { $script:subs += @{Id=$c.Name; Name=$c.DisplayName} } + else { Get-Subs $c } + } + } +} +Get-Subs $mg + +Write-Host "Processing $($subs.Count) subscription(s)..." -ForegroundColor Cyan + +$total = @{Found=0; Suppressed=0; Failed=0} +$ttl = Get-TtlString -days $Days + +foreach ($sub in $subs) { + Set-AzContext -SubscriptionId $sub.Id -ErrorAction SilentlyContinue | Out-Null + + $recs = Get-AzAdvisorRecommendation -ErrorAction SilentlyContinue | + Where-Object { $_.RecommendationTypeId -in $RecommendationTypeIds } + + if (-not $recs) { continue } + + $total.Found += $recs.Count + Write-Host "[$($sub.Name)] Found $($recs.Count)" -ForegroundColor Yellow + + foreach ($rec in $recs) { + if ($WhatIfPreference) { + Write-Host " WhatIf: $($rec.ShortDescriptionProblem)" -ForegroundColor Gray + continue + } + + $resourceUri = $rec.Id.Substring(0, $rec.Id.IndexOf("/providers/Microsoft.Advisor")) + $recId = ($rec.Id -split '/recommendations/')[-1] + $suppressionId = [Guid]::NewGuid() + $uri = "https://management.azure.com$resourceUri/providers/Microsoft.Advisor/recommendations/$recId/suppressions/$suppressionId?api-version=2023-01-01" + + $body = @{properties=@{ttl=$ttl}} | ConvertTo-Json + $resp = Invoke-AzRestMethod -Method PUT -Uri $uri -Payload $body + + if ($resp.StatusCode -in 200,201) { $total.Suppressed++ } + else { $total.Failed++; Write-Warning "Failed ($($resp.StatusCode)): $($rec.ShortDescriptionProblem)" } + } +} + +Write-Host "`nFound: $($total.Found) | Suppressed: $($total.Suppressed) | Failed: $($total.Failed)" -ForegroundColor Cyan diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-AnomalyAlert.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-AnomalyAlert.ps1 new file mode 100644 index 000000000..ec116c820 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-AnomalyAlert.ps1 @@ -0,0 +1,312 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Deploy anomaly alert configuration to an Azure subscription. + +.DESCRIPTION + This script deploys the anomaly alert Bicep template to create a subscription-level + scheduled action for cost anomaly monitoring. The script handles subscription + validation, parameter collection, and deployment with proper error handling. + +.PARAMETER SubscriptionId + The target Azure subscription ID where the anomaly alert will be deployed. + If not provided, the script will prompt for selection from available subscriptions. + +.PARAMETER EmailRecipients + Array of email addresses that'll receive anomaly alert notifications. + These should be valid email addresses of stakeholders who need to be notified. + +.PARAMETER NotificationEmail + Primary notification email address for the anomaly alert system. + This is typically an administrative or monitoring email address. + +.PARAMETER DeploymentName + Optional custom name for the deployment. If not provided, a timestamped name will be generated. + +.PARAMETER Location + Azure region for the deployment. Defaults to 'West US' if not specified. + Note: This is only for deployment metadata, not resource location. + +.PARAMETER Force + Skip confirmation prompts and proceed with deployment automatically. + +.PARAMETER Quiet + Suppress verbose deployment progress output to avoid the 5-second polling wait. + +.EXAMPLE + ./Deploy-AnomalyAlert.ps1 -EmailRecipients @("admin@company.com", "finance@company.com") -NotificationEmail "alerts@company.com" + + Deploy anomaly alert with interactive subscription selection and specified email addresses. + +.EXAMPLE + ./Deploy-AnomalyAlert.ps1 -SubscriptionId "12345678-1234-1234-1234-123456789012" -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" -WhatIf + + Show what would be deployed in the specified subscription without actually deploying. + +.EXAMPLE + ./Deploy-AnomalyAlert.ps1 -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" -Force + + Deploy without confirmation prompts. + +.NOTES + - Requires Azure PowerShell module (Az) + - User must be authenticated to Azure (Connect-AzAccount) + - User must have appropriate permissions to create subscription-level resources + - The deployment creates a cost management scheduled action for anomaly detection +#> + +[CmdletBinding(SupportsShouldProcess)] +param( + [Parameter(Mandatory = $false)] + [ValidatePattern('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$')] + [string]$SubscriptionId, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string[]]$EmailRecipients, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$NotificationEmail, + + [Parameter(Mandatory = $false)] + [string]$DeploymentName, + + [Parameter(Mandatory = $false)] + [string]$Location = 'West US', + + [Parameter(Mandatory = $false)] + [switch]$Force, + + [Parameter(Mandatory = $false)] + [switch]$Quiet +) + +#region Helper Functions + +function Write-Log { + param( + [string]$Message, + [ValidateSet('Info', 'Warning', 'Error', 'Success')] + [string]$Level = 'Info' + ) + + $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' + $colors = @{ + 'Info' = 'White' + 'Warning' = 'Yellow' + 'Error' = 'Red' + 'Success' = 'Green' + } + + Write-Host "[$timestamp] " -NoNewline -ForegroundColor Gray + Write-Host $Message -ForegroundColor $colors[$Level] +} + +function Test-AzureConnection { + try { + $context = Get-AzContext + if (-not $context) { + return $false + } + return $true + } + catch { + return $false + } +} + +function Get-SubscriptionSelection { + param([string]$TargetSubscriptionId) + + try { + $subscriptions = Get-AzSubscription | Sort-Object Name + + if ($subscriptions.Count -eq 0) { + throw "No subscriptions found. Check if you are logged in with the correct Azure account." + } + + if ($TargetSubscriptionId) { + $selectedSub = $subscriptions | Where-Object { $_.Id -eq $TargetSubscriptionId } + if (-not $selectedSub) { + throw "Subscription with ID '$TargetSubscriptionId' not found or not accessible." + } + return $selectedSub + } + + if ($subscriptions.Count -eq 1) { + Write-Log "Using the only available subscription: $($subscriptions[0].Name)" -Level Info + return $subscriptions[0] + } + + Write-Log "Multiple subscriptions found. Please select:" -Level Info + for ($i = 0; $i -lt $subscriptions.Count; $i++) { + Write-Host " [$i] $($subscriptions[$i].Name) ($($subscriptions[$i].Id))" + } + + do { + $selection = Read-Host "Enter subscription number [0-$($subscriptions.Count - 1)]" + $selectionIndex = $null + if ([int]::TryParse($selection, [ref]$selectionIndex) -and + $selectionIndex -ge 0 -and $selectionIndex -lt $subscriptions.Count) { + return $subscriptions[$selectionIndex] + } + Write-Log "Invalid selection. Please enter a number between 0 and $($subscriptions.Count - 1)." -Level Warning + } while ($true) + } + catch { + throw "Failed to get subscription information: $($_.Exception.Message)" + } +} + +function Confirm-Deployment { + param( + [object]$Subscription, + [string[]]$EmailRecipients, + [string]$NotificationEmail, + [string]$DeploymentName + ) + + if ($Force) { + return $true + } + + Write-Host "" + Write-Log "Deployment summary:" -Level Info + Write-Host " Subscription: $($Subscription.Name) ($($Subscription.Id))" + Write-Host " Deployment name: $DeploymentName" + Write-Host " Email recipients: $($EmailRecipients -join ', ')" + Write-Host " Notification email: $NotificationEmail" + Write-Host "" + + $confirmation = Read-Host "Do you want to proceed with this deployment? (y/N)" + return ($confirmation -eq 'y' -or $confirmation -eq 'Y') +} + +#endregion + +#region Main Script + +try { + Write-Log "Starting anomaly alert deployment script..." -Level Info + + # Check if Azure PowerShell is available + if (-not (Get-Module -Name Az.Accounts -ListAvailable)) { + throw "Azure PowerShell module (Az) isn't installed. Please install it using: Install-Module -Name Az" + } + + # Check Azure connection + if (-not (Test-AzureConnection)) { + Write-Log "Not connected to Azure. Please run 'Connect-AzAccount' first." -Level Error + throw "Azure authentication required" + } + + Write-Log "Azure connection verified." -Level Success + + # Get target subscription + $targetSubscription = Get-SubscriptionSelection -TargetSubscriptionId $SubscriptionId + Write-Log "Selected subscription: $($targetSubscription.Name)" -Level Success + + # Set the subscription context + $null = Set-AzContext -SubscriptionId $targetSubscription.Id + + # Generate deployment name if not provided + if (-not $DeploymentName) { + $timestamp = Get-Date -Format "yyyyMMddHHmmss" + $DeploymentName = "anomaly-alert-$timestamp" + } + + # Get the script directory and template path + $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + $templateFile = Join-Path $scriptDir "anomaly-alert.bicep" + + # Verify template file exists + if (-not (Test-Path $templateFile)) { + throw "Bicep template file not found: $templateFile" + } + + Write-Log "Template file found: $templateFile" -Level Success + + # Validate email addresses + $emailRegex = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' + foreach ($email in $EmailRecipients) { + if ($email -notmatch $emailRegex) { + throw "Invalid email address format: $email" + } + } + + if ($NotificationEmail -notmatch $emailRegex) { + throw "Invalid notification email address format: $NotificationEmail" + } + + Write-Log "Email addresses validated." -Level Success + + # Prepare deployment parameters + $deploymentParams = @{ + emailRecipients = $EmailRecipients + notificationEmail = $NotificationEmail + } + + # Show deployment summary and get confirmation + if (-not (Confirm-Deployment -Subscription $targetSubscription -EmailRecipients $EmailRecipients -NotificationEmail $NotificationEmail -DeploymentName $DeploymentName)) { + Write-Log "Deployment cancelled by user." -Level Warning + return + } + + # Prepare deployment splat + $deploymentSplat = @{ + Name = $DeploymentName + Location = $Location + TemplateFile = $templateFile + TemplateParameterObject = $deploymentParams + } + + if ($WhatIfPreference) { + $deploymentSplat.Add('WhatIf', $true) + Write-Log "Running deployment validation (What-If)..." -Level Info + } else { + Write-Log "Starting deployment..." -Level Info + } + + # Execute deployment + if ($PSCmdlet.ShouldProcess($targetSubscription.Name, "Deploy anomaly alert")) { + if ($Quiet) { + $deployment = New-AzSubscriptionDeployment @deploymentSplat + } else { + $deployment = New-AzSubscriptionDeployment @deploymentSplat -Verbose + } + + if (-not $WhatIfPreference) { + if ($deployment.ProvisioningState -eq 'Succeeded') { + Write-Log "Deployment completed successfully!" -Level Success + Write-Host "" + Write-Log "Deployment details:" -Level Info + Write-Host " Deployment name: $($deployment.DeploymentName)" + Write-Host " Resource ID: $($deployment.Id)" + Write-Host " Status: $($deployment.ProvisioningState)" + Write-Host " Timestamp: $($deployment.Timestamp)" + Write-Host "" + Write-Log "Anomaly alert has been configured and will monitor cost anomalies for this subscription." -Level Info + Write-Log "Notifications will be sent to: $($EmailRecipients -join ', ')" -Level Info + } else { + Write-Log "Deployment failed with status: $($deployment.ProvisioningState)" -Level Error + if ($deployment.Error) { + Write-Log "Error details: $($deployment.Error.Message)" -Level Error + } + throw "Deployment failed" + } + } else { + Write-Log "What-If operation completed. Review the output above." -Level Success + } + } +} +catch { + Write-Log "Script execution failed: $($_.Exception.Message)" -Level Error + Write-Log "Stack trace: $($_.ScriptStackTrace)" -Level Error + exit 1 +} +finally { + Write-Log "Script execution completed." -Level Info +} + +#endregion diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-BulkALZ.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-BulkALZ.ps1 new file mode 100755 index 000000000..890b7297b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/Deploy-BulkALZ.ps1 @@ -0,0 +1,168 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + Deploy anomaly alerts to all subscriptions in a management group. + +.DESCRIPTION + Deploy anomaly alerts to all subscriptions in the specified management group with + intelligent pagination support for large enterprise environments. The script uses + Azure Resource Graph to discover subscriptions and deploys alerts in batches. + +.PARAMETER TenantId + Azure tenant ID to connect to. + +.PARAMETER ManagementGroup + Management group name to query for subscriptions. + +.PARAMETER EmailRecipients + Array of email addresses that'll receive anomaly notifications. + +.PARAMETER NotificationEmail + Primary notification email address for alerts. + +.PARAMETER WhatIf + Preview changes without deploying. + +.PARAMETER Quiet + Suppress Azure PowerShell warning messages for cleaner output. + +.EXAMPLE + ./Deploy-BulkALZ.ps1 -TenantId "12345678-1234-1234-1234-123456789012" -ManagementGroup "ALZ" -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" + + Deploy anomaly alerts to all subscriptions in the ALZ management group. + +.EXAMPLE + ./Deploy-BulkALZ.ps1 -TenantId "12345678-1234-1234-1234-123456789012" -ManagementGroup "ALZ" -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" -WhatIf + + Preview what would be deployed without making actual changes. + +.EXAMPLE + ./Deploy-BulkALZ.ps1 -TenantId "12345678-1234-1234-1234-123456789012" -ManagementGroup "ALZ" -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" -Quiet + + Deploy with minimal output for automated scenarios. + +.NOTES + - Requires Azure PowerShell and Azure Resource Graph modules + - Supports intelligent pagination for thousands of subscriptions + - Automatically handles Azure Resource Graph's 1,000 result limit + - User must have appropriate permissions across target subscriptions +#> + +param( + [Parameter(Mandatory=$true)] + [string[]]$EmailRecipients, + + [Parameter(Mandatory=$true)] + [string]$NotificationEmail, + + [Parameter(Mandatory=$true)] + [string]$TenantId, + + [Parameter(Mandatory=$true)] + [string]$ManagementGroup, + + [switch]$WhatIf, + + [switch]$Quiet +) + +Write-Host "=== Bulk anomaly alert deployment ===" -ForegroundColor Cyan +Write-Host "Target: $ManagementGroup management group" -ForegroundColor Yellow +Write-Host "Tenant: $TenantId" -ForegroundColor Yellow +Write-Host "Mode: $(if ($WhatIf) { 'What-if (preview)' } else { 'Deploy' })" -ForegroundColor Yellow + +# Suppress Azure PowerShell warnings if Quiet mode is enabled +if ($Quiet) { + $WarningPreference = 'SilentlyContinue' +} + +# Connect to target tenant +Write-Host "Connecting to tenant..." -ForegroundColor Yellow +Connect-AzAccount -TenantId $tenantId + +# Get subscriptions +Write-Host "Finding subscriptions in $ManagementGroup management group..." -ForegroundColor Yellow + +# Handle pagination for large result sets +$allSubscriptions = @() +$skip = 0 +$pageSize = 1000 + +do { + Write-Host "Querying subscriptions (page $([math]::Floor($skip / $pageSize) + 1))..." -ForegroundColor Gray + + $query = "ResourceContainers | where type =~ 'microsoft.resources/subscriptions' | where properties.state == 'Enabled' | project subscriptionId, name" + + if ($skip -eq 0) { + $pageResults = Search-AzGraph -Query $query -ManagementGroup $managementGroup -First $pageSize + } else { + $pageResults = Search-AzGraph -Query $query -ManagementGroup $managementGroup -First $pageSize -Skip $skip + } + + if ($pageResults) { + $allSubscriptions += $pageResults + $skip += $pageResults.Count + Write-Host "Found $($pageResults.Count) subscriptions in this page (total: $($allSubscriptions.Count))" -ForegroundColor Gray + } + + # Continue if we got a full page (indicating there might be more) +} while ($pageResults -and $pageResults.Count -eq $pageSize) + +$subscriptions = $allSubscriptions +Write-Host "Total subscriptions found: $($subscriptions.Count)" -ForegroundColor Green + +if (!$subscriptions -or $subscriptions.Count -eq 0) { + Write-Host "No subscriptions found!" -ForegroundColor Red + exit 1 +} + +Write-Host "Subscriptions to deploy to:" -ForegroundColor Green +foreach ($sub in $subscriptions | Select-Object -First 10) { + Write-Host " - $($sub.name)" -ForegroundColor White +} + +if ($subscriptions.Count -gt 10) { + Write-Host " ... and $($subscriptions.Count - 10) more" -ForegroundColor Gray +} + +# Confirm deployment +if (!$WhatIf) { + Write-Host "" + $confirm = Read-Host "Deploy to all subscriptions? (y/N)" + if ($confirm -ne 'y' -and $confirm -ne 'Y') { + Write-Host "Cancelled." -ForegroundColor Yellow + exit 0 + } +} + +# Deploy to each subscription +Write-Host "" +Write-Host "Starting deployment..." -ForegroundColor Green + +foreach ($sub in $subscriptions) { + Write-Host "Deploying to: $($sub.name)" -ForegroundColor Cyan + + try { + if ($WhatIf) { + if ($Quiet) { + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients $EmailRecipients -NotificationEmail $NotificationEmail -WhatIf -Force -Quiet -WarningAction SilentlyContinue + } else { + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients $EmailRecipients -NotificationEmail $NotificationEmail -WhatIf -Force -Quiet + } + } else { + if ($Quiet) { + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients $EmailRecipients -NotificationEmail $NotificationEmail -Force -Quiet -WarningAction SilentlyContinue + } else { + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients $EmailRecipients -NotificationEmail $NotificationEmail -Force -Quiet + } + } + Write-Host "✅ Success: $($sub.name)" -ForegroundColor Green + } + catch { + Write-Host "❌ Failed: $($sub.name) - $($_.Exception.Message)" -ForegroundColor Red + } +} + +Write-Host "" +Write-Host "Deployment complete!" -ForegroundColor Green diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/README.md new file mode 100644 index 000000000..023a3d55e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/README.md @@ -0,0 +1,436 @@ +# Anomaly alert deployment + +Deploy cost anomaly alerts across your Azure subscriptions at enterprise scale. + +## Table of contents + +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Deployment scripts](#deployment-scripts) + - [Individual subscription deployment](#deploy-anomalyalertps1-individual-subscriptions) + - [Enterprise bulk deployment](#deploy-bulkalzps1-enterprise-bulk-deployment) +- [Quick start guide](#quick-start-guide) + - [Single subscription](#single-subscription-deployment) + - [Enterprise bulk deployment](#enterprise-bulk-deployment) +- [Parameters reference](#parameters-reference) + - [Deploy-AnomalyAlert.ps1 parameters](#deploy-anomalyalertps1-parameters) + - [Deploy-BulkALZ.ps1 parameters](#deploy-bulkalzps1-parameters) +- [Enterprise-scale features](#enterprise-scale-features) + - [Pagination system](#pagination-system) + - [Performance optimization](#performance-optimization) +- [Advanced usage](#advanced-usage) + - [Azure CLI deployment](#azure-cli-deployment) + - [Validation and what-if](#validation-and-what-if) + - [Custom bulk deployment examples](#custom-bulk-deployment-examples) +- [Troubleshooting](#troubleshooting) +- [Security considerations](#security-considerations) +- [Technical notes](#technical-notes) + +## Overview + +### What's included + +- `anomaly-alert.bicep` - Bicep template that creates subscription-level scheduled actions for anomaly detection +- `Deploy-AnomalyAlert.ps1` - PowerShell script for individual subscription deployments +- `Deploy-BulkALZ.ps1` - Enterprise-scale bulk deployment script with intelligent pagination +- `anomaly-alert.parameters.json` - Sample parameters file for deployment +- `README.md` - This documentation + +### What gets deployed + +This deployment creates: +- **Cost management scheduled action** - Named "AnomalyAlert" +- **Anomaly detection** - Monitors cost anomalies at the subscription level +- **Email notifications** - Sends alerts to your specified email addresses when anomalies are detected + +## Prerequisites + +1. **Azure PowerShell module** - Install the Az PowerShell module: + ```powershell + Install-Module -Name Az -Force -AllowClobber + ``` + +2. **Azure Resource Graph module** (for bulk operations) - Required for querying multiple subscriptions: + ```powershell + Install-Module -Name Az.ResourceGraph -Force -AllowClobber + ``` + +3. **Azure authentication** - Sign in to Azure: + ```powershell + Connect-AzAccount + ``` + +4. **Permissions** - You'll need Contributor or Owner role on target subscriptions. + +## Deployment scripts + +Choose the right script for your deployment scenario: + +### Deploy-AnomalyAlert.ps1 (individual subscriptions) + +**Best for**: Single subscription deployments, CI/CD pipelines, testing environments + +**Key features**: +- Interactive subscription selection +- Parameter validation and error handling +- Email address format validation +- What-if deployment support +- Color-coded logging with timestamps +- Force deployment option for automation +- Quiet mode for clean output +- Detailed help documentation + +### Deploy-BulkALZ.ps1 (enterprise bulk deployment) + +**Best for**: Large-scale enterprise deployments, management group-wide rollouts + +**Key features**: +- Automated deployment across thousands of subscriptions +- Azure Resource Graph integration for subscription discovery +- Management group targeting with intelligent filtering +- **Enterprise-grade pagination** for handling massive subscription sets +- **Automatic page size optimization** (1000 subscriptions per query) +- **Progressive discovery** with real-time progress reporting +- Performance optimization with quiet deployment mode +- Built-in error handling and rollback safety +- Confirmation prompts for enterprise safety + +## Quick start guide + +### Single subscription deployment + +#### Option 1: interactive subscription selection +```powershell +./Deploy-AnomalyAlert.ps1 -EmailRecipients @("admin@company.com", "finance@company.com") -NotificationEmail "alerts@company.com" +``` + +#### Option 2: specify target subscription +```powershell +./Deploy-AnomalyAlert.ps1 -SubscriptionId "12345678-1234-1234-1234-123456789012" -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" +``` + +#### Option 3: what-if preview +```powershell +./Deploy-AnomalyAlert.ps1 -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" -WhatIf +``` + +#### Option 4: automated/silent deployment +```powershell +./Deploy-AnomalyAlert.ps1 -SubscriptionId "12345678-1234-1234-1234-123456789012" -EmailRecipients @("admin@company.com") -NotificationEmail "alerts@company.com" -Force -Quiet +``` + +### Enterprise bulk deployment + +#### Option 1: deploy to management group +```powershell +./Deploy-BulkALZ.ps1 -TenantId "12345678-1234-1234-1234-123456789012" -ManagementGroup "ALZ" -EmailRecipients @("finops@company.com", "alerts@company.com") -NotificationEmail "alerts@company.com" +``` + +#### Option 2: bulk what-if preview +```powershell +./Deploy-BulkALZ.ps1 -TenantId "12345678-1234-1234-1234-123456789012" -ManagementGroup "ALZ" -EmailRecipients @("finops@company.com") -NotificationEmail "alerts@company.com" -WhatIf +``` + +#### Option 3: quiet enterprise deployment +```powershell +./Deploy-BulkALZ.ps1 -TenantId "12345678-1234-1234-1234-123456789012" -ManagementGroup "ALZ" -EmailRecipients @("finops@company.com") -NotificationEmail "alerts@company.com" -Quiet +``` + +## Parameters reference + +### Deploy-AnomalyAlert.ps1 parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `EmailRecipients` | Yes | Array of email addresses that'll receive anomaly notifications | +| `NotificationEmail` | Yes | Primary email address for the anomaly alert system | +| `SubscriptionId` | No | Target subscription ID (if not provided, script prompts for selection) | +| `DeploymentName` | No | Custom deployment name (auto-generated if not provided) | +| `Location` | No | Azure region for deployment metadata (defaults to 'West US') | +| `Force` | No | Skip confirmation prompts | +| `Quiet` | No | Suppress verbose output and enable quiet deployment mode | +| `WhatIf` | No | Preview deployment without making changes | + +### Deploy-BulkALZ.ps1 parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `TenantId` | Yes | Azure tenant ID for authentication | +| `ManagementGroup` | Yes | Management group name to query for subscriptions | +| `EmailRecipients` | Yes | Array of email addresses that'll receive anomaly notifications | +| `NotificationEmail` | Yes | Primary email address for the anomaly alert system | +| `WhatIf` | No | Preview deployment without making changes | +| `Quiet` | No | Suppress Azure PowerShell warnings and enable quiet deployment mode | + +## Enterprise-scale features + +### Pagination system + +The `Deploy-BulkALZ.ps1` script includes intelligent pagination designed for large enterprise environments with thousands of subscriptions. + +#### How pagination works + +The script uses Azure Resource Graph's pagination features to automatically discover and process subscriptions in optimized batches: + +1. **Automatic page size optimization** - Queries subscriptions in batches of 1,000 per page (optimal for Azure Resource Graph performance) +2. **Progressive discovery** - Automatically detects when more subscriptions exist and continues querying +3. **Real-time progress reporting** - Shows current page number and running totals as subscriptions are discovered +4. **Memory efficient** - Processes large subscription sets without overwhelming system memory + +#### Implementation details + +```powershell +# The script automatically handles pagination like this: +$allSubscriptions = @() +$skip = 0 +$pageSize = 1000 + +do { + Write-Host "Querying subscriptions (page $([math]::Floor($skip / $pageSize) + 1))..." -ForegroundColor Gray + + $query = "ResourceContainers | where type =~ 'microsoft.resources/subscriptions' | where properties.state == 'Enabled' | project subscriptionId, name" + + if ($skip -eq 0) { + $pageResults = Search-AzGraph -Query $query -ManagementGroup $managementGroup -First $pageSize + } else { + $pageResults = Search-AzGraph -Query $query -ManagementGroup $managementGroup -First $pageSize -Skip $skip + } + + if ($pageResults) { + $allSubscriptions += $pageResults + $skip += $pageResults.Count + Write-Host "Found $($pageResults.Count) subscriptions in this page (total: $($allSubscriptions.Count))" -ForegroundColor Gray + } + +# Continue if we got a full page (indicating there might be more) +} while ($pageResults -and $pageResults.Count -eq $pageSize) +``` + +### Performance optimization + +#### Sample output for large environments + +``` +Connecting to tenant... +Finding subscriptions in ALZ management group... +Querying subscriptions (page 1)... +Found 1000 subscriptions in this page (total: 1000) +Querying subscriptions (page 2)... +Found 1000 subscriptions in this page (total: 2000) +Querying subscriptions (page 3)... +Found 847 subscriptions in this page (total: 2847) +Total subscriptions found: 2847 +``` + +#### Enterprise environment benefits + +- **Scalability** - Handles environments with 5,000+ subscriptions without performance degradation +- **Reliability** - Prevents timeout issues that can occur when querying large datasets +- **Visibility** - Provides clear progress reporting during the discovery phase +- **Efficiency** - Optimizes network requests by using maximum practical page sizes + +## Advanced usage + +### Azure CLI deployment + +Deploy using Azure CLI with the parameters file: + +```bash +az deployment sub create \ + --name "anomaly-alert-deployment" \ + --location "West US" \ + --template-file "anomaly-alert.bicep" \ + --parameters "@anomaly-alert.parameters.json" +``` + +Or using Azure PowerShell with parameters file: + +```powershell +New-AzSubscriptionDeployment -Name "anomaly-alert-deployment" -Location "West US" -TemplateFile "anomaly-alert.bicep" -TemplateParameterFile "anomaly-alert.parameters.json" +``` + +### Validation and what-if + +Before deploying, validate your template using these commands: + +#### Azure CLI validation +```bash +az deployment sub validate \ + --location "West US" \ + --template-file "anomaly-alert.bicep" \ + --parameters "@anomaly-alert.parameters.json" +``` + +#### Azure PowerShell validation +```powershell +Test-AzSubscriptionDeployment -Location "West US" -TemplateFile "anomaly-alert.bicep" -TemplateParameterFile "anomaly-alert.parameters.json" +``` + +#### What-if analysis (Azure CLI) +```bash +az deployment sub what-if \ + --location "West US" \ + --template-file "anomaly-alert.bicep" \ + --parameters "@anomaly-alert.parameters.json" +``` + +#### What-if analysis (Azure PowerShell) +```powershell +New-AzSubscriptionDeployment -Name "anomaly-alert-whatif" -Location "West US" -TemplateFile "anomaly-alert.bicep" -TemplateParameterFile "anomaly-alert.parameters.json" -WhatIf +``` + +### Custom bulk deployment examples + +#### Example 1: deploy to all subscriptions in a management group + +```powershell +# Set your management group name +$managementGroupName = "Production" +$emailRecipients = @("finops@company.com", "alerts@company.com") +$notificationEmail = "alerts@company.com" + +# Query subscriptions in the management group +$subscriptions = Search-AzGraph -Query "ResourceContainers | where type =~ 'microsoft.resources/subscriptions' | project subscriptionId, name" -ManagementGroup $managementGroupName + +Write-Host "Found $($subscriptions.Count) subscriptions in management group '$managementGroupName'" + +# Deploy to each subscription +foreach ($sub in $subscriptions) { + try { + Write-Host "Deploying anomaly alert to: $($sub.name) ($($sub.subscriptionId))" -ForegroundColor Cyan + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients $emailRecipients -NotificationEmail $notificationEmail -Force + Write-Host "✅ Successfully deployed to $($sub.name)" -ForegroundColor Green + } + catch { + Write-Host "❌ Failed to deploy to $($sub.name): $($_.Exception.Message)" -ForegroundColor Red + } +} +``` + +#### Example 2: deploy to filtered subscriptions + +```powershell +# Deploy only to production subscriptions (filtering by name pattern) +$emailRecipients = @("finops@company.com") +$notificationEmail = "alerts@company.com" + +# Query subscriptions with name filtering +$subscriptions = Search-AzGraph -Query "ResourceContainers | where type =~ 'microsoft.resources/subscriptions' | where name contains 'Prod' or name contains 'Production' | project subscriptionId, name" + +Write-Host "Found $($subscriptions.Count) production subscriptions" + +foreach ($sub in $subscriptions) { + Write-Host "Deploying to production subscription: $($sub.name)" -ForegroundColor Yellow + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients $emailRecipients -NotificationEmail $notificationEmail -Force +} +``` + +#### Example 3: deploy with what-if validation first + +```powershell +# Validate deployments across multiple subscriptions before actual deployment +$managementGroupName = "Development" +$subscriptions = Search-AzGraph -Query "ResourceContainers | where type =~ 'microsoft.resources/subscriptions' | project subscriptionId, name" -ManagementGroup $managementGroupName + +# First pass: What-if validation +Write-Host "=== VALIDATION PHASE ===" -ForegroundColor Magenta +foreach ($sub in $subscriptions) { + Write-Host "Validating deployment for: $($sub.name)" -ForegroundColor Cyan + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients @("test@company.com") -NotificationEmail "test@company.com" -WhatIf +} + +# Prompt for confirmation +$confirm = Read-Host "Do you want to proceed with actual deployment? (y/N)" +if ($confirm -eq 'y' -or $confirm -eq 'Y') { + Write-Host "=== DEPLOYMENT PHASE ===" -ForegroundColor Magenta + foreach ($sub in $subscriptions) { + ./Deploy-AnomalyAlert.ps1 -SubscriptionId $sub.subscriptionId -EmailRecipients @("alerts@company.com") -NotificationEmail "alerts@company.com" -Force + } +} +``` + +#### Azure Resource Graph query reference + +Here are useful Azure Resource Graph queries for subscription discovery: + +| Query purpose | KQL query | +|---------------|-----------| +| All accessible subscriptions | `ResourceContainers \| where type =~ 'microsoft.resources/subscriptions' \| project subscriptionId, name` | +| Subscriptions in a management group | Use `-ManagementGroup` parameter with the above query | +| Subscriptions with name filter | `ResourceContainers \| where type =~ 'microsoft.resources/subscriptions' \| where name contains 'keyword' \| project subscriptionId, name` | +| Enabled subscriptions only | `ResourceContainers \| where type =~ 'microsoft.resources/subscriptions' \| where properties.state == 'Enabled' \| project subscriptionId, name` | + +**Pagination note**: Azure Resource Graph returns a maximum of 1,000 results per query. The `Deploy-BulkALZ.ps1` script automatically handles this by implementing pagination with the `-First` and `-Skip` parameters. Manual queries may need pagination for large result sets: + +```powershell +# Example of manual pagination +$allResults = @() +$skip = 0 +$pageSize = 1000 + +do { + $pageResults = Search-AzGraph -Query $query -First $pageSize -Skip $skip + $allResults += $pageResults + $skip += $pageResults.Count +} while ($pageResults.Count -eq $pageSize) +``` + +## Troubleshooting + +### Common issues and solutions + +1. **Permission errors** - Ensure you have Contributor or Owner role on the target subscription +2. **Authentication issues** - Run `Connect-AzAccount` and verify you're signed into the correct tenant +3. **Module not found** - Install the Azure PowerShell module: `Install-Module -Name Az` +4. **Location conflicts** - If you get an "Invalid deployment location" error, the subscription may already have an anomaly alert in a different region. The scripts default to "West US" which works for most cases. +5. **Template validation errors** - Ensure the Bicep template includes `targetScope = 'subscription'` for subscription-level deployments +6. **Resource Graph module missing** - For bulk operations, install: `Install-Module -Name Az.ResourceGraph` +7. **Management group access** - Ensure you have Reader role or higher on management groups when using `-ManagementGroup` parameter +8. **Query timeout** - Large management groups may cause query timeouts; the pagination system automatically handles this by processing subscriptions in batches of 1,000 +9. **Memory usage** - The pagination system efficiently manages memory when processing thousands of subscriptions +10. **Azure Resource Graph limits** - The script respects Azure Resource Graph's rate limits and pagination requirements automatically +11. **Rate limiting** - Azure Resource Manager may throttle requests during bulk deployments; add delays between deployments if needed +12. **Existing anomaly alerts** - Subscriptions may already have anomaly alerts configured; the script will update existing ones +13. **Verbose output issues** - Use the `-Quiet` parameter to suppress verbose Azure PowerShell warnings and deployment monitoring delays + +### Best practices for enterprise deployment + +1. **Test first** - Always use what-if validation or deploy to a test subscription first +2. **Error handling** - Wrap deployments in try-catch blocks to handle failures gracefully +3. **Logging** - Log successful and failed deployments for audit purposes +4. **Use enterprise script for scale** - For deployments involving 100+ subscriptions, use `Deploy-BulkALZ.ps1` which includes automatic pagination +5. **Monitor progress** - The pagination system provides real-time progress updates during subscription discovery +6. **Permissions** - Verify you have appropriate permissions before starting bulk operations +7. **Resource Graph optimization** - The built-in pagination handles Azure Resource Graph's 1,000 result limit automatically +8. **Performance** - Use `-Quiet` parameter for faster deployments without verbose progress output + +### Getting help + +The PowerShell script includes detailed help documentation: + +```powershell +Get-Help ./Deploy-AnomalyAlert.ps1 -Full +``` + +For the bulk script, basic usage is shown with: + +```powershell +Get-Help ./Deploy-BulkALZ.ps1 +``` + +## Security considerations + +- Email addresses are validated for proper format before deployment +- The script uses Azure PowerShell's built-in authentication mechanisms +- No credentials are stored or logged in the script +- All Azure interactions use the authenticated user's permissions + +## Technical notes + +- The Bicep template includes `targetScope = 'subscription'` for proper subscription-level deployment +- The anomaly alert uses the public Bicep registry module `br/public:cost/subscription-scheduled-action:1.0.2` +- Alerts are configured for "InsightAlert" type, which specifically monitors for cost anomalies +- The display name is set to "My anomaly check" but can be customized by modifying the Bicep template +- The scheduled action operates at the subscription level +- Default deployment location is "West US" to avoid conflicts with existing deployments +- Both scripts support email address validation and proper error handling diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.bicep b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.bicep new file mode 100644 index 000000000..2fe00e2cf --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.bicep @@ -0,0 +1,17 @@ +targetScope = 'subscription' + +param emailRecipients array +param notificationEmail string + + +module anomalyAlert 'br/public:cost/subscription-scheduled-action:1.0.2' = { + name: 'anomalyAlert' + scope: subscription() + params: { + name: 'AnomalyAlert' + kind: 'InsightAlert' + displayName: 'Cost anomaly alert' + emailRecipients: emailRecipients + notificationEmail: notificationEmail + } +} diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.parameters.json b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.parameters.json new file mode 100644 index 000000000..9a83cccd1 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/anomaly-alerts/anomaly-alert.parameters.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "emailRecipients": { + "value": [ + "admin@company.com", + "finance@company.com" + ] + }, + "notificationEmail": { + "value": "admin@company.com" + } + } +} diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-Budget.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-Budget.ps1 new file mode 100644 index 000000000..392118481 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-Budget.ps1 @@ -0,0 +1,449 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Deploy budget configuration to an Azure subscription. + +.DESCRIPTION + This script deploys the budget Bicep template to create a subscription-level + cost budget with notification thresholds. The script handles subscription + validation, parameter collection, and deployment with proper error handling. + +.PARAMETER SubscriptionId + The target Azure subscription ID where the budget will be deployed. + If not provided, the script will prompt for selection from available subscriptions. + +.PARAMETER BudgetName + Name of the budget. Defaults to 'SubscriptionBudget'. + +.PARAMETER Amount + The total budget amount in the billing currency. Defaults to 1000. + +.PARAMETER TimeGrain + Budget reset period: Monthly, Quarterly, or Annually. Defaults to Monthly. + +.PARAMETER StartDate + Budget start date in YYYY-MM-DD format. Must be first of month. + Defaults to first of next month. + +.PARAMETER EndDate + Budget end date in YYYY-MM-DD format. Defaults to one year from start date. + +.PARAMETER ContactEmails + Array of email addresses that'll receive budget notifications. + +.PARAMETER ContactRoles + Array of Azure roles to notify. Defaults to Owner and Contributor. + +.PARAMETER FirstThreshold + First notification threshold percentage. Defaults to 50. + +.PARAMETER SecondThreshold + Second notification threshold percentage. Defaults to 75. + +.PARAMETER ThirdThreshold + Third notification threshold percentage. Defaults to 90. + +.PARAMETER ForecastedThreshold + Forecasted cost notification threshold percentage. Defaults to 100. + +.PARAMETER DeploymentName + Optional custom name for the deployment. If not provided, a timestamped name will be generated. + +.PARAMETER Location + Azure region for the deployment. Defaults to 'West US'. + +.PARAMETER Force + Skip confirmation prompts and proceed with deployment automatically. + +.PARAMETER Quiet + Suppress verbose deployment progress output. + +.EXAMPLE + ./Deploy-Budget.ps1 -ContactEmails @("admin@company.com") -Amount 5000 + + Deploy budget with interactive subscription selection and $5000 monthly budget. + +.EXAMPLE + ./Deploy-Budget.ps1 -SubscriptionId "12345678-1234-1234-1234-123456789012" -ContactEmails @("admin@company.com") -Amount 10000 -TimeGrain Quarterly -WhatIf + + Preview quarterly budget deployment without making changes. + +.EXAMPLE + ./Deploy-Budget.ps1 -ContactEmails @("admin@company.com") -Amount 2000 -Force + + Deploy without confirmation prompts. + +.NOTES + - Requires Azure PowerShell module (Az) + - User must be authenticated to Azure (Connect-AzAccount) + - User must have appropriate permissions to create subscription-level resources + - Start date must be the first of the month +#> + +[CmdletBinding(SupportsShouldProcess)] +param( + [Parameter(Mandatory = $false)] + [ValidatePattern('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$')] + [string]$SubscriptionId, + + [Parameter(Mandatory = $false)] + [string]$BudgetName = 'SubscriptionBudget', + + [Parameter(Mandatory = $false)] + [ValidateRange(1, [int]::MaxValue)] + [int]$Amount, + + [Parameter(Mandatory = $false)] + [ValidateSet('Monthly', 'Quarterly', 'Annually')] + [string]$TimeGrain = 'Monthly', + + [Parameter(Mandatory = $false)] + [string]$StartDate, + + [Parameter(Mandatory = $false)] + [string]$EndDate, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string[]]$ContactEmails, + + [Parameter(Mandatory = $false)] + [string[]]$ContactRoles = @('Owner', 'Contributor'), + + [Parameter(Mandatory = $false)] + [ValidateRange(1, 1000)] + [int]$FirstThreshold = 50, + + [Parameter(Mandatory = $false)] + [ValidateRange(1, 1000)] + [int]$SecondThreshold = 75, + + [Parameter(Mandatory = $false)] + [ValidateRange(1, 1000)] + [int]$ThirdThreshold = 90, + + [Parameter(Mandatory = $false)] + [ValidateRange(1, 1000)] + [int]$ForecastedThreshold = 100, + + [Parameter(Mandatory = $false)] + [string]$DeploymentName, + + [Parameter(Mandatory = $false)] + [string]$Location = 'West US', + + [Parameter(Mandatory = $false)] + [switch]$Force, + + [Parameter(Mandatory = $false)] + [switch]$Quiet +) + +#region Helper Functions + +function Write-Log { + param( + [string]$Message, + [ValidateSet('Info', 'Warning', 'Error', 'Success')] + [string]$Level = 'Info' + ) + + $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' + $colors = @{ + 'Info' = 'White' + 'Warning' = 'Yellow' + 'Error' = 'Red' + 'Success' = 'Green' + } + + Write-Host "[$timestamp] " -NoNewline -ForegroundColor Gray + Write-Host $Message -ForegroundColor $colors[$Level] +} + +function Test-AzureConnection { + try { + $context = Get-AzContext + if (-not $context) { + return $false + } + return $true + } + catch { + return $false + } +} + +function Get-SubscriptionSelection { + param([string]$TargetSubscriptionId) + + try { + $subscriptions = Get-AzSubscription | Sort-Object Name + + if ($subscriptions.Count -eq 0) { + throw "No subscriptions found. Check if you are logged in with the correct Azure account." + } + + if ($TargetSubscriptionId) { + $selectedSub = $subscriptions | Where-Object { $_.Id -eq $TargetSubscriptionId } + if (-not $selectedSub) { + throw "Subscription with ID '$TargetSubscriptionId' not found or not accessible." + } + return $selectedSub + } + + if ($subscriptions.Count -eq 1) { + Write-Log "Using the only available subscription: $($subscriptions[0].Name)" -Level Info + return $subscriptions[0] + } + + Write-Log "Multiple subscriptions found. Please select:" -Level Info + for ($i = 0; $i -lt $subscriptions.Count; $i++) { + Write-Host " [$i] $($subscriptions[$i].Name) ($($subscriptions[$i].Id))" + } + + do { + $selection = Read-Host "Enter subscription number [0-$($subscriptions.Count - 1)]" + $selectionIndex = $null + if ([int]::TryParse($selection, [ref]$selectionIndex) -and + $selectionIndex -ge 0 -and $selectionIndex -lt $subscriptions.Count) { + return $subscriptions[$selectionIndex] + } + Write-Log "Invalid selection. Please enter a number between 0 and $($subscriptions.Count - 1)." -Level Warning + } while ($true) + } + catch { + throw "Failed to get subscription information: $($_.Exception.Message)" + } +} + +function Get-DefaultStartDate { + # Returns first of next month in YYYY-MM-DD format + $today = Get-Date + $nextMonth = $today.AddMonths(1) + $firstOfMonth = Get-Date -Year $nextMonth.Year -Month $nextMonth.Month -Day 1 + return $firstOfMonth.ToString('yyyy-MM-dd') +} + +function Get-DefaultEndDate { + param([string]$StartDate) + # Returns one year from start date + $start = [DateTime]::Parse($StartDate) + $end = $start.AddYears(1) + return $end.ToString('yyyy-MM-dd') +} + +function Confirm-Deployment { + param( + [object]$Subscription, + [string]$BudgetName, + [int]$Amount, + [string]$TimeGrain, + [string]$StartDate, + [string]$EndDate, + [string[]]$ContactEmails, + [string]$DeploymentName + ) + + if ($Force) { + return $true + } + + Write-Host "" + Write-Log "Deployment summary:" -Level Info + Write-Host " Subscription: $($Subscription.Name) ($($Subscription.Id))" + Write-Host " Budget name: $BudgetName" + Write-Host " Amount: $Amount ($TimeGrain)" + Write-Host " Period: $StartDate to $EndDate" + Write-Host " Email recipients: $($ContactEmails -join ', ')" + Write-Host " Deployment name: $DeploymentName" + Write-Host "" + + $confirmation = Read-Host "Do you want to proceed with this deployment? (y/N)" + return ($confirmation -eq 'y' -or $confirmation -eq 'Y') +} + +#endregion + +#region Main Script + +try { + Write-Log "Starting budget deployment script..." -Level Info + + # Check if Azure PowerShell is available + if (-not (Get-Module -Name Az.Accounts -ListAvailable)) { + throw "Azure PowerShell module (Az) isn't installed. Please install it using: Install-Module -Name Az" + } + + # Check Azure connection + if (-not (Test-AzureConnection)) { + Write-Log "Not connected to Azure. Please run 'Connect-AzAccount' first." -Level Error + throw "Azure authentication required" + } + + Write-Log "Azure connection verified." -Level Success + + # Get target subscription + $targetSubscription = Get-SubscriptionSelection -TargetSubscriptionId $SubscriptionId + Write-Log "Selected subscription: $($targetSubscription.Name)" -Level Success + + # Set the subscription context + $null = Set-AzContext -SubscriptionId $targetSubscription.Id + + # Determine budget amount: explicit parameter > BudgetAmount tag > default ($10) + $defaultAmount = 10 + if ($PSBoundParameters.ContainsKey('Amount')) { + Write-Log "Using explicitly provided amount: $Amount" -Level Info + } else { + # Check for BudgetAmount tag on subscription (must use Get-AzTag, not Get-AzSubscription) + $tagValue = $null + try { + $subscriptionResourceId = "/subscriptions/$($targetSubscription.Id)" + $tags = Get-AzTag -ResourceId $subscriptionResourceId -ErrorAction SilentlyContinue + if ($tags -and $tags.Properties -and $tags.Properties.TagsProperty) { + $tagValue = $tags.Properties.TagsProperty['BudgetAmount'] + } + } catch { + Write-Log "Could not retrieve subscription tags: $($_.Exception.Message)" -Level Warning + } + + if ($tagValue) { + $parsedAmount = 0 + if ([int]::TryParse($tagValue, [ref]$parsedAmount) -and $parsedAmount -gt 0) { + $Amount = $parsedAmount + Write-Log "Using BudgetAmount tag value: $Amount" -Level Info + } else { + Write-Log "Invalid BudgetAmount tag value '$tagValue', using default: $defaultAmount" -Level Warning + $Amount = $defaultAmount + } + } else { + $Amount = $defaultAmount + Write-Log "No BudgetAmount tag found, using default: $Amount" -Level Info + } + } + + # Set default dates if not provided + if (-not $StartDate) { + $StartDate = Get-DefaultStartDate + Write-Log "Using default start date: $StartDate" -Level Info + } + + if (-not $EndDate) { + $EndDate = Get-DefaultEndDate -StartDate $StartDate + Write-Log "Using default end date: $EndDate" -Level Info + } + + # Validate start date is first of month + $startDateParsed = [DateTime]::Parse($StartDate) + if ($startDateParsed.Day -ne 1) { + throw "Start date must be the first of the month. Got: $StartDate" + } + + # Generate deployment name if not provided + if (-not $DeploymentName) { + $timestamp = Get-Date -Format "yyyyMMddHHmmss" + $DeploymentName = "budget-$timestamp" + } + + # Get the script directory and template path + $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + $templateFile = Join-Path $scriptDir "budget.bicep" + + # Verify template file exists + if (-not (Test-Path $templateFile)) { + throw "Bicep template file not found: $templateFile" + } + + Write-Log "Template file found: $templateFile" -Level Success + + # Validate email addresses + $emailRegex = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' + foreach ($email in $ContactEmails) { + if ($email -notmatch $emailRegex) { + throw "Invalid email address format: $email" + } + } + + Write-Log "Email addresses validated." -Level Success + + # Prepare deployment parameters + $deploymentParams = @{ + budgetName = $BudgetName + amount = $Amount + timeGrain = $TimeGrain + startDate = $StartDate + endDate = $EndDate + contactEmails = $ContactEmails + contactRoles = $ContactRoles + firstThreshold = $FirstThreshold + secondThreshold = $SecondThreshold + thirdThreshold = $ThirdThreshold + forecastedThreshold = $ForecastedThreshold + } + + # Show deployment summary and get confirmation + if (-not (Confirm-Deployment -Subscription $targetSubscription -BudgetName $BudgetName -Amount $Amount -TimeGrain $TimeGrain -StartDate $StartDate -EndDate $EndDate -ContactEmails $ContactEmails -DeploymentName $DeploymentName)) { + Write-Log "Deployment cancelled by user." -Level Warning + return + } + + # Prepare deployment splat + $deploymentSplat = @{ + Name = $DeploymentName + Location = $Location + TemplateFile = $templateFile + TemplateParameterObject = $deploymentParams + } + + if ($WhatIfPreference) { + Write-Log "Running deployment validation (What-If)..." -Level Info + + # Run What-If deployment preview + if ($Quiet) { + $whatIfResult = New-AzSubscriptionDeployment @deploymentSplat -WhatIf -WhatIfResultFormat FullResourcePayloads 2>&1 + } else { + $whatIfResult = New-AzSubscriptionDeployment @deploymentSplat -WhatIf -WhatIfResultFormat FullResourcePayloads -Verbose 2>&1 + } + + Write-Host $whatIfResult + Write-Log "What-If operation completed." -Level Success + } else { + Write-Log "Starting deployment..." -Level Info + + # Execute actual deployment + if ($Quiet) { + $deployment = New-AzSubscriptionDeployment @deploymentSplat + } else { + $deployment = New-AzSubscriptionDeployment @deploymentSplat -Verbose + } + + if ($deployment.ProvisioningState -eq 'Succeeded') { + Write-Log "Deployment completed successfully!" -Level Success + Write-Host "" + Write-Log "Deployment details:" -Level Info + Write-Host " Deployment name: $($deployment.DeploymentName)" + Write-Host " Budget name: $BudgetName" + Write-Host " Amount: $Amount ($TimeGrain)" + Write-Host " Status: $($deployment.ProvisioningState)" + Write-Host " Timestamp: $($deployment.Timestamp)" + Write-Host "" + Write-Log "Budget has been configured and will monitor costs for this subscription." -Level Info + Write-Log "Notifications will be sent to: $($ContactEmails -join ', ')" -Level Info + } else { + Write-Log "Deployment failed with status: $($deployment.ProvisioningState)" -Level Error + if ($deployment.Error) { + Write-Log "Error details: $($deployment.Error.Message)" -Level Error + } + throw "Deployment failed" + } + } +} +catch { + Write-Log "Script execution failed: $($_.Exception.Message)" -Level Error + Write-Log "Stack trace: $($_.ScriptStackTrace)" -Level Error + exit 1 +} +finally { + Write-Log "Script execution completed." -Level Info +} + +#endregion diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-BulkBudgets.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-BulkBudgets.ps1 new file mode 100644 index 000000000..cdf9238bf --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/Deploy-BulkBudgets.ps1 @@ -0,0 +1,257 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + Deploy budgets to all subscriptions in a management group. + +.DESCRIPTION + Deploy budgets to all subscriptions in the specified management group with + intelligent pagination support for large enterprise environments. The script uses + Azure Resource Graph to discover subscriptions and deploys budgets in batches. + Assumes user is already authenticated via Connect-AzAccount. + +.PARAMETER ManagementGroup + Management group name to query for subscriptions. + +.PARAMETER ContactEmails + Array of email addresses that'll receive budget notifications. + +.PARAMETER BudgetName + Name of the budget. Defaults to 'SubscriptionBudget'. + +.PARAMETER Amount + The total budget amount in the billing currency. Defaults to 1000. + +.PARAMETER TimeGrain + Budget reset period: Monthly, Quarterly, or Annually. Defaults to Monthly. + +.PARAMETER StartDate + Budget start date in YYYY-MM-DD format. Must be first of month. + Defaults to first of next month. + +.PARAMETER EndDate + Budget end date in YYYY-MM-DD format. Defaults to one year from start date. + +.PARAMETER WhatIf + Preview changes without deploying. + +.PARAMETER Quiet + Suppress Azure PowerShell warning messages for cleaner output. + +.EXAMPLE + ./Deploy-BulkBudgets.ps1 -ManagementGroup "ALZ" -ContactEmails @("admin@company.com") -Amount 5000 + + Deploy $5000 monthly budgets to all subscriptions in the ALZ management group. + +.EXAMPLE + ./Deploy-BulkBudgets.ps1 -ManagementGroup "ALZ" -ContactEmails @("admin@company.com") -Amount 10000 -TimeGrain Quarterly -WhatIf + + Preview quarterly budget deployment without making actual changes. + +.EXAMPLE + ./Deploy-BulkBudgets.ps1 -ManagementGroup "ALZ" -ContactEmails @("admin@company.com") -Quiet + + Deploy with minimal output for automated scenarios (uses BudgetAmount tag or $10 default). + +.NOTES + - Requires Azure PowerShell and Azure Resource Graph modules + - Supports intelligent pagination for thousands of subscriptions + - Automatically handles Azure Resource Graph's 1,000 result limit + - User must have appropriate permissions across target subscriptions +#> + +param( + [Parameter(Mandatory=$true)] + [string]$ManagementGroup, + + [Parameter(Mandatory=$true)] + [string[]]$ContactEmails, + + [Parameter(Mandatory=$false)] + [string]$BudgetName = 'SubscriptionBudget', + + [Parameter(Mandatory=$false)] + [ValidateRange(1, [int]::MaxValue)] + [int]$Amount, + + [Parameter(Mandatory=$false)] + [ValidateSet('Monthly', 'Quarterly', 'Annually')] + [string]$TimeGrain = 'Monthly', + + [Parameter(Mandatory=$false)] + [string]$StartDate, + + [Parameter(Mandatory=$false)] + [string]$EndDate, + + [Parameter(Mandatory=$false)] + [string[]]$ContactRoles = @('Owner', 'Contributor'), + + [Parameter(Mandatory=$false)] + [ValidateRange(1, 1000)] + [int]$FirstThreshold = 50, + + [Parameter(Mandatory=$false)] + [ValidateRange(1, 1000)] + [int]$SecondThreshold = 75, + + [Parameter(Mandatory=$false)] + [ValidateRange(1, 1000)] + [int]$ThirdThreshold = 90, + + [Parameter(Mandatory=$false)] + [ValidateRange(1, 1000)] + [int]$ForecastedThreshold = 100, + + [switch]$WhatIf, + + [switch]$Quiet, + + [switch]$Force +) + +# Set default dates if not provided +if (-not $StartDate) { + $today = Get-Date + $nextMonth = $today.AddMonths(1) + $firstOfMonth = Get-Date -Year $nextMonth.Year -Month $nextMonth.Month -Day 1 + $StartDate = $firstOfMonth.ToString('yyyy-MM-dd') +} + +if (-not $EndDate) { + $start = [DateTime]::Parse($StartDate) + $EndDate = $start.AddYears(1).ToString('yyyy-MM-dd') +} + +Write-Host "=== Bulk budget deployment ===" -ForegroundColor Cyan +Write-Host "Target: $ManagementGroup management group" -ForegroundColor Yellow +if ($PSBoundParameters.ContainsKey('Amount')) { + Write-Host "Budget: $Amount ($TimeGrain) - explicit override" -ForegroundColor Yellow +} else { + Write-Host "Budget: Per-subscription BudgetAmount tag, default `$10 ($TimeGrain)" -ForegroundColor Yellow +} +Write-Host "Period: $StartDate to $EndDate" -ForegroundColor Yellow +Write-Host "Mode: $(if ($WhatIf) { 'What-if (preview)' } else { 'Deploy' })" -ForegroundColor Yellow + +# Suppress Azure PowerShell warnings if Quiet mode is enabled +if ($Quiet) { + $WarningPreference = 'SilentlyContinue' +} + +# Verify Azure connection (assume already logged in) +$context = Get-AzContext +if (-not $context) { + Write-Host "Not connected to Azure. Please run 'Connect-AzAccount' first." -ForegroundColor Red + exit 1 +} + +# Get subscriptions +Write-Host "Finding subscriptions in $ManagementGroup management group..." -ForegroundColor Yellow + +# Handle pagination for large result sets +$allSubscriptions = @() +$skip = 0 +$pageSize = 1000 + +do { + Write-Host "Querying subscriptions (page $([math]::Floor($skip / $pageSize) + 1))..." -ForegroundColor Gray + + $query = "ResourceContainers | where type =~ 'microsoft.resources/subscriptions' | where properties.state == 'Enabled' | project subscriptionId, name" + + if ($skip -eq 0) { + $pageResults = Search-AzGraph -Query $query -ManagementGroup $ManagementGroup -First $pageSize + } else { + $pageResults = Search-AzGraph -Query $query -ManagementGroup $ManagementGroup -First $pageSize -Skip $skip + } + + if ($pageResults) { + $allSubscriptions += $pageResults + $skip += $pageResults.Count + Write-Host "Found $($pageResults.Count) subscriptions in this page (total: $($allSubscriptions.Count))" -ForegroundColor Gray + } + + # Continue if we got a full page (indicating there might be more) +} while ($pageResults -and $pageResults.Count -eq $pageSize) + +$subscriptions = $allSubscriptions +Write-Host "Total subscriptions found: $($subscriptions.Count)" -ForegroundColor Green + +if (!$subscriptions -or $subscriptions.Count -eq 0) { + Write-Host "No subscriptions found!" -ForegroundColor Red + exit 1 +} + +Write-Host "Subscriptions to deploy to:" -ForegroundColor Green +foreach ($sub in $subscriptions | Select-Object -First 10) { + Write-Host " - $($sub.name)" -ForegroundColor White +} + +if ($subscriptions.Count -gt 10) { + Write-Host " ... and $($subscriptions.Count - 10) more" -ForegroundColor Gray +} + +# Confirm deployment +if (!$WhatIf -and !$Force) { + Write-Host "" + $confirm = Read-Host "Deploy to all subscriptions? (y/N)" + if ($confirm -ne 'y' -and $confirm -ne 'Y') { + Write-Host "Cancelled." -ForegroundColor Yellow + exit 0 + } +} + +# Deploy to each subscription +Write-Host "" +Write-Host "Starting deployment..." -ForegroundColor Green + +$successCount = 0 +$failCount = 0 + +foreach ($sub in $subscriptions) { + Write-Host "Deploying to: $($sub.name)" -ForegroundColor Cyan + + try { + $deployParams = @{ + SubscriptionId = $sub.subscriptionId + BudgetName = $BudgetName + TimeGrain = $TimeGrain + StartDate = $StartDate + EndDate = $EndDate + ContactEmails = $ContactEmails + ContactRoles = $ContactRoles + FirstThreshold = $FirstThreshold + SecondThreshold = $SecondThreshold + ThirdThreshold = $ThirdThreshold + ForecastedThreshold = $ForecastedThreshold + Force = $true + Quiet = $true + } + + # Only pass Amount if explicitly provided; otherwise let Deploy-Budget.ps1 use tag/default + if ($PSBoundParameters.ContainsKey('Amount')) { + $deployParams.Add('Amount', $Amount) + } + + if ($WhatIf) { + $deployParams.Add('WhatIf', $true) + } + + if ($Quiet) { + & "$PSScriptRoot/Deploy-Budget.ps1" @deployParams -WarningAction SilentlyContinue + } else { + & "$PSScriptRoot/Deploy-Budget.ps1" @deployParams + } + + Write-Host "✅ Success: $($sub.name)" -ForegroundColor Green + $successCount++ + } + catch { + Write-Host "❌ Failed: $($sub.name) - $($_.Exception.Message)" -ForegroundColor Red + $failCount++ + } +} + +Write-Host "" +Write-Host "Deployment complete!" -ForegroundColor Green +Write-Host " Succeeded: $successCount" -ForegroundColor Green +Write-Host " Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { 'Red' } else { 'Green' }) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/README.md new file mode 100644 index 000000000..a71468d49 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/README.md @@ -0,0 +1,152 @@ +# Azure subscription budget deployment + +Deploy cost budgets to Azure subscriptions with automatic tag-based amount configuration. + +## Overview + +These scripts deploy `Microsoft.Consumption/budgets` resources to Azure subscriptions with configurable notification thresholds. Budget amounts can be set per-subscription using the `BudgetAmount` tag, allowing different spending limits across your environment. + +## Budget amount priority + +1. **Explicit parameter** - If `-Amount` is provided, that value is used +2. **Subscription tag** - If the subscription has a `BudgetAmount` tag, that value is used +3. **Default** - Falls back to $10/month + +## Prerequisites + +- Azure PowerShell module (`Az`) +- Azure Resource Graph module (`Az.ResourceGraph`) - for bulk deployments +- Authenticated to Azure (`Connect-AzAccount`) +- Appropriate permissions to create subscription-level resources + +## Scripts + +### Deploy-Budget.ps1 + +Deploy a budget to a single subscription. + +```powershell +# Interactive - prompts for subscription selection +./Deploy-Budget.ps1 -ContactEmails "admin@company.com" + +# Specific subscription +./Deploy-Budget.ps1 -SubscriptionId "12345678-1234-1234-1234-123456789012" -ContactEmails "admin@company.com" + +# Override the tag/default amount +./Deploy-Budget.ps1 -ContactEmails "admin@company.com" -Amount 5000 + +# Preview without deploying +./Deploy-Budget.ps1 -ContactEmails "admin@company.com" -WhatIf + +# Skip confirmation prompt +./Deploy-Budget.ps1 -ContactEmails "admin@company.com" -Force +``` + +#### Parameters + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `-SubscriptionId` | No | Interactive | Target subscription GUID | +| `-ContactEmails` | Yes | - | Email addresses for notifications | +| `-Amount` | No | Tag or $10 | Budget amount (overrides tag) | +| `-BudgetName` | No | `SubscriptionBudget` | Name of the budget resource | +| `-TimeGrain` | No | `Monthly` | Reset period: Monthly, Quarterly, Annually | +| `-StartDate` | No | 1st of next month | Budget start date (YYYY-MM-DD) | +| `-EndDate` | No | 1 year from start | Budget end date (YYYY-MM-DD) | +| `-ContactRoles` | No | Owner, Contributor | Azure roles to notify | +| `-FirstThreshold` | No | 50 | First notification threshold % | +| `-SecondThreshold` | No | 75 | Second notification threshold % | +| `-ThirdThreshold` | No | 90 | Third notification threshold % | +| `-ForecastedThreshold` | No | 100 | Forecasted cost threshold % | +| `-Force` | No | - | Skip confirmation prompt | +| `-Quiet` | No | - | Suppress verbose output | +| `-WhatIf` | No | - | Preview without deploying | + +### Deploy-BulkBudgets.ps1 + +Deploy budgets to all subscriptions in a management group. + +```powershell +# Deploy to all subscriptions in management group (uses tag/default per subscription) +./Deploy-BulkBudgets.ps1 -ManagementGroup "ALZ" -ContactEmails "admin@company.com" + +# Override amount for all subscriptions +./Deploy-BulkBudgets.ps1 -ManagementGroup "ALZ" -ContactEmails "admin@company.com" -Amount 5000 + +# Preview without deploying +./Deploy-BulkBudgets.ps1 -ManagementGroup "ALZ" -ContactEmails "admin@company.com" -WhatIf + +# Automated deployment (no prompts, minimal output) +./Deploy-BulkBudgets.ps1 -ManagementGroup "ALZ" -ContactEmails "admin@company.com" -Force -Quiet +``` + +#### Parameters + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `-ManagementGroup` | Yes | - | Management group to query for subscriptions | +| `-ContactEmails` | Yes | - | Email addresses for notifications | +| `-Amount` | No | Per-sub tag or $10 | Budget amount (overrides all tags) | +| `-BudgetName` | No | `SubscriptionBudget` | Name of the budget resource | +| `-TimeGrain` | No | `Monthly` | Reset period: Monthly, Quarterly, Annually | +| `-StartDate` | No | 1st of next month | Budget start date (YYYY-MM-DD) | +| `-EndDate` | No | 1 year from start | Budget end date (YYYY-MM-DD) | +| `-ContactRoles` | No | Owner, Contributor | Azure roles to notify | +| `-FirstThreshold` | No | 50 | First notification threshold % | +| `-SecondThreshold` | No | 75 | Second notification threshold % | +| `-ThirdThreshold` | No | 90 | Third notification threshold % | +| `-ForecastedThreshold` | No | 100 | Forecasted cost threshold % | +| `-Force` | No | - | Skip confirmation prompt | +| `-Quiet` | No | - | Suppress verbose output | +| `-WhatIf` | No | - | Preview without deploying | + +## Setting the BudgetAmount Tag + +Set the `BudgetAmount` tag on subscriptions to control per-subscription budget amounts: + +```powershell +# Set tag on a subscription +Update-AzTag -ResourceId "/subscriptions/" -Tag @{BudgetAmount = "500"} -Operation Merge +``` + +Or via Azure CLI: + +```bash +az tag update --resource-id "/subscriptions/" --operation merge --tags BudgetAmount=500 +``` + +## Notification Thresholds + +By default, notifications are sent when: + +| Threshold | Type | Default | +|-----------|------|---------| +| First | Actual | 50% | +| Second | Actual | 75% | +| Third | Actual | 90% | +| Forecasted | Forecasted | 100% | + +## Examples + +### Enterprise deployment + +```powershell +# Connect to Azure +Connect-AzAccount + +# Preview deployment to production management group +./Deploy-BulkBudgets.ps1 -ManagementGroup "Production" -ContactEmails "finops@company.com","alerts@company.com" -WhatIf + +# Deploy after review +./Deploy-BulkBudgets.ps1 -ManagementGroup "Production" -ContactEmails "finops@company.com","alerts@company.com" -Force +``` + +### Development environment with low budget + +```powershell +# Tag dev subscriptions with low budget +Update-AzTag -ResourceId "/subscriptions/" -Tag @{BudgetAmount = "50"} -Operation Merge + +# Deploy - will use $50 from tag +./Deploy-Budget.ps1 -SubscriptionId "" -ContactEmails "dev-team@company.com" +``` diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.bicep b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.bicep new file mode 100644 index 000000000..f37b6ab6b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.bicep @@ -0,0 +1,89 @@ +targetScope = 'subscription' + +@description('Name of the Budget. It should be unique within the subscription.') +param budgetName string = 'SubscriptionBudget' + +@description('The total amount of cost to track with the budget (in the billing currency). If subscription has BudgetAmount tag, that value is used instead.') +param amount int = 10 + +@description('The time covered by a budget. Tracking of the amount will be reset based on the time grain.') +@allowed([ + 'Monthly' + 'Quarterly' + 'Annually' +]) +param timeGrain string = 'Monthly' + +@description('The start date must be first of the month in YYYY-MM-DD format.') +param startDate string + +@description('The end date for the budget in YYYY-MM-DD format.') +param endDate string + +@description('First threshold percentage. Notification sent when cost exceeds this threshold.') +param firstThreshold int = 50 + +@description('Second threshold percentage. Notification sent when cost exceeds this threshold.') +param secondThreshold int = 75 + +@description('Third threshold percentage. Notification sent when cost exceeds this threshold.') +param thirdThreshold int = 90 + +@description('Forecasted threshold percentage. Notification sent when FORECASTED cost exceeds this threshold.') +param forecastedThreshold int = 100 + +@description('The list of email addresses to send the budget notification to when thresholds are exceeded.') +param contactEmails array + +@description('The list of contact roles to send the budget notification to when the threshold is exceeded.') +param contactRoles array = [ + 'Owner' + 'Contributor' +] + +resource budget 'Microsoft.Consumption/budgets@2023-11-01' = { + name: budgetName + properties: { + timePeriod: { + startDate: startDate + endDate: endDate + } + timeGrain: timeGrain + amount: amount + category: 'Cost' + notifications: { + Notification_FirstThreshold: { + enabled: true + operator: 'GreaterThan' + threshold: firstThreshold + contactEmails: contactEmails + contactRoles: contactRoles + } + Notification_SecondThreshold: { + enabled: true + operator: 'GreaterThan' + threshold: secondThreshold + contactEmails: contactEmails + contactRoles: contactRoles + } + Notification_ThirdThreshold: { + enabled: true + operator: 'GreaterThan' + threshold: thirdThreshold + contactEmails: contactEmails + contactRoles: contactRoles + } + Notification_Forecasted: { + enabled: true + operator: 'GreaterThan' + threshold: forecastedThreshold + thresholdType: 'Forecasted' + contactEmails: contactEmails + contactRoles: contactRoles + } + } + } +} + +output name string = budget.name +output resourceId string = budget.id diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.parameters.json b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.parameters.json new file mode 100644 index 000000000..fbc2d154b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/budgets/budget.parameters.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "budgetName": { + "value": "SubscriptionBudget" + }, + "amount": { + "value": 10 + }, + "timeGrain": { + "value": "Monthly" + }, + "startDate": { + "value": "2026-02-01" + }, + "endDate": { + "value": "2027-02-01" + }, + "firstThreshold": { + "value": 50 + }, + "secondThreshold": { + "value": 75 + }, + "thirdThreshold": { + "value": 90 + }, + "forecastedThreshold": { + "value": 100 + }, + "contactEmails": { + "value": [ + "admin@company.com", + "finance@company.com" + ] + }, + "contactRoles": { + "value": [ + "Owner", + "Contributor" + ] + } + } +} diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/README.md new file mode 100644 index 000000000..75c0808c5 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/README.md @@ -0,0 +1,219 @@ +# LLM-optimized calculator + +A Python calculator script using **SymPy** for safe evaluation of mathematical expressions from string input—perfect for LLM usage. + +## Why SymPy (not NumPy)? + +- **String parsing**: Accepts natural math expressions as strings +- **Safe evaluation**: Safer than Python's `eval()`, designed for untrusted input +- **Symbolic + numeric**: Handles exact symbolic math and floating-point evaluation +- **Rich functions**: Built-in support for sqrt, sin, cos, log, factorial, etc. +- **Multiple formats**: Can parse LaTeX, natural math syntax, implicit multiplication + +NumPy is for array/matrix operations, not parsing calculator-style string expressions. + +## Installation + +```bash +pip install sympy +# or use the requirements file +pip install -r calculator-requirements.txt +``` + +## Usage + +### Basic arithmetic +```bash +python3 calculator.py "2 + 2" # 4.00000000000000 +python3 calculator.py "10 * 5 + 3" # 53.0000000000000 +python3 calculator.py "100 / 4" # 25.0000000000000 +``` + +### Exponentiation (use ^ or **) +```bash +python3 calculator.py "2^8" # 256.000000000000 +python3 calculator.py "3**4" # 81.0000000000000 +python3 calculator.py "sqrt(16) + 3^2" # 13.0000000000000 +``` + +### Mathematical functions +```bash +python3 calculator.py "sin(pi/2)" # 1.00000000000000 +python3 calculator.py "cos(pi)" # -1.00000000000000 +python3 calculator.py "tan(pi/4)" # 1.00000000000000 +python3 calculator.py "log(100, 10)" # 2.00000000000000 (log base 10) +python3 calculator.py "ln(e^2)" # 2.00000000000000 (natural log) +python3 calculator.py "factorial(5)" # 120.000000000000 +python3 calculator.py "sqrt(144)" # 12.0000000000000 +python3 calculator.py "abs(-42)" # 42.0000000000000 +``` + +### Symbolic expressions +```bash +python3 calculator.py "x^2 + 2*x + 1" --symbolic # x**2 + 2*x + 1 +python3 calculator.py "sin(x) + cos(x)" -s # sin(x) + cos(x) +``` + +### Precision control +```bash +python3 calculator.py "pi" --precision 50 +# 3.1415926535897932384626433832795028841971693993751 +``` + +## LLM integration examples + +### Example 1: calculator tool for an LLM agent +```python +from calculator import calculate + +# LLM generates expression string +llm_output = "sqrt(144) + 5^2" +result = calculate(llm_output) +print(result) # 37.0000000000000 +``` + +### Example 2: safe math evaluation +```python +# User provides input (potentially unsafe) +user_input = "sin(pi/6) * 2" +result = calculate(user_input) +print(result) # 1.00000000000000 +``` + +### Example 3: symbolic manipulation +```python +# Preserve symbolic form +expr = "(x + 1)^2" +result = calculate(expr, symbolic=True) +print(result) # (x + 1)**2 +``` + +## Supported operations + +### Arithmetic +- Addition: `+` +- Subtraction: `-` +- Multiplication: `*` +- Division: `/` +- Exponentiation: `^` or `**` +- Modulo: `%` + +### Functions +- `sqrt(x)` - Square root +- `sin(x)`, `cos(x)`, `tan(x)` - Trigonometric +- `asin(x)`, `acos(x)`, `atan(x)` - Inverse trig +- `log(x, base)` - Logarithm (default base e) +- `ln(x)` - Natural logarithm +- `exp(x)` - Exponential (e^x) +- `factorial(n)` - Factorial +- `abs(x)` - Absolute value + +### Constants +- `pi` - π (3.14159...) +- `e` - Euler's number (2.71828...) +- `oo` - Infinity + +### Implicit multiplication (works automatically) +```bash +python3 calculator.py "2x + 3y" # Requires --symbolic since x,y are variables +python3 calculator.py "2(3 + 4)" # 14.0000000000000 +``` + +## Features + +1. **Safe evaluation**: No arbitrary code execution +2. **Flexible parsing**: Handles `^` for exponents, implicit multiplication +3. **Symbolic and numeric**: Choose between exact symbolic or numeric evaluation +4. **Error handling**: Clear error messages for invalid expressions +5. **High precision**: Configurable decimal precision + +## Command-line options + +- `--symbolic` or `-s`: Return symbolic result (don't evaluate numerically) +- `--precision N` or `-p N`: Set decimal precision (default: 15) + +## Error handling + +```bash +python3 calculator.py "1/0" +# Error: ValueError: Division by zero + +python3 calculator.py "invalid expression" +# Error: SyntaxError: invalid syntax +``` + +## Integration with LLM tools + +### As a function calling tool +```json +{ + "name": "calculate", + "description": "Evaluate mathematical expressions safely", + "parameters": { + "type": "object", + "properties": { + "expression": { + "type": "string", + "description": "Mathematical expression to evaluate (e.g., 'sqrt(16) + 3^2')" + }, + "symbolic": { + "type": "boolean", + "description": "Return symbolic result instead of numeric evaluation" + } + }, + "required": ["expression"] + } +} +``` + +### Python function interface +```python +def calculate(expression: str, symbolic: bool = False, precision: int = 15) -> str: + """ + Evaluate a mathematical expression safely using SymPy. + + Args: + expression: String mathematical expression + symbolic: Return symbolic result if True + precision: Decimal places for numeric evaluation + + Returns: + String representation of the result + """ +``` + +## Advanced examples + +### Complex expressions +```bash +python3 calculator.py "(sin(pi/4))^2 + (cos(pi/4))^2" # 1.00000000000000 +python3 calculator.py "log(1000, 10) + sqrt(144)" # 15.0000000000000 +python3 calculator.py "factorial(6) / factorial(4)" # 30.0000000000000 +``` + +### Scientific notation +```bash +python3 calculator.py "1.5e10 + 2.3e9" # 17300000000.0 +``` + +## Why this design? + +**Optimized for LLM usage:** +- LLMs output strings, not Python objects +- Simple command-line interface +- Clear error messages for debugging +- No eval() security risks +- Handles common mathematical notation naturally +- Symbolic mode for algebraic manipulation + +**SymPy advantages over alternatives:** +- **vs eval()**: Much safer, no arbitrary code execution +- **vs NumPy**: NumPy requires array syntax, doesn't parse strings naturally +- **vs ast.literal_eval()**: Doesn't support mathematical functions +- **vs custom parser**: SymPy has years of battle-testing and edge case handling + +## License + +This calculator is part of the azcapman project. + +**Source**: [SymPy documentation](https://docs.sympy.org/latest/index.html) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/calculator.py b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/calculator.py new file mode 100755 index 000000000..758abedce --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/calculator.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +""" +LLM-Optimized Calculator using SymPy + +A calculator script designed for LLM usage with safe string evaluation, +symbolic mathematics, and comprehensive mathematical operations. + +Usage: + python calculator.py "2 + 2" + python calculator.py "sqrt(16) + 3^2" + python calculator.py "sin(pi/2)" + python calculator.py "x^2 + 2*x + 1" --symbolic +""" + +import sys +from sympy import parse_expr, sympify, symbols, N +from sympy.parsing.sympy_parser import ( + parse_expr, + standard_transformations, + implicit_multiplication_application, + convert_xor, +) + + +def calculate(expression: str, symbolic: bool = False, precision: int = 15) -> str: + """ + Evaluate a mathematical expression safely using SymPy. + + Args: + expression: String mathematical expression (e.g., "2 + 2", "sqrt(16)") + symbolic: If True, return symbolic result; if False, evaluate numerically + precision: Number of decimal places for numeric evaluation + + Returns: + String representation of the result + + Examples: + >>> calculate("2 + 2") + '4' + >>> calculate("sqrt(16) + 3**2") + '13' + >>> calculate("sin(pi/2)") + '1.00000000000000' + >>> calculate("x^2 + 2*x + 1", symbolic=True) + 'x**2 + 2*x + 1' + """ + try: + # Define transformations to make parsing more flexible + transformations = ( + standard_transformations + + (implicit_multiplication_application,) + + (convert_xor,) # Convert ^ to ** for exponentiation + ) + + # Parse the expression with transformations + expr = parse_expr(expression, transformations=transformations) + + if symbolic or expr.free_symbols: + # Return symbolic form if requested or if expression contains variables + return str(expr) + else: + # Evaluate numerically + result = N(expr, precision) + return str(result) + + except Exception as e: + return f"Error: {type(e).__name__}: {str(e)}" + + +def main(): + """Command-line interface for the calculator.""" + if len(sys.argv) < 2: + print(__doc__) + print("\nExamples:") + print(' python calculator.py "2 + 2"') + print(' python calculator.py "sqrt(16) + 3^2"') + print(' python calculator.py "sin(pi/2)"') + print(' python calculator.py "log(100, 10)"') + print(' python calculator.py "factorial(5)"') + print(' python calculator.py "integrate(x^2, x)" --symbolic') + sys.exit(1) + + expression = sys.argv[1] + symbolic = "--symbolic" in sys.argv or "-s" in sys.argv + + # Check for precision flag + precision = 15 + for i, arg in enumerate(sys.argv): + if arg in ["--precision", "-p"] and i + 1 < len(sys.argv): + try: + precision = int(sys.argv[i + 1]) + except ValueError: + print(f"Warning: Invalid precision value '{sys.argv[i + 1]}', using default {precision}") + + result = calculate(expression, symbolic=symbolic, precision=precision) + print(result) + + +if __name__ == "__main__": + main() diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/example_usage.py b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/example_usage.py new file mode 100644 index 000000000..09e5096fa --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/example_usage.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +""" +Example usage of the LLM-optimized calculator module. +Demonstrates how to integrate the calculator into LLM agents or other Python applications. +""" + +from calculator import calculate + + +def main(): + print("LLM-Optimized Calculator Examples\n" + "=" * 50 + "\n") + + # Example 1: Basic arithmetic + print("Example 1: Basic Arithmetic") + expressions = [ + "2 + 2", + "10 * 5 + 3", + "100 / 4", + "2^8", + ] + for expr in expressions: + result = calculate(expr) + print(f" {expr:20s} = {result}") + print() + + # Example 2: Mathematical functions + print("Example 2: Mathematical Functions") + expressions = [ + "sqrt(144)", + "sin(pi/2)", + "cos(pi)", + "log(100, 10)", + "factorial(5)", + ] + for expr in expressions: + result = calculate(expr) + print(f" {expr:20s} = {result}") + print() + + # Example 3: Symbolic expressions + print("Example 3: Symbolic Expressions") + symbolic_exprs = [ + "x^2 + 2*x + 1", + "sin(x) + cos(x)", + "(a + b)^2", + ] + for expr in symbolic_exprs: + result = calculate(expr, symbolic=True) + print(f" {expr:20s} = {result}") + print() + + # Example 4: Complex calculations + print("Example 4: Complex Calculations") + expressions = [ + "(sin(pi/4))^2 + (cos(pi/4))^2", + "log(1000, 10) + sqrt(144)", + "factorial(6) / factorial(4)", + ] + for expr in expressions: + result = calculate(expr) + print(f" {expr:35s} = {result}") + print() + + # Example 5: High precision + print("Example 5: High Precision (50 decimal places)") + result = calculate("pi", precision=50) + print(f" pi = {result}") + print() + + # Example 6: Error handling + print("Example 6: Error Handling") + bad_expressions = [ + "1 / 0", + "invalid expression", + "sqrt(-1)", # This will return I (imaginary unit) in SymPy + ] + for expr in bad_expressions: + result = calculate(expr) + print(f" {expr:20s} = {result}") + print() + + # Example 7: LLM tool integration pattern + print("Example 7: LLM Tool Integration Pattern") + print(" Simulating LLM generating math expressions...") + + # Simulate LLM outputs + llm_outputs = [ + "What is the square root of 256?", # Extract: sqrt(256) + "Calculate 15 factorial", # Extract: factorial(15) + "What's sin(30 degrees)?", # Convert: sin(30*pi/180) + ] + + # In a real LLM integration, you'd have the LLM extract/convert to expressions + extracted_expressions = [ + "sqrt(256)", + "factorial(15)", + "sin(30*pi/180)", + ] + + for question, expr in zip(llm_outputs, extracted_expressions): + result = calculate(expr) + print(f" Q: {question}") + print(f" A: {result}\n") + + +if __name__ == "__main__": + main() diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/requirements.txt b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/requirements.txt new file mode 100644 index 000000000..31a0ac42e --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/calculator/requirements.txt @@ -0,0 +1 @@ +sympy>=1.12 diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/generate_citation_matrix.py b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/generate_citation_matrix.py new file mode 100644 index 000000000..37847c0e6 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/generate_citation_matrix.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import re +from pathlib import Path +from collections import defaultdict + +ROOT = Path(__file__).resolve().parents[1] +DOCS_DIR = ROOT / "docs" + +# Match inline Markdown links: [label](url) +LINK_RE = re.compile(r"\[([^\]]+)\]\((https?://[^)]+)\)") + + +def extract_links(md_path: Path): + """Extract all inline Markdown links from a file.""" + links = [] # list of (label, url) + content = md_path.read_text(encoding="utf-8", errors="ignore") + for match in LINK_RE.finditer(content): + label, url = match.groups() + links.append((label, url)) + return links + + +def main(): + md_files = sorted( + [ + p + for p in DOCS_DIR.rglob("*.md") + if "_site" not in p.parts and "AGENTS.md" not in p.name + ] + ) + + url_map = defaultdict(list) # url -> list of (file_rel, label) + + for md in md_files: + rel = md.relative_to(ROOT).as_posix() + for label, url in extract_links(md): + url_map[url].append((rel, label)) + + matrix_path = DOCS_DIR / "operations" / "support-and-reference" / "citation-matrix.md" + matrix_path.parent.mkdir(parents=True, exist_ok=True) + + lines = [] + lines.append("---") + lines.append("title: Citation traceability matrix") + lines.append("parent: Support & Reference") + lines.append("nav_order: 4") + lines.append("---") + lines.append("") + lines.append("# Citation traceability matrix") + lines.append("") + lines.append( + "This matrix lists external links used across the documentation, along with the files that reference them." + ) + lines.append("") + lines.append(f"**Total unique URLs:** {len(url_map)}") + lines.append("") + lines.append("| URL | Label | Used in |") + lines.append("| --- | --- | --- |") + + for url in sorted(url_map.keys()): + uses = url_map[url] + # Pick first label as the display label + label = uses[0][1] + # Deduplicate files + files = sorted(set(rel for rel, _ in uses)) + files_desc = ", ".join(files) + # Escape pipes in label + label_escaped = label.replace("|", "\\|") + lines.append(f"| <{url}> | {label_escaped} | {files_desc} |") + + lines.append("") + + matrix_path.write_text("\n".join(lines), encoding="utf-8") + print(f"Generated {matrix_path} with {len(url_map)} unique URLs") + + +if __name__ == "__main__": + main() diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzAvailabilityZoneMapping.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzAvailabilityZoneMapping.ps1 new file mode 100644 index 000000000..a3b61d6af --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzAvailabilityZoneMapping.ps1 @@ -0,0 +1,232 @@ + +<# +.SYNOPSIS + Maps logical availability zones to physical zones across Azure subscriptions. + +.DESCRIPTION + This script analyzes the relationship between logical and physical availability zones + across multiple Azure subscriptions. Logical zones (1, 2, 3) may map to different + physical zones in different subscriptions, which is critical for understanding when + planning multi-subscription deployments that require specific zone alignment. + + The script outputs a detailed CSV mapping that shows: + - How logical zones map to physical zones per subscription + - The actual physical zone identifiers and names + - Location information for zone planning + + This data is essential for: + - Cross-subscription deployment planning + - Understanding zone distribution across subscriptions + - Ensuring proper zone alignment for multi-subscription architectures + - Compliance with data residency requirements + +.PARAMETER SubscriptionIds + Array of Azure subscription IDs to analyze for zone mappings. + If not specified, analyzes all accessible subscriptions in the current tenant. + Example: @('00000000-0000-0000-0000-000000000000', '11111111-1111-1111-1111-111111111111') + +.PARAMETER OutputFile + Name of the output CSV file containing the zone mapping analysis. + Default: "ZonePeers.csv" + +.EXAMPLE + .\Get-AzAvailabilityZoneMapping.ps1 + + Analyzes zone mappings for all accessible subscriptions and outputs to ZonePeers.csv. + +.EXAMPLE + .\Get-AzAvailabilityZoneMapping.ps1 -SubscriptionIds @('sub1-id','sub2-id') -OutputFile "CrossSubZones.csv" + + Analyzes specific subscriptions and outputs to a custom filename. + +.NOTES + Requires Azure PowerShell module and authenticated session with Reader access to target subscriptions. + Output CSV contains columns: TenantId, SubscriptionId, SubscriptionName, Location, + LogicalZone, PhysicalZone, PhysicalZoneName + + Zone Mapping Concepts: + - Logical Zone: The zone number (1, 2, 3) that applications see + - Physical Zone: The actual physical datacenter identifier (often a single character) + - Physical Zone Name: The full physical zone name (e.g., "eastus-az1", "eastus-az2") + + Different subscriptions may have different logical-to-physical zone mappings for the same region. + This is by design to ensure even distribution of resources across physical infrastructure. +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('00000000-0000-0000-0000-000000000000')")] + [string[]]$SubscriptionIds = @(), + + [Parameter(Mandatory = $false, HelpMessage = "Output CSV filename")] + [string]$OutputFile = "ZonePeers.csv" +) +# ================================================================================ +# HELPER FUNCTIONS +# ================================================================================ + +<# +.SYNOPSIS + Retrieves all accessible subscription IDs within the current tenant. + +.DESCRIPTION + Gets all Azure subscriptions that the current authenticated user has access to + within the current tenant context. Used when no specific subscription IDs are provided. + +.OUTPUTS + Array of subscription ID strings +#> +function Get-SubscriptionIds { + Write-Host "Listing Subscriptions" + return (Get-AzSubscription -TenantId ((Get-AzContext).Tenant.TenantId) | Select-Object -ExpandProperty SubscriptionId) +} + +<# +.SYNOPSIS + Extracts the last character from a string. + +.DESCRIPTION + Utility function used to extract the physical zone identifier from the full physical zone name. + Physical zones are typically identified by the last character (e.g., 'A', 'B', 'C') of the + full physical zone string (e.g., "eastus-az1" -> "1", "westus2-azA" -> "A"). + +.PARAMETER inputString + The input string to extract the last character from. + +.OUTPUTS + The last character of the input string, or empty string if input is null/empty. + +.EXAMPLE + Get-LastChar("eastus-az1") + Returns: "1" + +.EXAMPLE + Get-LastChar("westus2-azA") + Returns: "A" +#> +function Get-LastChar { + param ( + [string]$inputString + ) + + # Handle null or empty input + if ([string]::IsNullOrEmpty($inputString)) { + return "" + } + + # Additional length check for safety (though redundant with IsNullOrEmpty) + if ($inputString.Length -lt 1) { + return "" + } + + # Return the last character + return $inputString[-1] +} + +<# +.SYNOPSIS + Retrieves availability zone peering information for a specific subscription. + +.DESCRIPTION + Queries the Azure REST API to get detailed availability zone mapping information + for all regions within a subscription. This information shows how logical zones + (1, 2, 3) map to physical zones for each region. + +.PARAMETER SubscriptionId + The Azure subscription ID to query for zone peering information. + +.OUTPUTS + Array of location objects containing availability zone mapping details for all regions. + +.NOTES + Uses the Azure REST API directly as this detailed zone mapping information is not + available through standard PowerShell cmdlets. The API returns comprehensive + location data including availabilityZoneMappings for regions that support zones. + + The returned data structure includes: + - Location information (name, type, etc.) + - availabilityZoneMappings array with logicalZone -> physicalZone mappings +#> +function Get-ZonePeers { + param ( + [string]$SubscriptionId + ) + + # Construct REST API URI for location zone mappings using subscription-specific endpoint + $uri = "{0}subscriptions/{1}/locations?api-version=2022-12-01" -f $resourceManagerUrl, $SubscriptionId + + # Call Azure REST API to get comprehensive location and zone mapping data + $response = Invoke-AzRest -Method GET -Uri $uri + return ($response.Content | ConvertFrom-Json).value +} + +# ================================================================================ +# MAIN SCRIPT EXECUTION +# ================================================================================ + +# Set error handling and output preferences +$ErrorActionPreference = 'Stop' # Stop execution on any error +$VerbosePreference = 'SilentlyContinue' # Suppress verbose output for cleaner execution + +# Define CSV header structure for the zone mapping output +$csvHeaderString = "TenantId,SubscriptionId,SubscriptionName,Location,LogicalZone,PhysicalZone,PhysicalZoneName" + +# Initialize output file with CSV headers +$csvHeaderString | Out-File -Force -FilePath $OutputFile + +# Get the Azure Resource Manager URL for the current Azure environment +# This is needed for constructing REST API calls and may vary by cloud (Public, Government, etc.) +$resourceManagerUrl = (Get-AzContext).Environment.ResourceManagerUrl + +# Populate subscription list if not provided by user +if ($SubscriptionIds.Count -eq 0) { + $SubscriptionIds = Get-SubscriptionIds +} + +# Initialize array to collect all zone mapping data +$zoneMaps = @() + +# Process each subscription to extract zone mapping information +ForEach ($subscriptionId in $SubscriptionIds){ + Write-Output "Get zone peer details for $subscriptionId" + + # Get comprehensive zone peering data for this subscription + $zonePeers = Get-ZonePeers -SubscriptionId $subscriptionId + + # Extract availability zone mappings from regions only (filter out other location types) + # Only regions have availability zone mappings - other location types don't support zones + $zoneMappings = ($zonePeers | Where-Object { $_.type -eq "Region"}).availabilityZoneMappings + + # Get subscription details for output labeling + $subscription = Get-AzSubscription -SubscriptionId $subscriptionId + + # Process each zone mapping within this subscription + foreach($mapping in $zoneMappings) { + # Skip mappings with missing zone information + # Some regions may have incomplete or null zone mapping data + if([string]::IsNullOrEmpty($mapping.logicalZone) -or [string]::IsNullOrEmpty($mapping.physicalZone)) { + continue + } + + # Create zone mapping record with comprehensive details + $zoneMap = [PSCustomObject]@{ + TenantId = $Subscription.TenantId # Azure tenant identifier + SubscriptionId = $Subscription.Id # Subscription GUID + SubscriptionName = $Subscription.Name # Human-readable subscription name + Location = $mapping.physicalZone.Split("-")[0] # Region name (e.g., "eastus" from "eastus-az1") + LogicalZone = $mapping.logicalZone # Logical zone number (1, 2, 3) + PhysicalZone = Get-LastChar($mapping.physicalZone) # Physical zone identifier (A, B, C or 1, 2, 3) + PhysicalZoneName = $mapping.physicalZone # Full physical zone name (e.g., "eastus-az1") + } + + # Add this mapping to the collection + $zoneMaps += $zoneMap + } +} + +# Output all collected zone mapping data to CSV file +# Using -NoHeader since we already wrote headers at the beginning +$zoneMaps | ConvertTo-Csv -NoHeader | Out-File -Force -Append -FilePath $OutputFile + +Write-Host "Zone mapping analysis complete. Results written to: $OutputFile" +Write-Host "Total zone mappings found: $($zoneMaps.Count)" \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsage.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsage.ps1 new file mode 100644 index 000000000..d6f2b2de8 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsage.ps1 @@ -0,0 +1,555 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. + +<# +.SYNOPSIS + Multi-threaded Azure VM quota analysis script that queries compute resource SKU availability, + quota usage, and availability zone restrictions across subscriptions. + +.DESCRIPTION + This script analyzes Azure VM quota usage and availability zone restrictions across multiple + subscriptions and regions. It provides detailed information about: + - Current quota usage vs. limits for VM families + - Available and restricted availability zones per SKU + - Region-level restrictions for specific VM SKUs + - Physical vs. logical availability zone mappings + + The Catalogs API is the primary SKU source. The deprecated meter data CSV is used only as a + fallback when Catalogs API lookup fails and the SKUs parameter is not provided. + + The script supports multi-threading for faster execution across large numbers of subscriptions + and can normalize zone information to physical zones for cross-subscription deployment planning. + +.PARAMETER SKUs + Array of VM SKU names to analyze. If not specified, resolves VM SKUs from the Azure Catalogs + API first and falls back to the deprecated meter data CSV only if that lookup fails. + Example: @('Standard_D2s_v3', 'Standard_D4s_v3', 'Standard_E4s_v5') + +.PARAMETER Locations + Array of Azure regions to analyze. If not specified, queries all physical Azure regions. + Example: @('eastus', 'westus2', 'centralus') + +.PARAMETER SubscriptionIds + Array of subscription IDs to analyze. If not specified, queries all accessible subscriptions. + Example: @('00000000-0000-0000-0000-000000000000') + +.PARAMETER MeterDataUri + Deprecated fallback source URI for normalized VM SKU data from Cost Management connector data. + Used only when the Catalogs API lookup fails and the SKUs parameter is not provided. + +.PARAMETER CatalogLocation + Azure region used for Catalogs API requests when resolving VM SKU names from the primary SKU + source. + +.PARAMETER UsePhysicalZones + Switch to normalize availability zone output to physical zones instead of logical zones. + Useful for cross-subscription deployment planning where logical zones may differ. + +.PARAMETER Threads + Number of concurrent threads for processing subscriptions. Set to 0 for auto-detection. + Higher values speed up execution but may hit API rate limits. + +.PARAMETER OutputFile + Name of the output CSV file containing the analysis results. + +.EXAMPLE + .\Get-AzVMQuotaUsage.ps1 -SKUs @('Standard_D2s_v5','Standard_E4s_v5') -Locations @('eastus','westus2') + + Analyzes specific VM SKUs in specific regions across all accessible subscriptions. + +.EXAMPLE + .\Get-AzVMQuotaUsage.ps1 -UsePhysicalZones -Threads 4 -OutputFile "MyQuotaAnalysis.csv" + + Runs full analysis with physical zone mapping using 4 threads. + +.NOTES + Requires Azure PowerShell module and authenticated session with Reader access to target subscriptions. + Catalogs API access also requires the Microsoft.Capacity/catalogs/read permission. + Output CSV contains columns: TenantId, SubscriptionId, SubscriptionName, Location, Family, Size, + RegionRestricted, ZonesPresent, ZonesRestricted, CoresUsed, CoresTotal, CoresRequested, ZonesRequested +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('Standard_D2s_v3', 'Standard_D4s_v3')")] + [string[]]$SKUs = @(), + + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('eastus', 'westus')")] + [string[]]$Locations = @(), + + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('00000000-0000-0000-0000-000000000000')")] + [string[]]$SubscriptionIds = @(), + + [Parameter(Mandatory = $false, HelpMessage = "Deprecated fallback URL to download normalized VM SKU list")] + [string]$MeterDataUri = "https://ccmstorageprod.blob.core.windows.net/instancesizeflexibility-data/isfratioblob.csv", + + [Parameter(Mandatory = $false, HelpMessage = "Azure region to query for VM catalog data")] + [string]$CatalogLocation = "eastus", + + [Parameter(Mandatory = $false, HelpMessage = "Normalize output to physical availability zones")] + [switch]$UsePhysicalZones = $false, + + [Parameter(Mandatory = $false, HelpMessage = "Concurrent threads to use. Set to '0' for auto-detect")] + [ValidateRange(0, 40)] + [int]$Threads = 2, + + [Parameter(Mandatory = $false, HelpMessage = "Output file name")] + [string]$OutputFile = "QuotaQuery.csv" +) + +# ================================================================================ +# HELPER FUNCTIONS +# ================================================================================ + +<# +.SYNOPSIS + Retrieves normalized VM SKU names from the Azure Catalogs API, with CSV as fallback. + +.DESCRIPTION + Queries the Azure Catalogs API for normalized VM SKU names and uses that as the + primary source for quota analysis. If the Catalogs API call fails, falls back to + AutofitComboMeterData.csv. Filters out SQL-related SKUs and returns unique SKU names. + +.OUTPUTS + Array of normalized VM SKU names (e.g., 'Standard_D2s_v3', 'Standard_E4s_v5') +#> +function Get-SKUDetails { + try { + Write-Host "Querying Azure Catalogs API for VM SKU details in $CatalogLocation" + $catalogData = Get-VMCatalogData -SubscriptionId $SubscriptionIds[0] -Location $CatalogLocation + [string[]]$skuNames = @( + ($catalogData | Select-Object -Property ArmSkuName -Unique | Where-Object { $_.ArmSkuName -notlike "*sql*" }).ArmSkuName | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + ) + + if ($skuNames.Count -eq 0) { + throw "Catalogs API returned zero VM SKUs" + } + + Write-Host "Retrieved $($skuNames.Count) unique VM SKUs from Catalogs API" + return $skuNames + } + catch { + Write-Warning "Catalogs API failed: $($_.Exception.Message)" + Write-Warning "Falling back to CSV download from $MeterDataUri" + + # Extract filename from URI for local storage + [string]$meterDataFile = $MeterDataUri.Split('/')[-1] + + # Download the Cost Management connector data file + Invoke-WebRequest -Uri $MeterDataUri -OutFile $meterDataFile + + # Parse CSV and extract unique, non-SQL VM SKUs + $meterData = Get-Content $meterDataFile | ConvertFrom-Csv + [string[]]$skuNames = @( + ($meterData | Select-Object -Property ArmSkuName -Unique | Where-Object { $_.ArmSkuName -notlike "*sql*" }).ArmSkuName | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + ) + return $skuNames + } +} + +<# +.SYNOPSIS + Retrieves VM catalog data from the Azure Microsoft.Capacity catalogs API. + +.DESCRIPTION + Calls the Azure catalogs endpoint for VirtualMachines in the specified subscription + and location using Invoke-AzRestMethod. Follows any nextLink values until all pages + are retrieved and returns only entries that contain the required instance size + flexibility properties. + +.PARAMETER SubscriptionId + The Azure subscription ID used to scope the catalogs API request. + +.PARAMETER Location + The Azure region name used in the catalogs API filter. + +.OUTPUTS + Array of PSCustomObject values with InstanceSizeFlexibilityGroup, ArmSkuName, and Ratio properties. +#> +function Get-VMCatalogData { + param ( + [string]$SubscriptionId, + [string]$Location + ) + + $catalogItems = [System.Collections.Generic.List[object]]::new() + $path = "/subscriptions/{0}/providers/Microsoft.Capacity/catalogs?api-version=2022-11-01&reservedResourceType=VirtualMachines&location={1}" -f $SubscriptionId, $Location + $nextLink = $null + + do { + $response = if ([string]::IsNullOrWhiteSpace($nextLink)) { + Invoke-AzRestMethod -Method GET -Path $path + } + else { + Invoke-AzRestMethod -Method GET -Uri $nextLink + } + + $payload = $response.Content | ConvertFrom-Json -Depth 10 + + foreach ($item in @($payload.value)) { + $groupProperty = @($item.skuProperties | Where-Object { $_.name -eq 'ReservationsAutofitGroup' } | Select-Object -First 1) + $ratioProperty = @($item.skuProperties | Where-Object { $_.name -eq 'ReservationsAutofitRatio' } | Select-Object -First 1) + + if ([string]::IsNullOrWhiteSpace([string]$item.name) -or + $groupProperty.Count -eq 0 -or + $ratioProperty.Count -eq 0 -or + [string]::IsNullOrWhiteSpace([string]$groupProperty[0].value) -or + [string]::IsNullOrWhiteSpace([string]$ratioProperty[0].value)) { + continue + } + + $catalogItems.Add([PSCustomObject]@{ + InstanceSizeFlexibilityGroup = $groupProperty[0].value + ArmSkuName = $item.name + Ratio = $ratioProperty[0].value + }) + } + + $nextLink = $payload.nextLink + } while (-not [string]::IsNullOrWhiteSpace($nextLink)) + + return $catalogItems.ToArray() +} + +<# +.SYNOPSIS + Retrieves all accessible subscription IDs within the current tenant. + +.DESCRIPTION + Gets all Azure subscriptions that the current authenticated user has access to + within the current tenant context. + +.OUTPUTS + Array of subscription ID strings +#> +function Get-SubscriptionIds { + Write-Host "Listing Subscriptions" + return (Get-AzSubscription -TenantId ((Get-AzContext).Tenant.TenantId) | Select-Object -ExpandProperty SubscriptionId) +} + +<# +.SYNOPSIS + Extracts the last character from a string. + +.DESCRIPTION + Utility function used to extract physical zone identifiers from availability zone mappings. + Physical zones are typically identified by the last character of the physical zone string. + +.PARAMETER inputString + The input string to extract the last character from. + +.OUTPUTS + The last character of the input string, or empty string if input is null/empty. +#> +function Get-LastChar { + param ( + [string]$inputString + ) + + if ([string]::IsNullOrEmpty($inputString)) { + return "" + } + return $inputString[-1] +} + +<# +.SYNOPSIS + Retrieves all physical Azure regions. + +.DESCRIPTION + Gets all Azure regions that are physical locations (not logical regions) + and have a defined physical location. Filters out logical regions and + regions without physical presence. + +.OUTPUTS + Array of Azure region names (e.g., 'eastus', 'westus2', 'centralus') +#> +function Get-Locations { + Write-Host "Listing Locations" + return (Get-AzLocation | Where-Object { $_.RegionType -eq 'Physical' -and $_.PhysicalLocation -ne "" -and $_.Location } | Select-Object -Property Location -Unique).Location +} + +<# +.SYNOPSIS + Retrieves availability zone peering information for a subscription. + +.DESCRIPTION + Gets the logical-to-physical availability zone mappings for all regions + within a specific subscription. This information is crucial for understanding + how logical zones (1, 2, 3) map to physical zones across different subscriptions. + +.PARAMETER SubscriptionId + The Azure subscription ID to query for zone peering information. + +.OUTPUTS + Array of location objects containing availability zone mapping details. + +.NOTES + Uses the Azure REST API directly as this information is not available through + standard PowerShell cmdlets. +#> +function Get-ZonePeers { + param ( + [string]$SubscriptionId + ) + Write-Host "Get Zone Peering Information for subscription $SubscriptionId" + + # Construct REST API URI for location zone mappings + $uri = "{0}subscriptions/{1}/locations?api-version=2022-12-01" -f (Get-AzContext).Environment.ResourceManagerUrl, $SubscriptionId + + # Call Azure REST API to get zone peering data + $response = Invoke-AzRest -Method GET -Uri $uri + return ($response.Content | ConvertFrom-Json).value +} + +<# +.SYNOPSIS + Analyzes VM quota usage and restrictions for a specific subscription. + +.DESCRIPTION + Core function that performs detailed quota analysis for a single subscription. + Queries compute resource SKUs, VM usage statistics, and availability zone + restrictions across specified locations and SKUs. + +.PARAMETER SubscriptionId + The Azure subscription ID to analyze. + +.PARAMETER Locations + Array of Azure regions to analyze within this subscription. + +.PARAMETER SKUs + Array of VM SKU names to analyze. + +.PARAMETER OutputFile + Name of the CSV file to append results to. + +.OUTPUTS + Appends CSV rows to the output file with quota and restriction details. + +.NOTES + This function is designed to run in parallel across multiple subscriptions + for optimal performance. Each execution handles one subscription completely. +#> +function Get-QuotaDetails { + param ( + [string]$SubscriptionId, + [string[]]$Locations, + [string[]]$SKUs, + [string]$OutputFile + ) + + $start = Get-Date + try { + # Get subscription details and validate access + $Subscription = Get-AzSubscription -SubscriptionId $SubscriptionId -WarningAction SilentlyContinue + if ($null -eq $Subscription) { + throw "Subscription not found" + } + + # Set context to target subscription for all subsequent queries + Set-AzContext -SubscriptionId $Subscription.Id -WarningAction SilentlyContinue | Out-Null + + # Get zone peering information if physical zone mapping is requested + if($UsePhysicalZones) + { + $zonePeers = Get-ZonePeers -SubscriptionId $SubscriptionId + if ($zonePeers.Count -eq 0) { + Write-Host "No Zone Peering Information found for subscription $SubscriptionId" -ForegroundColor Yellow + } + } + + # Process each location within the subscription + foreach ($Location in $Locations) { + "Querying: $SubscriptionId - $($Subscription.Name) - $Location" + + # Get all VM SKUs available in this location + $computeSKUs = Get-AzComputeResourceSku -Location $Location -ErrorAction SilentlyContinue | Where-Object { $_.ResourceType -eq 'virtualMachines' } + + # Get current VM quota usage for this location + $vmUsage = Get-AZVMUsage -Location $Location -ErrorAction SilentlyContinue + + # Get availability zone mappings for this location (if using physical zones) + $availabilityZoneMappings = ($zonePeers | Where-Object { $_.name -like $Location -and $_.type -eq "Region"}).availabilityZoneMappings + + # Process each requested SKU + foreach ($SKU in $SKUs) { + # Find the specific SKU data for this location + $filteredSku = $computeSKUs | Where-Object { $_.Name.ToLowerInvariant() -eq $SKU.ToLowerInvariant() -and $_.LocationInfo.Location -like $Location } + + # Find the quota usage data for this SKU's family + $skuUsage = $vmUsage | Select-Object -ExpandProperty Name -Property CurrentValue, Limit | Where-Object { $_.Value -eq $filteredSku.Family } + + # Skip if SKU not found in this location + if ($null -eq $filteredSku ) { + continue + } + + # Skip if quota usage data not found + if ($null -eq $skuUsage) { + continue + } + + # Process availability zones (logical or physical) + $zones = @($filteredSku.LocationInfo.Zones) + if($UsePhysicalZones) + { + # Convert logical zones to physical zones + for ($i = 0; $i -lt $zones.Length; $i++) { + $zones[$i] = Get-LastChar(($availabilityZoneMappings | Where-Object {$_.LogicalZone -like $zones[$i]}).physicalZone) + } + } + + # Create the quota analysis object + $auditedSku = [PSCustomObject]@{ + TenantId = $Subscription.TenantId + SubscriptionId = $Subscription.Id + SubscriptionName = $Subscription.Name + Location = $Location + Family = $skuUsage.LocalizedValue # VM family name (e.g., "Dv3 Family vCPUs") + Size = $filteredSku.Name # Specific SKU (e.g., "Standard_D2s_v3") + RegionRestricted = 'False' # Whether SKU is restricted in this entire region + ZonesPresent = ($zones | Sort-Object) -join "," # Available zones for this SKU + ZonesRestricted = '' # Zones where SKU is restricted + CoresUsed = $skuUsage.CurrentValue # Current quota usage + CoresTotal = $skuUsage.Limit # Total quota limit + CoresRequested = '' # Placeholder for future use + ZonesRequested = '' # Placeholder for future use + } + + # Process any restrictions on this SKU + foreach ($restriction in $filteredSku.Restrictions) { + if ($restriction.Type -like "Zone") { + # Handle zone-specific restrictions + $zoneRestrictions = @($restriction.RestrictionInfo.Zones) + if($UsePhysicalZones) + { + # Convert restricted logical zones to physical zones + for ($i = 0; $i -lt $zoneRestrictions.Length; $i++) { + $zoneRestrictions[$i] = Get-LastChar(($availabilityZoneMappings | Where-Object {$_.LogicalZone -like $zoneRestrictions[$i]}).physicalZone) + } + } + $auditedSku.ZonesRestricted = ($zoneRestrictions | Sort-Object) -join "," + } + elseif ($restriction.Type -like "Location") { + # Handle region-wide restrictions + $auditedSku.RegionRestricted = 'True' + } + } + + # Append the result to the CSV file + $auditedSku | ConvertTo-Csv -NoHeader | Out-File -Force -Append -FilePath .\$OutputFile + } + } + } + catch { + Write-Host "Failed Querying Subscription ID: $SubscriptionId" -ForegroundColor Yellow + $_.Exception.Message + } + finally { + # Report processing time for this subscription + $end = Get-Date + "Processed: $SubscriptionId - $($Subscription.Name) in $([math]::Round((New-TimeSpan -Start $start -End $end).TotalSeconds, 2)) seconds" + } +} + +# ================================================================================ +# MAIN SCRIPT EXECUTION +# ================================================================================ + +# Set error handling and output preferences +$ErrorActionPreference = 'Stop' +$VerbosePreference = 'SilentlyContinue' +$begin = Get-Date + +# Define CSV header structure for output file +$csvHeaderString = "TenantId,SubscriptionId,SubscriptionName,Location,Family,Size,RegionRestricted,ZonesPresent,ZonesRestricted,CoresUsed,CoresTotal,CoresRequested,ZonesRequested" + +# Auto-detect optimal thread count if not specified +if($Threads -eq 0) +{ + try { + # Use WMI to detect CPU configuration + $spec = Get-WmiObject -Class Win32_Processor | Select-Object -Property NumberOfCores, NumberOfLogicalProcessors + if($spec.NumberOfLogicalProcessors -gt $spec.NumberOfCores) { + # Hyper-threading enabled: Use physical cores to avoid e-core performance issues + $Threads = $spec.NumberOfLogicalProcessors - $spec.NumberOfCores + } + else { + # Hyper-threading disabled: Use all available cores + $Threads = $spec.NumberOfCores + } + } + catch { + # Fallback to single-threaded if CPU detection fails + $Threads = 1 + } +} + +# Populate subscription list if not provided +if ($SubscriptionIds.Count -eq 0) { + $SubscriptionIds = Get-SubscriptionIds +} + +# Populate locations list if not provided, otherwise sort provided list +if ($Locations.Count -eq 0) { + $Locations = Get-Locations | Sort-Object +} else { + $Locations = $Locations | Sort-Object +} + +# Populate SKUs list if not provided +if ($SKUs.Count -eq 0) { + $SKUs = Get-SKUDetails +} + +# Display configuration information +if($UsePhysicalZones) +{ + Write-Host "Output will be normalized to physical availability zones" +} +else { + Write-Host "Output will not be normalized to physical availability zones" +} + +Write-Host "Querying $($SubscriptionIds.Count) subscriptions with $($SKUs.Count) SKUs in $($Locations.Count) locations using $Threads threads" + +# Execute quota analysis using parallel processing +$funcDef = ${function:Get-QuotaDetails}.ToString() +$SubscriptionIds | Foreach-Object -ThrottleLimit $Threads -Parallel { + # Import function definition into parallel runspace + ${function:Get-QuotaDetails} = $using:funcDef + + # Use separate output files for multi-threaded execution to avoid conflicts + if($USING:Threads -gt 1) { + $outFile = "QuotaQuery_{0}.csv" -f $PSItem + } else { + $outFile = $USING:OutputFile + } + + # Write CSV header to output file + $USING:csvHeaderString | Out-File -Force $outFile + + # Execute quota analysis for this subscription + Get-QuotaDetails -SubscriptionId $_ -Locations $USING:Locations -SKUs $USING:SKUs -outputFile $outFile +} + +# Merge multiple CSV files if multi-threaded execution was used +if($Threads -gt 1) { + Write-Host "Merging CSV files" + + # Create consolidated output file with header + $csvHeaderString | Out-File -Force -FilePath $OutputFile + + # Append content from all thread-specific files (skipping headers) + Get-ChildItem -Path .\QuotaQuery_*.csv | ForEach-Object { + Get-Content $_.FullName | Select-Object -Skip 1 | Add-Content $OutputFile + Remove-Item $_.FullName # Clean up temporary files + } +} + +# Display completion summary +Write-Host "Output written to $OutputFile" +$end = Get-Date +Write-Host "Processed $($SubscriptionIds.Count) subscriptions in $([math]::Round((New-TimeSpan -Start $begin -End $end).TotalSeconds, 2)) seconds" diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsageCli.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsageCli.ps1 new file mode 100644 index 000000000..d5b21ab3b --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Get-AzVMQuotaUsageCli.ps1 @@ -0,0 +1,597 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. + +<# +.SYNOPSIS + Multi-threaded Azure VM quota analysis script that queries compute resource SKU availability, + quota usage, and availability zone restrictions across subscriptions using Azure CLI. + +.DESCRIPTION + This script analyzes Azure VM quota usage and availability zone restrictions across multiple + subscriptions and regions. It provides detailed information about: + - Current quota usage vs. limits for VM families + - Available and restricted availability zones per SKU + - Region-level restrictions for specific VM SKUs + - Physical vs. logical availability zone mappings + + The Catalogs API is the primary SKU source. The deprecated meter data CSV is used only as a + fallback when Catalogs API lookup fails and the SKUs parameter is not provided. + + The script supports multi-threading for faster execution across large numbers of subscriptions + and can normalize zone information to physical zones for cross-subscription deployment planning. + + This is the Azure CLI variant of Get-AzVMQuotaUsage.ps1. It uses `az` commands exclusively + and does not require the Azure PowerShell (Az) module. + +.PARAMETER SKUs + Array of VM SKU names to analyze. If not specified, resolves VM SKUs from the Azure Catalogs + API first and falls back to the deprecated meter data CSV only if that lookup fails. + Example: @('Standard_D2s_v3', 'Standard_D4s_v3', 'Standard_E4s_v5') + +.PARAMETER Locations + Array of Azure regions to analyze. If not specified, queries all physical Azure regions. + Example: @('eastus', 'westus2', 'centralus') + +.PARAMETER SubscriptionIds + Array of subscription IDs to analyze. If not specified, queries all accessible subscriptions. + Example: @('00000000-0000-0000-0000-000000000000') + +.PARAMETER MeterDataUri + Deprecated fallback source URI for normalized VM SKU data from Cost Management connector data. + Used only when the Catalogs API lookup fails and the SKUs parameter is not provided. + +.PARAMETER CatalogLocation + Azure region used for Catalogs API requests when resolving VM SKU names from the primary SKU + source. + +.PARAMETER UsePhysicalZones + Switch to normalize availability zone output to physical zones instead of logical zones. + Useful for cross-subscription deployment planning where logical zones may differ. + +.PARAMETER Threads + Number of concurrent threads for processing subscriptions. Set to 0 for auto-detection. + Higher values speed up execution but may hit API rate limits. + +.PARAMETER OutputFile + Name of the output CSV file containing the analysis results. + +.EXAMPLE + .\Get-AzVMQuotaUsageCli.ps1 -SKUs @('Standard_D2s_v5','Standard_E4s_v5') -Locations @('eastus','westus2') + + Analyzes specific VM SKUs in specific regions across all accessible subscriptions. + +.EXAMPLE + .\Get-AzVMQuotaUsageCli.ps1 -UsePhysicalZones -Threads 4 -OutputFile "MyQuotaAnalysis.csv" + + Runs full analysis with physical zone mapping using 4 threads. + +.NOTES + Requires Azure CLI (`az`) installed and an authenticated session (`az login`) with Reader + access to target subscriptions. The Az PowerShell module is not required. + Catalogs API access also requires the Microsoft.Capacity/catalogs/read permission. + Output CSV contains columns: TenantId, SubscriptionId, SubscriptionName, Location, Family, Size, + RegionRestricted, ZonesPresent, ZonesRestricted, CoresUsed, CoresTotal, CoresRequested, ZonesRequested +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('Standard_D2s_v3', 'Standard_D4s_v3')")] + [string[]]$SKUs = @(), + + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('eastus', 'westus')")] + [string[]]$Locations = @(), + + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('00000000-0000-0000-0000-000000000000')")] + [string[]]$SubscriptionIds = @(), + + [Parameter(Mandatory = $false, HelpMessage = "Deprecated fallback URL to download normalized VM SKU list")] + [string]$MeterDataUri = "https://ccmstorageprod.blob.core.windows.net/instancesizeflexibility-data/isfratioblob.csv", + + [Parameter(Mandatory = $false, HelpMessage = "Azure region to query for VM catalog data")] + [string]$CatalogLocation = "eastus", + + [Parameter(Mandatory = $false, HelpMessage = "Normalize output to physical availability zones")] + [switch]$UsePhysicalZones = $false, + + [Parameter(Mandatory = $false, HelpMessage = "Concurrent threads to use. Set to '0' for auto-detect")] + [ValidateRange(0, 40)] + [int]$Threads = 2, + + [Parameter(Mandatory = $false, HelpMessage = "Output file name")] + [string]$OutputFile = "QuotaQuery.csv" +) + +# ================================================================================ +# HELPER FUNCTIONS +# ================================================================================ + +<# +.SYNOPSIS + Retrieves normalized VM SKU names from the Azure Catalogs API, with CSV as fallback. + +.DESCRIPTION + Queries the Azure Catalogs API for normalized VM SKU names and uses that as the + primary source for quota analysis. If the Catalogs API call fails, falls back to + AutofitComboMeterData.csv. Filters out SQL-related SKUs and returns unique SKU names. + +.OUTPUTS + Array of normalized VM SKU names (e.g., 'Standard_D2s_v3', 'Standard_E4s_v5') +#> +function Get-SKUDetails { + try { + Write-Host "Querying Azure Catalogs API for VM SKU details in $CatalogLocation" + $catalogData = Get-VMCatalogData -SubscriptionId $SubscriptionIds[0] -Location $CatalogLocation + [string[]]$skuNames = @( + ($catalogData | Select-Object -Property ArmSkuName -Unique | Where-Object { $_.ArmSkuName -notlike "*sql*" }).ArmSkuName | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + ) + + if ($skuNames.Count -eq 0) { + throw "Catalogs API returned zero VM SKUs" + } + + Write-Host "Retrieved $($skuNames.Count) unique VM SKUs from Catalogs API" + return $skuNames + } + catch { + Write-Warning "Catalogs API failed: $($_.Exception.Message)" + Write-Warning "Falling back to CSV download from $MeterDataUri" + + # Extract filename from URI for local storage + [string]$meterDataFile = $MeterDataUri.Split('/')[-1] + + # Download the Cost Management connector data file + Invoke-WebRequest -Uri $MeterDataUri -OutFile $meterDataFile + + # Parse CSV and extract unique, non-SQL VM SKUs + $meterData = Get-Content $meterDataFile | ConvertFrom-Csv + [string[]]$skuNames = @( + ($meterData | Select-Object -Property ArmSkuName -Unique | Where-Object { $_.ArmSkuName -notlike "*sql*" }).ArmSkuName | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + ) + return $skuNames + } +} + +<# +.SYNOPSIS + Retrieves VM catalog data from the Azure Microsoft.Capacity catalogs API using Azure CLI. + +.DESCRIPTION + Calls the Azure catalogs endpoint for VirtualMachines in the specified subscription + and location using `az rest`. Follows any nextLink values until all pages are + retrieved and returns only entries that contain the required instance size + flexibility properties. + +.PARAMETER SubscriptionId + The Azure subscription ID used to scope the catalogs API request. + +.PARAMETER Location + The Azure region name used in the catalogs API filter. + +.OUTPUTS + Array of PSCustomObject values with InstanceSizeFlexibilityGroup, ArmSkuName, and Ratio properties. +#> +function Get-VMCatalogData { + param ( + [string]$SubscriptionId, + [string]$Location + ) + + $catalogItems = [System.Collections.Generic.List[object]]::new() + + # Get the resource manager endpoint for the current cloud (supports sovereign clouds) + $resourceManagerUrl = (az cloud show --query endpoints.resourceManager -o tsv).TrimEnd('/') + + $uri = "{0}/subscriptions/{1}/providers/Microsoft.Capacity/catalogs?api-version=2022-11-01&reservedResourceType=VirtualMachines&location={2}" -f $resourceManagerUrl, $SubscriptionId, $Location + + do { + $response = az rest --method GET --url $uri -o json | ConvertFrom-Json + + foreach ($item in @($response.value)) { + $groupProperty = @($item.skuProperties | Where-Object { $_.name -eq 'ReservationsAutofitGroup' } | Select-Object -First 1) + $ratioProperty = @($item.skuProperties | Where-Object { $_.name -eq 'ReservationsAutofitRatio' } | Select-Object -First 1) + + if ([string]::IsNullOrWhiteSpace([string]$item.name) -or + $groupProperty.Count -eq 0 -or + $ratioProperty.Count -eq 0 -or + [string]::IsNullOrWhiteSpace([string]$groupProperty[0].value) -or + [string]::IsNullOrWhiteSpace([string]$ratioProperty[0].value)) { + continue + } + + $catalogItems.Add([PSCustomObject]@{ + InstanceSizeFlexibilityGroup = $groupProperty[0].value + ArmSkuName = $item.name + Ratio = $ratioProperty[0].value + }) + } + + $uri = $response.nextLink + } while (-not [string]::IsNullOrWhiteSpace($uri)) + + return $catalogItems.ToArray() +} + +<# +.SYNOPSIS + Retrieves all accessible subscription IDs within the current tenant using Azure CLI. + +.DESCRIPTION + Gets all Azure subscriptions that the current authenticated user has access to + within the current tenant context. Uses `az account list` filtered by the current + tenant ID obtained from `az account show`. + +.OUTPUTS + Array of subscription ID strings +#> +function Get-SubscriptionIds { + Write-Host "Listing Subscriptions" + + # Get the current tenant ID from the active CLI session + $tenantId = az account show --query tenantId -o tsv + + # List all subscriptions in this tenant and return their IDs + $subscriptions = az account list --query "[?tenantId=='$tenantId'].id" -o json | ConvertFrom-Json + return $subscriptions +} + +<# +.SYNOPSIS + Extracts the last character from a string. + +.DESCRIPTION + Utility function used to extract physical zone identifiers from availability zone mappings. + Physical zones are typically identified by the last character of the physical zone string. + +.PARAMETER inputString + The input string to extract the last character from. + +.OUTPUTS + The last character of the input string, or empty string if input is null/empty. +#> +function Get-LastChar { + param ( + [string]$inputString + ) + + if ([string]::IsNullOrEmpty($inputString)) { + return "" + } + return $inputString[-1] +} + +<# +.SYNOPSIS + Retrieves all physical Azure regions using Azure CLI. + +.DESCRIPTION + Gets all Azure regions that are physical locations (not logical regions) + and have a defined physical location. Uses `az account list-locations` with + a JMESPath query to filter out logical regions and regions without physical presence. + +.OUTPUTS + Array of Azure region names (e.g., 'eastus', 'westus2', 'centralus') +#> +function Get-Locations { + Write-Host "Listing Locations" + + # Query physical regions only — exclude logical regions and those without a physical location. + # The Az module equivalent filters on RegionType == 'Physical' and PhysicalLocation != ''. + # az account list-locations exposes this via metadata.regionType and metadata.physicalLocation. + $locations = az account list-locations --query "[?metadata.regionType=='Physical' && metadata.physicalLocation!=''].name" -o json | ConvertFrom-Json + return $locations +} + +<# +.SYNOPSIS + Retrieves availability zone peering information for a subscription using Azure CLI. + +.DESCRIPTION + Gets the logical-to-physical availability zone mappings for all regions + within a specific subscription. This information is crucial for understanding + how logical zones (1, 2, 3) map to physical zones across different subscriptions. + +.PARAMETER SubscriptionId + The Azure subscription ID to query for zone peering information. + +.OUTPUTS + Array of location objects containing availability zone mapping details. + +.NOTES + Uses the Azure REST API via `az rest` as this information is not available through + standard Azure CLI commands. The resource manager endpoint is obtained from `az cloud show`. +#> +function Get-ZonePeers { + param ( + [string]$SubscriptionId + ) + Write-Host "Get Zone Peering Information for subscription $SubscriptionId" + + # Get the resource manager endpoint for the current cloud (supports sovereign clouds) + # TrimEnd('/') ensures sovereign clouds (AzureUSGovernment, AzureChinaCloud) that omit + # a trailing slash don't produce a malformed URI like "https://...netsubscriptions/..." + $resourceManagerUrl = (az cloud show --query endpoints.resourceManager -o tsv).TrimEnd('/') + + # Construct REST API URI for location zone mappings + $uri = "${resourceManagerUrl}/subscriptions/${SubscriptionId}/locations?api-version=2022-12-01" + + # Call Azure REST API to get zone peering data; pass --subscription to avoid context issues + $response = az rest --method GET --url $uri --subscription $SubscriptionId -o json | ConvertFrom-Json + return $response.value +} + +<# +.SYNOPSIS + Analyzes VM quota usage and restrictions for a specific subscription using Azure CLI. + +.DESCRIPTION + Core function that performs detailed quota analysis for a single subscription. + Queries compute resource SKUs, VM usage statistics, and availability zone + restrictions across specified locations and SKUs using `az` CLI commands. + + Unlike the Az module variant, this function passes --subscription to each + az command rather than calling az account set, which avoids race conditions + when running in parallel across multiple subscriptions. + + UsePhysicalZones is accepted as a parameter (not inherited from script scope) + so that parallel runspaces can correctly receive the switch value via $using:. + +.PARAMETER SubscriptionId + The Azure subscription ID to analyze. + +.PARAMETER Locations + Array of Azure regions to analyze within this subscription. + +.PARAMETER SKUs + Array of VM SKU names to analyze. + +.PARAMETER OutputFile + Name of the CSV file to append results to. + +.OUTPUTS + Appends CSV rows to the output file with quota and restriction details. + +.NOTES + This function is designed to run in parallel across multiple subscriptions + for optimal performance. Each execution handles one subscription completely. + Pass --subscription to every az command; do not use az account set inside + parallel runspaces as it is process-global and causes race conditions. +#> +function Get-QuotaDetails { + param ( + [string]$SubscriptionId, + [string[]]$Locations, + [string[]]$SKUs, + [string]$OutputFile, + [bool]$UsePhysicalZones = $false + ) + + $start = Get-Date + try { + # Get subscription details and validate access using Azure CLI. + # Pass --subscription so we never change the global az context. + $subscriptionJson = az account show --subscription $SubscriptionId -o json 2>$null | ConvertFrom-Json + if ($null -eq $subscriptionJson) { + throw "Subscription not found" + } + + # Build a subscription object with the same field names used throughout the function + $Subscription = [PSCustomObject]@{ + Id = $subscriptionJson.id + Name = $subscriptionJson.name + TenantId = $subscriptionJson.tenantId + } + + # Get zone peering information if physical zone mapping is requested + if ($UsePhysicalZones) { + $zonePeers = Get-ZonePeers -SubscriptionId $SubscriptionId + if ($zonePeers.Count -eq 0) { + Write-Host "No Zone Peering Information found for subscription $SubscriptionId" -ForegroundColor Yellow + } + } + + # Process each location within the subscription + foreach ($Location in $Locations) { + "Querying: $SubscriptionId - $($Subscription.Name) - $Location" + + # Get all VM SKUs available in this location using Azure CLI. + # az vm list-skus returns objects where resourceType is lowercase. + $computeSKUs = az vm list-skus --location $Location --resource-type virtualMachines --subscription $SubscriptionId -o json 2>$null | ConvertFrom-Json + + # Get current VM quota usage for this location using Azure CLI. + # Returns objects with currentValue, limit, and name.value / name.localizedValue. + $vmUsage = az vm list-usage --location $Location --subscription $SubscriptionId -o json 2>$null | ConvertFrom-Json + + # Get availability zone mappings for this location (if using physical zones) + $availabilityZoneMappings = ($zonePeers | Where-Object { $_.name -like $Location -and $_.type -eq "Region" }).availabilityZoneMappings + + # Process each requested SKU + foreach ($SKU in $SKUs) { + # Find the specific SKU data for this location. + # az vm list-skus locationInfo is an array; check locationInfo[0].location. + $filteredSku = $computeSKUs | Where-Object { + $_.name.ToLowerInvariant() -eq $SKU.ToLowerInvariant() -and + $_.locationInfo.Count -gt 0 -and + $_.locationInfo[0].location -like $Location + } + + # Skip if SKU not found in this location + if ($null -eq $filteredSku) { + continue + } + + # Find the quota usage data for this SKU's family. + # In az vm list-usage output: name.value holds the family identifier (e.g. standardDSv5Family) + # and name.localizedValue holds the human-readable label. + $skuUsage = $vmUsage | Where-Object { $_.name.value -eq $filteredSku.family } + + # Skip if quota usage data not found + if ($null -eq $skuUsage) { + continue + } + + # Process availability zones (logical or physical). + # az vm list-skus stores zones in locationInfo[0].zones. + # Guard against empty locationInfo to avoid index-out-of-bounds on SKUs + # that have no location info entries (returns empty array instead of throwing). + $zones = if ($filteredSku.locationInfo.Count -gt 0) { @($filteredSku.locationInfo[0].zones) } else { @() } + if ($UsePhysicalZones) { + # Convert logical zones to physical zones + for ($i = 0; $i -lt $zones.Length; $i++) { + $zones[$i] = Get-LastChar(($availabilityZoneMappings | Where-Object { $_.LogicalZone -like $zones[$i] }).physicalZone) + } + } + + # Create the quota analysis object + $auditedSku = [PSCustomObject]@{ + TenantId = $Subscription.TenantId + SubscriptionId = $Subscription.Id + SubscriptionName = $Subscription.Name + Location = $Location + Family = $skuUsage.name.localizedValue # VM family name (e.g., "Dv3 Family vCPUs") + Size = $filteredSku.name # Specific SKU (e.g., "Standard_D2s_v3") + RegionRestricted = 'False' # Whether SKU is restricted in this entire region + ZonesPresent = ($zones | Sort-Object) -join "," # Available zones for this SKU + ZonesRestricted = '' # Zones where SKU is restricted + CoresUsed = $skuUsage.currentValue # Current quota usage + CoresTotal = $skuUsage.limit # Total quota limit + CoresRequested = '' # Placeholder for future use + ZonesRequested = '' # Placeholder for future use + } + + # Process any restrictions on this SKU. + # az vm list-skus restrictions[].type is lowercase (e.g. "Zone", "Location"). + foreach ($restriction in $filteredSku.restrictions) { + if ($restriction.type -like "Zone") { + # Handle zone-specific restrictions. + # az vm list-skus stores restricted zones in restrictionInfo.zones. + $zoneRestrictions = @($restriction.restrictionInfo.zones) + if ($UsePhysicalZones) { + # Convert restricted logical zones to physical zones + for ($i = 0; $i -lt $zoneRestrictions.Length; $i++) { + $zoneRestrictions[$i] = Get-LastChar(($availabilityZoneMappings | Where-Object { $_.LogicalZone -like $zoneRestrictions[$i] }).physicalZone) + } + } + $auditedSku.ZonesRestricted = ($zoneRestrictions | Sort-Object) -join "," + } + elseif ($restriction.type -like "Location") { + # Handle region-wide restrictions + $auditedSku.RegionRestricted = 'True' + } + } + + # Append the result to the CSV file + $auditedSku | ConvertTo-Csv -NoHeader | Out-File -Force -Append -FilePath .\$OutputFile + } + } + } + catch { + Write-Host "Failed Querying Subscription ID: $SubscriptionId" -ForegroundColor Yellow + $_.Exception.Message + } + finally { + # Report processing time for this subscription + $end = Get-Date + "Processed: $SubscriptionId - $($Subscription.Name) in $([math]::Round((New-TimeSpan -Start $start -End $end).TotalSeconds, 2)) seconds" + } +} + +# ================================================================================ +# MAIN SCRIPT EXECUTION +# ================================================================================ + +# Set error handling and output preferences +$ErrorActionPreference = 'Stop' +$VerbosePreference = 'SilentlyContinue' +$begin = Get-Date + +# Define CSV header structure for output file +$csvHeaderString = "TenantId,SubscriptionId,SubscriptionName,Location,Family,Size,RegionRestricted,ZonesPresent,ZonesRestricted,CoresUsed,CoresTotal,CoresRequested,ZonesRequested" + +# Auto-detect optimal thread count if not specified. +# Uses [Environment]::ProcessorCount (cross-platform) instead of WMI (Windows-only). +if ($Threads -eq 0) { + try { + $Threads = [Math]::Max(1, [Environment]::ProcessorCount / 2) + } + catch { + # Fallback to single-threaded if CPU detection fails + $Threads = 1 + } +} + +# Populate subscription list if not provided +if ($SubscriptionIds.Count -eq 0) { + $SubscriptionIds = Get-SubscriptionIds +} + +# Populate locations list if not provided, otherwise sort provided list +if ($Locations.Count -eq 0) { + $Locations = Get-Locations | Sort-Object +} else { + $Locations = $Locations | Sort-Object +} + +# Populate SKUs list if not provided +if ($SKUs.Count -eq 0) { + $SKUs = Get-SKUDetails +} + +# Display configuration information +if ($UsePhysicalZones) { + Write-Host "Output will be normalized to physical availability zones" +} +else { + Write-Host "Output will not be normalized to physical availability zones" +} + +Write-Host "Querying $($SubscriptionIds.Count) subscriptions with $($SKUs.Count) SKUs in $($Locations.Count) locations using $Threads threads" + +# Execute quota analysis using parallel processing. +# Function definition is serialized as a string and re-imported in each runspace, +# because parallel runspaces do not inherit the calling scope's function definitions. +# IMPORTANT: az account set is NOT used inside the parallel block. Every az command +# receives --subscription explicitly to avoid process-global context race conditions. +$funcDef = ${function:Get-QuotaDetails}.ToString() +$lastCharFuncDef = ${function:Get-LastChar}.ToString() +$getZonePeersFuncDef = ${function:Get-ZonePeers}.ToString() + +$SubscriptionIds | Foreach-Object -ThrottleLimit $Threads -Parallel { + # Import all required function definitions into the parallel runspace + ${function:Get-QuotaDetails} = $using:funcDef + ${function:Get-LastChar} = $using:lastCharFuncDef + ${function:Get-ZonePeers} = $using:getZonePeersFuncDef + + # Use separate output files for multi-threaded execution to avoid write conflicts + if ($USING:Threads -gt 1) { + $outFile = "QuotaQuery_{0}.csv" -f $PSItem + } else { + $outFile = $USING:OutputFile + } + + # Write CSV header to output file + $USING:csvHeaderString | Out-File -Force $outFile + + # Execute quota analysis for this subscription + Get-QuotaDetails -SubscriptionId $_ -Locations $USING:Locations -SKUs $USING:SKUs -OutputFile $outFile -UsePhysicalZones ([bool]$USING:UsePhysicalZones) +} + +# Merge multiple CSV files if multi-threaded execution was used +if ($Threads -gt 1) { + Write-Host "Merging CSV files" + + # Create consolidated output file with header + $csvHeaderString | Out-File -Force -FilePath $OutputFile + + # Append content from all thread-specific files (skipping headers) + Get-ChildItem -Path .\QuotaQuery_*.csv | ForEach-Object { + Get-Content $_.FullName | Select-Object -Skip 1 | Add-Content $OutputFile + Remove-Item $_.FullName # Clean up temporary files + } +} + +# Display completion summary +Write-Host "Output written to $OutputFile" +$end = Get-Date +Write-Host "Processed $($SubscriptionIds.Count) subscriptions in $([math]::Round((New-TimeSpan -Start $begin -End $end).TotalSeconds, 2)) seconds" diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/README.md new file mode 100644 index 000000000..c4a7fe4df --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/README.md @@ -0,0 +1,219 @@ +--- +title: Quota Management +--- + +# Quota management scripts + +These scripts are intended to analyze quota usage across subscriptions and regions in scenarios where Quota Groups **have not** been implemented. + +> [!TIP] +> Use these scripts alongside Azure quota and availability zone guidance so your analysis matches the way Azure enforces vCPU and zone limits.[^vm-quotas][^az-zones][^az-quota] + +--- + +## What you'll need + +Here's what you'll need to get started: + +1. **Azure PowerShell Module**: Install the latest version + ```powershell + Install-Module -Name Az -Repository PSGallery -Force + ``` + +2. **Authentication**: Sign in to your Azure account + ```powershell + Connect-AzAccount + ``` + +3. **Permissions**: Reader access to target subscriptions + +4. **PowerShell Version**: + - PowerShell 5.1+ for single-threaded scripts + - PowerShell 7+ recommended for best performance + +--- + +## Available scripts + +### Get-AzVMQuotaUsage.ps1 (Recommended) + +**Multi-threaded quota analysis** - Fast parallel processing across multiple subscriptions. + +**Requirements**: Azure PowerShell module, PowerShell 7+ for multi-threading +**Best for**: Large-scale analysis + +```powershell +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/microsoft/azcapman/main/scripts/quota/Get-AzVMQuotaUsage.ps1" -OutFile "Get-AzVMQuotaUsage.ps1" +.\Get-AzVMQuotaUsage.ps1 -SKUs @('Standard_D2s_v5', 'Standard_E2s_v5') -Locations @('eastus', 'westus2') -Threads 4 +``` + +What you'll get: +- Current quota usage vs. limits for VM families +- Available and restricted availability zones per SKU +- Region-level restrictions for specific VM SKUs +- Physical vs. logical availability zone mappings +- Multi-threading for faster processing + +**Script Output:** + +|TenantId|SubscriptionId|SubscriptionName|Location|Family|Size|RegionRestricted|ZonesPresent|ZonesRestricted|CoresUsed|CoresTotal| +|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------| +|...|...|...|eastus|standardDSv5Family|Standard_D2s_v5|False|1,2,3||0|100| +|...|...|...|westus2|standardESv5Family|Standard_E2s_v5|False|1,2,3||0|100| +|...|...|...|westus3|standardFSv2Family|Standard_F2s_v2|True|1,2,3|1,2,3|0|100| + +**What each column means:** +- **TenantId**: Your Microsoft Entra tenant ID +- **SubscriptionId**: Your subscription ID +- **SubscriptionName**: Friendly name you've given your subscription +- **Location**: Azure region name +- **Family**: VM family (used for quota calculations) +- **Size**: Specific VM SKU name +- **RegionRestricted**: Whether the SKU has regional restrictions +- **ZonesPresent**: Available availability zones for the SKU +- **ZonesRestricted**: Restricted availability zones for the SKU +- **CoresUsed**: vCPU cores you're currently using +- **CoresTotal**: Total vCPU cores available to you + +--- + +### Show-AzVMQuotaReport.ps1 (Single-threaded) +**Simple quota analysis** - Single-threaded version for smaller projects. + +**Requirements**: Azure PowerShell module, PowerShell 5.1+ +**Best for**: Smaller analysis or learning + +```powershell +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/microsoft/azcapman/main/scripts/quota/Show-AzVMQuotaReport.ps1" -OutFile "Show-AzVMQuotaReport.ps1" +.\Show-AzVMQuotaReport.ps1 -SKUs @('Standard_D2s_v5', 'Standard_E2s_v5') -Locations @('eastus', 'westus2') +``` + +This script provides: +- Sequential processing across subscriptions +- Formatted table display of results +- Same core functionality as the multi-threaded version +- Streamlined for educational purposes + +**Script Output:** + +|TenantId|SubscriptionId|SubscriptionName|Location|Family|Size|RegionRestricted|ZonesPresent|ZonesRestricted|CoresUsed|CoresTotal| +|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------| +|...|...|...|eastus|standardDSv5Family|Standard_D2s_v5|False|1,2,3||0|100| +|...|...|...|westus2|standardESv5Family|Standard_E2s_v5|False|1,2,3||0|100| +|...|...|...|westus3|standardFSv2Family|Standard_F2s_v2|True|1,2,3|1,2,3|0|100| + +--- + +### Get-AzAvailabilityZoneMapping.ps1 (Zone Analysis) +**Zone mapping analysis** - Shows how logical zones map to physical zones across subscriptions. + +**Requirements**: Azure PowerShell module, Reader access to target subscriptions +**Best for**: Cross-subscription deployment planning + +```powershell +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/microsoft/azcapman/main/scripts/quota/Get-AzAvailabilityZoneMapping.ps1" -OutFile "Get-AzAvailabilityZoneMapping.ps1" +.\Get-AzAvailabilityZoneMapping.ps1 -SubscriptionIds @('sub1-id','sub2-id') -OutputFile "ZoneMappings.csv" +``` + +This script provides: +- Logical to physical zone mappings per subscription +- Physical zone identifiers and names +- Essential data for multi-subscription architectures +- Compliance with data residency requirements + +**Script Output:** + +|TenantId|SubscriptionId|SubscriptionName|Location|LogicalZone|PhysicalZone|PhysicalZoneName| +|--------|--------|--------|--------|--------|--------|--------| +|...|...|...|eastus|1|A|eastus-az1| +|...|...|...|eastus|2|B|eastus-az2| +|...|...|...|eastus|3|C|eastus-az3| + +--- + +## Manual quota analysis examples + +### Check your current quota + +```powershell +$Location = 'West US 2' +$VMSize = 'Standard_D4d_v4' +$SKU = Get-AzComputeResourceSku -Location $Location | Where-Object ResourceType -eq "virtualMachines" | Select-Object Name,Family +$VMFamily = ($SKU | Where-Object Name -eq $VMSize | Select-Object -Property Family).Family +$Usage = Get-AzVMUsage -Location $Location | Where-Object { $_.Name.Value -eq $VMFamily } +``` + +--- + +## Script parameters + +### Common parameters (all scripts) + +- **SKUs**: Array of VM SKU names to analyze (e.g., `@('Standard_D2s_v5', 'Standard_E4s_v5')`) +- **Locations**: Array of Azure regions (e.g., `@('eastus', 'westus2')`) +- **SubscriptionIds**: Array of subscription IDs to analyze +- **OutputFile**: Name of the output CSV file + +--- + +### Get-AzVMQuotaUsage.ps1 Specific Parameters + +- **Threads**: Number of concurrent threads (default: 2, set to 0 for auto-detect) +- **UsePhysicalZones**: Switch to normalize output to physical zones +- **MeterDataUri**: URL for downloading VM SKU list + +--- + +### Get-AzAvailabilityZoneMapping.ps1 Specific Parameters + +- **OutputFile**: Default filename is "ZonePeers.csv" + +You'll need Azure PowerShell installed and signed in to use these scripts. + +--- + +## Troubleshooting + +### Common issues + +**Authentication Errors**: +```powershell +# Ensure you're signed in +Connect-AzAccount +# Verify current context +Get-AzContext +``` + +**Permission Denied**: +- Verify you have Reader access to target subscriptions +- Check if the subscription is in a different tenant + +**Empty Results**: +- Confirm the specified regions support the requested VM SKUs +- Verify subscription IDs are correct +- Check if regions have restricted access + +**Multi-threading Issues** (Get-AzVMQuotaUsage.ps1): +- Reduce the number of threads if hitting API limits +- Use PowerShell 7+ for optimal multi-threading support + +**Rate Limiting**: +- Reduce concurrent operations +- Add delays between API calls if necessary + +### Getting help + +For issues with these scripts: +1. Check the [Azure PowerShell documentation](https://learn.microsoft.com/en-us/powershell/azure/) +2. Review Azure subscription and quota limits +3. Contact Azure support for quota increase requests + +## Script versions + +These scripts are maintained in the [azcapman repository](https://github.com/microsoft/azcapman). Check for updates regularly to get the latest features and bug fixes. + +--- + +[^vm-quotas]: [Check vCPU quotas - Azure Virtual Machines](https://learn.microsoft.com/en-us/azure/virtual-machines/quotas) +[^az-quota]: [az quota CLI reference](https://learn.microsoft.com/en-us/cli/azure/quota?view=azure-cli-latest) +[^az-zones]: [Availability zones – physical and logical mapping](https://learn.microsoft.com/en-us/azure/reliability/availability-zones-overview#configuring-resources-for-availability-zone-support) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Show-AzVMQuotaReport.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Show-AzVMQuotaReport.ps1 new file mode 100644 index 000000000..2939144c1 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/quota/Show-AzVMQuotaReport.ps1 @@ -0,0 +1,517 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. + +<# +.SYNOPSIS + Single-threaded Azure VM quota analysis script that queries compute resource SKU availability, + quota usage, and availability zone restrictions across subscriptions. + +.DESCRIPTION + This script provides simplified quota analysis functionality for Azure VM resources. + It's designed as a streamlined version for smaller-scale analysis or educational purposes. + The script analyzes: + - Current quota usage vs. limits for VM families + - Available and restricted availability zones per SKU + - Region-level restrictions for specific VM SKUs + - Physical vs. logical availability zone mappings (optional) + + The Catalogs API is the primary SKU source. The deprecated meter data CSV is used only as a + fallback when Catalogs API lookup fails and the SKUs parameter is not provided. + + Unlike the multi-threaded Get-AzVMQuotaUsage.ps1, this version processes subscriptions + sequentially and displays results in a formatted table at the end. + +.PARAMETER SKUs + Array of VM SKU names to analyze. If not specified, resolves VM SKUs from the Azure Catalogs + API first and falls back to the deprecated meter data CSV only if that lookup fails. + Example: @('Standard_D2s_v3', 'Standard_D4s_v3', 'Standard_E4s_v5') + +.PARAMETER Locations + Array of Azure regions to analyze. If not specified, queries all physical Azure regions. + Example: @('eastus', 'westus2', 'centralus') + +.PARAMETER SubscriptionIds + Array of subscription IDs to analyze. If not specified, queries all accessible subscriptions. + Example: @('00000000-0000-0000-0000-000000000000') + +.PARAMETER MeterDataUri + Deprecated fallback source URI for normalized VM SKU data from Cost Management connector data. + Used only when the Catalogs API lookup fails and the SKUs parameter is not provided. + +.PARAMETER CatalogLocation + Azure region used for Catalogs API requests when resolving VM SKU names from the primary SKU + source. + +.PARAMETER OutputFile + Name of the output CSV file containing the analysis results. + Default: "QuotaQuery.csv" + +.PARAMETER UsePhysicalZones + Switch to normalize availability zone output to physical zones instead of logical zones. + Useful for cross-subscription deployment planning where logical zones may differ. + +.EXAMPLE + .\Show-AzVMQuotaReport.ps1 -SKUs @('Standard_D2s_v5','Standard_E4s_v5') -Locations @('eastus','westus2') + + Analyzes specific VM SKUs in specific regions and displays results in table format. + +.EXAMPLE + .\Show-AzVMQuotaReport.ps1 -UsePhysicalZones -OutputFile "MyQuotaAnalysis.csv" + + Runs full analysis with physical zone mapping and custom output filename. + +.NOTES + Requires Azure PowerShell module and authenticated session with Reader access to target subscriptions. + Catalogs API access also requires the Microsoft.Capacity/catalogs/read permission. + This is a simplified, educational version of the quota analysis functionality. + For production use with large numbers of subscriptions, consider using Get-AzVMQuotaUsage.ps1 instead. + + Output CSV contains columns: TenantId, SubscriptionId, SubscriptionName, Location, Family, Size, + RegionRestricted, ZonesPresent, ZonesRestricted, CoresUsed, CoresTotal +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('Standard_D2s_v3', 'Standard_D4s_v3')")] + [string[]]$SKUs = @(), + + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('eastus', 'westus')")] + [string[]]$Locations = @(), + + [Parameter(Mandatory = $false, HelpMessage = "e.g. @('00000000-0000-0000-0000-000000000000')")] + [string[]]$SubscriptionIds = @(), + + [Parameter(Mandatory = $false, HelpMessage = "Deprecated fallback URL to download normalized VM SKU list")] + [string]$MeterDataUri = "https://ccmstorageprod.blob.core.windows.net/instancesizeflexibility-data/isfratioblob.csv", + + [Parameter(Mandatory = $false, HelpMessage = "Azure region to query for VM catalog data")] + [string]$CatalogLocation = "eastus", + + [Parameter(Mandatory = $false, HelpMessage = "Output CSV filename")] + [string]$OutputFile = "QuotaQuery.csv", + + [Parameter(Mandatory = $false, HelpMessage = "Normalize output to physical availability zones")] + [switch]$UsePhysicalZones = $false +) + +# ================================================================================ +# HELPER FUNCTIONS +# ================================================================================ + +<# +.SYNOPSIS + Retrieves normalized VM SKU names from the Azure Catalogs API, with CSV as fallback. + +.DESCRIPTION + Queries the Azure Catalogs API for normalized VM SKU names and uses that as the + primary source for quota analysis. If the Catalogs API call fails, falls back to + AutofitComboMeterData.csv. Filters out SQL-related SKUs and returns unique SKU names. + +.OUTPUTS + Array of normalized VM SKU names (e.g., 'Standard_D2s_v3', 'Standard_E4s_v5') +#> +function Get-SKUDetails { + try { + Write-Host "Querying Azure Catalogs API for VM SKU details in $CatalogLocation" + $catalogData = Get-VMCatalogData -SubscriptionId $SubscriptionIds[0] -Location $CatalogLocation + [string[]]$skuNames = @( + ($catalogData | Select-Object -Property ArmSkuName -Unique | Where-Object { $_.ArmSkuName -notlike "*sql*" }).ArmSkuName | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + ) + + if ($skuNames.Count -eq 0) { + throw "Catalogs API returned zero VM SKUs" + } + + Write-Host "Retrieved $($skuNames.Count) unique VM SKUs from Catalogs API" + return $skuNames + } + catch { + Write-Warning "Catalogs API failed: $($_.Exception.Message)" + Write-Warning "Falling back to CSV download from $MeterDataUri" + + # Extract filename from URI for local storage (more robust approach) + [string]$meterDataFile = $MeterDataUri.Split('/')[$MeterDataUri.Split('/').Length - 1] + + # Download the Cost Management connector data file + Invoke-WebRequest -Uri $MeterDataUri -OutFile $meterDataFile + + # Parse CSV and extract unique, non-SQL VM SKUs + $meterData = Get-Content $meterDataFile | ConvertFrom-Csv + [string[]]$skuNames = @( + ($meterData | Select-Object -Property ArmSkuName -Unique | Where-Object { $_.ArmSkuName -notlike "*sql*" }).ArmSkuName | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } + ) + return $skuNames + } +} + +<# +.SYNOPSIS + Retrieves VM catalog data from the Azure Microsoft.Capacity catalogs API. + +.DESCRIPTION + Calls the Azure catalogs endpoint for VirtualMachines in the specified subscription + and location using Invoke-AzRestMethod. Follows any nextLink values until all pages + are retrieved and returns only entries that contain the required instance size + flexibility properties. + +.PARAMETER SubscriptionId + The Azure subscription ID used to scope the catalogs API request. + +.PARAMETER Location + The Azure region name used in the catalogs API filter. + +.OUTPUTS + Array of PSCustomObject values with InstanceSizeFlexibilityGroup, ArmSkuName, and Ratio properties. +#> +function Get-VMCatalogData { + param ( + [string]$SubscriptionId, + [string]$Location + ) + + $catalogItems = [System.Collections.Generic.List[object]]::new() + $path = "/subscriptions/{0}/providers/Microsoft.Capacity/catalogs?api-version=2022-11-01&reservedResourceType=VirtualMachines&location={1}" -f $SubscriptionId, $Location + $nextLink = $null + + do { + $response = if ([string]::IsNullOrWhiteSpace($nextLink)) { + Invoke-AzRestMethod -Method GET -Path $path + } + else { + Invoke-AzRestMethod -Method GET -Uri $nextLink + } + + $payload = $response.Content | ConvertFrom-Json -Depth 10 + + foreach ($item in @($payload.value)) { + $groupProperty = @($item.skuProperties | Where-Object { $_.name -eq 'ReservationsAutofitGroup' } | Select-Object -First 1) + $ratioProperty = @($item.skuProperties | Where-Object { $_.name -eq 'ReservationsAutofitRatio' } | Select-Object -First 1) + + if ([string]::IsNullOrWhiteSpace([string]$item.name) -or + $groupProperty.Count -eq 0 -or + $ratioProperty.Count -eq 0 -or + [string]::IsNullOrWhiteSpace([string]$groupProperty[0].value) -or + [string]::IsNullOrWhiteSpace([string]$ratioProperty[0].value)) { + continue + } + + $catalogItems.Add([PSCustomObject]@{ + InstanceSizeFlexibilityGroup = $groupProperty[0].value + ArmSkuName = $item.name + Ratio = $ratioProperty[0].value + }) + } + + $nextLink = $payload.nextLink + } while (-not [string]::IsNullOrWhiteSpace($nextLink)) + + return $catalogItems.ToArray() +} + +<# +.SYNOPSIS + Retrieves all accessible subscription IDs within the current tenant. + +.DESCRIPTION + Gets all Azure subscriptions that the current authenticated user has access to + within the current tenant context. Used when no specific subscription IDs are provided. + +.OUTPUTS + Array of subscription ID strings +#> +function Get-SubscriptionIds { + Write-Host "Listing Subscriptions" + return (Get-AzSubscription -TenantId ((Get-AzContext).Tenant.TenantId) | Select-Object -ExpandProperty SubscriptionId) +} + +<# +.SYNOPSIS + Extracts the last character from a string. + +.DESCRIPTION + Utility function used to extract the physical zone identifier from the full physical zone name. + Physical zones are typically identified by the last character (e.g., 'A', 'B', 'C') of the + full physical zone string (e.g., "eastus-az1" -> "1", "westus2-azA" -> "A"). + +.PARAMETER inputString + The input string to extract the last character from. + +.OUTPUTS + The last character of the input string, or empty string if input is null/empty. +#> +function Get-LastChar { + param ( + [string]$inputString + ) + + # Handle null or empty input + if ([string]::IsNullOrEmpty($inputString)) { + return "" + } + + # Additional length check for safety (though redundant with IsNullOrEmpty) + if ($inputString.Length -lt 1) { + return "" + } + + # Return the last character + return $inputString[-1] +} + +<# +.SYNOPSIS + Retrieves all physical Azure regions. + +.DESCRIPTION + Gets all Azure regions that are physical locations (not logical regions) + and have a defined physical location. Filters out logical regions and + regions without physical presence. + +.OUTPUTS + Array of Azure region names (e.g., 'eastus', 'westus2', 'centralus') +#> +function Get-Locations { + Write-Host "Listing Locations" + return (Get-AzLocation | Where-Object { $_.RegionType -eq 'Physical' -and $_.PhysicalLocation -ne "" -and $_.Location } | Select-Object -Property Location -Unique).Location +} + +<# +.SYNOPSIS + Retrieves availability zone peering information for a specific subscription. + +.DESCRIPTION + Queries the Azure REST API to get detailed availability zone mapping information + for all regions within a subscription. This information shows how logical zones + (1, 2, 3) map to physical zones for each region. + +.PARAMETER SubscriptionId + The Azure subscription ID to query for zone peering information. + +.OUTPUTS + Array of location objects containing availability zone mapping details for all regions. + +.NOTES + Uses the Azure REST API directly as this detailed zone mapping information is not + available through standard PowerShell cmdlets. +#> +function Get-ZonePeers { + param ( + [string]$SubscriptionId + ) + Write-Host "Get Zone Peering Information for subscription $SubscriptionId" + + # Construct REST API URI for location zone mappings using subscription-specific endpoint + $uri = "{0}subscriptions/{1}/locations?api-version=2022-12-01" -f $resourceManagerUrl, $SubscriptionId + + # Call Azure REST API to get comprehensive location and zone mapping data + $response = Invoke-AzRest -Method GET -Uri $uri + return ($response.Content | ConvertFrom-Json).value +} + +<# +.SYNOPSIS + Analyzes VM quota usage and restrictions for a specific subscription. + +.DESCRIPTION + Core function that performs detailed quota analysis for a single subscription. + This simplified version processes subscriptions sequentially and provides + detailed console output showing progress through regions and SKUs. + +.PARAMETER SubscriptionId + The Azure subscription ID to analyze. + +.PARAMETER Locations + Array of Azure regions to analyze within this subscription. + +.PARAMETER SKUs + Array of VM SKU names to analyze. + +.PARAMETER OutputFile + Name of the CSV file to append results to. + +.OUTPUTS + Appends CSV rows to the output file with quota and restriction details. + Provides console output showing analysis progress. + +.NOTES + This function includes Microsoft.Capacity resource provider registration + to ensure quota APIs are available. Also provides visual progress feedback + with dots for each SKU processed. +#> +function Get-QuotaDetails { + param ( + [string]$SubscriptionId, + [string[]]$Locations, + [string[]]$SKUs, + [string]$OutputFile + ) + + try { + # Get subscription details and validate access + $Subscription = Get-AzSubscription -SubscriptionId $SubscriptionId -WarningAction SilentlyContinue + if ($null -eq $Subscription) { + throw "Subscription not found" + } + + # Set context to target subscription for all subsequent queries + Set-AzContext -SubscriptionId $Subscription.Id -WarningAction SilentlyContinue | Out-Null + + # Ensure Microsoft.Capacity resource provider is registered for quota APIs + if ((Get-AzResourceProvider -ListAvailable | Where-Object { $_.ProviderNamespace -like 'Microsoft.Capacity' }).RegistrationState -notlike 'Registered') { + try { + Register-AzResourceProvider -ProviderNamespace Microsoft.Capacity + } + catch { + Write-Host "Failed Registering Resource Provider: Microsoft.Capacity" -ForegroundColor Yellow + } + } + + # Get zone peering information if physical zone mapping is requested + if($UsePhysicalZones) + { + $zonePeers = Get-ZonePeers -SubscriptionId $SubscriptionId + if ($zonePeers.Count -eq 0) { + Write-Host "No Zone Peering Information found for subscription $SubscriptionId" -ForegroundColor Yellow + } + } + + # Process each location within the subscription + Write-Host "Querying Subscription: $($Subscription.Name)" + foreach ($Location in $Locations) { + Write-Host " Querying Region: $Location" + + # Get all VM SKUs available in this location + $computeSKUs = Get-AzComputeResourceSku -Location $Location -ErrorAction SilentlyContinue | Where-Object { $_.ResourceType -eq 'virtualMachines' } + + # Get current VM quota usage for this location + $vmUsage = Get-AZVMUsage -Location $Location -ErrorAction SilentlyContinue + + # Get availability zone mappings for this location (if using physical zones) + $availabilityZoneMappings = ($zonePeers | Where-Object { $_.name -like $Location -and $_.type -eq "Region"}).availabilityZoneMappings + + # Process each requested SKU with visual progress indicator + foreach ($SKU in $SKUs) { + Write-Host -NoNewline "." # Progress indicator for each SKU processed + + # Find the specific SKU data for this location + $filteredSku = $computeSKUs | Where-Object { $_.Name.ToLowerInvariant() -eq $SKU.ToLowerInvariant() -and $_.LocationInfo.Location -like $Location } + + # Find the quota usage data for this SKU's family + $skuUsage = $vmUsage | Select-Object -ExpandProperty Name -Property CurrentValue, Limit | Where-Object { $_.Value -eq $filteredSku.Family } + + # Skip if SKU not found in this location + if ($null -eq $filteredSku) { + continue + } + + # Process availability zones (logical or physical) + $zones = @($filteredSku.LocationInfo.Zones) + if($UsePhysicalZones) + { + # Convert logical zones to physical zones + for ($i = 0; $i -lt $zones.Length; $i++) { + $zones[$i] = Get-LastChar(($availabilityZoneMappings | Where-Object {$_.LogicalZone -like $zones[$i]}).physicalZone) + } + } + + # Create the quota analysis object + $auditedSku = [PSCustomObject]@{ + TenantId = $Subscription.TenantId + SubscriptionId = $Subscription.Id + SubscriptionName = $Subscription.Name + Location = $Location + Family = $skuUsage.LocalizedValue # VM family name (e.g., "Dv3 Family vCPUs") + Size = $filteredSku.Name # Specific SKU (e.g., "Standard_D2s_v3") + RegionRestricted = 'False' # Whether SKU is restricted in this entire region + ZonesPresent = ($zones | Sort-Object) -join "," # Available zones for this SKU + ZonesRestricted = '' # Zones where SKU is restricted + CoresUsed = $skuUsage.CurrentValue # Current quota usage + CoresTotal = $skuUsage.Limit # Total quota limit + } + + # Process any restrictions on this SKU + foreach ($restriction in $filteredSku.Restrictions) { + if ($restriction.Type -like "Zone") { + # Handle zone-specific restrictions + $zoneRestrictions = @($restriction.RestrictionInfo.Zones) + if($UsePhysicalZones) + { + # Convert restricted logical zones to physical zones + for ($i = 0; $i -lt $zoneRestrictions.Length; $i++) { + $zoneRestrictions[$i] = Get-LastChar(($availabilityZoneMappings | Where-Object {$_.LogicalZone -like $zoneRestrictions[$i]}).physicalZone) + } + } + $auditedSku.ZonesRestricted = ($zoneRestrictions | Sort-Object) -join "," + } + elseif ($restriction.Type -like "Location") { + # Handle region-wide restrictions + $auditedSku.RegionRestricted = 'True' + } + } + + # Append the result to the CSV file + $auditedSku | ConvertTo-Csv -NoHeader | Out-File -Force -Append -FilePath .\$OutputFile + } + Write-Host "" # New line after completing all SKUs in this region + } + } + catch { + Write-Host "Failed Querying Subscription ID: $SubscriptionId" -ForegroundColor Yellow + $_.Exception.Message + } +} + +# ================================================================================ +# MAIN SCRIPT EXECUTION +# ================================================================================ + +# Set error handling and output preferences +$ErrorActionPreference = 'Stop' # Stop execution on any error +$VerbosePreference = 'SilentlyContinue' # Suppress verbose output for cleaner execution + +# Define CSV header structure for output file +$csvHeaderString = "TenantId,SubscriptionId,SubscriptionName,Location,Family,Size,RegionRestricted,ZonesPresent,ZonesRestricted,CoresUsed,CoresTotal" + +# Initialize output file with CSV headers +$csvHeaderString | Out-File -Force -FilePath $OutputFile + +# Get the Azure Resource Manager URL for the current Azure environment +# This is needed for constructing REST API calls and may vary by cloud (Public, Government, etc.) +$resourceManagerUrl = (Get-AzContext).Environment.ResourceManagerUrl + +# Populate subscription list if not provided by user +if ($SubscriptionIds.Count -eq 0) { + $SubscriptionIds = Get-SubscriptionIds +} + +# Populate locations list if not provided by user +if ($Locations.Count -eq 0) { + $Locations = Get-Locations | Sort-Object +} + +# Populate SKUs list if not provided by user +if ($SKUs.Count -eq 0) { + $SKUs = Get-SKUDetails +} + +# Display configuration information +if($UsePhysicalZones) +{ + Write-Host "Output will be normalized to physical availability zones" +} +else { + Write-Host "Output will not be normalized to physical availability zones" +} + +# Execute quota analysis sequentially for each subscription +# This simplified version processes one subscription at a time for educational clarity +foreach ($SubscriptionId in $SubscriptionIds) { + Get-QuotaDetails -SubscriptionId $SubscriptionId -Locations $Locations -SKUs $SKUs -outputFile $OutputFile +} + +# Display results in formatted table for immediate review +Write-Host "" +Write-Host "Analysis complete. Displaying results:" +Get-Content $OutputFile | ConvertFrom-Csv | Format-Table -AutoSize diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/Get-BenefitRecommendations.ps1 b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/Get-BenefitRecommendations.ps1 new file mode 100644 index 000000000..b7d6ce71c --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/Get-BenefitRecommendations.ps1 @@ -0,0 +1,74 @@ + +<# +.SYNOPSIS + Get Azure Cost Management benefit recommendations for savings plans and reserved instances. + +.DESCRIPTION + This script queries the Azure Cost Management API to retrieve benefit recommendations + based on historical usage patterns. It helps identify opportunities for cost savings + through Azure savings plans and reserved instances. + +.PARAMETER BillingScope + The billing scope to query. Can be a billing account or subscription. + Examples: + - "providers/Microsoft.Billing/billingAccounts/12345678" + - "subscriptions/12345678-1234-1234-1234-123456789012" + +.PARAMETER LookBackPeriod + Historical period to analyze for recommendations. + Valid values: Last7Days, Last30Days, Last60Days + Default: Last7Days + +.PARAMETER Term + Commitment term for savings plans. + Valid values: P1Y (1 year), P3Y (3 years) + Default: P3Y + +.EXAMPLE + .\Get-BenefitRecommendations.ps1 -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" + + Gets 3-year savings plan recommendations for a subscription based on last 7 days usage. + +.EXAMPLE + .\Get-BenefitRecommendations.ps1 -BillingScope "providers/Microsoft.Billing/billingAccounts/12345678" -LookBackPeriod "Last30Days" -Term "P1Y" + + Gets 1-year savings plan recommendations for a billing account based on last 30 days usage. + +.NOTES + Requires Azure PowerShell module and Cost Management Reader permissions on the specified scope. + + To find your billing account: Get-AzBillingAccount + To find subscriptions: Get-AzSubscription +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $true, HelpMessage = "Billing scope (billing account or subscription)")] + [string] + $BillingScope, + + [Parameter()] + [ValidateSet('Last7Days', 'Last30Days', 'Last60Days')] + [string] + $LookBackPeriod = 'Last7Days', + + [Parameter()] + [ValidateSet('P1Y', 'P3Y')] + [string] + $Term = 'P3Y' +) + +$url="https://management.azure.com/{0}/providers/Microsoft.CostManagement/benefitRecommendations?`$filter=properties/lookBackPeriod eq '{1}' AND properties/term eq '{2}'&`$expand=properties/usage,properties/allRecommendationDetails&api-version=2024-08-01" -f $BillingScope, $lookBackPeriod, $term +$uri=[uri]::new($url) +$result = Invoke-AzRestMethod -Uri $uri.AbsoluteUri -Method GET +$jsonResult = $result.Content | ConvertFrom-Json + +Write-Output "" +Write-Output "Raw output" +$result.Content +Write-Output "" +Write-Output "Recommended savings plan" +$jsonResult.value.properties.recommendationDetails | Format-Table +Write-Output "" +Write-Output "All savings plan recommendations" +$jsonResult.value.properties.allRecommendationDetails.value | Format-Table \ No newline at end of file diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/README.md new file mode 100644 index 000000000..3e099bf4d --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/rate/README.md @@ -0,0 +1,107 @@ +--- +title: Cost Analysis +--- + +# Cost analysis scripts + +Azure Cost Management tools for analyzing savings plan purchase recommendations and storage costs to optimize your Azure spend. + +> [!TIP] +> Use these scripts when you want to turn Azure Cost Management savings plan purchase recommendations into repeatable analyses for finance and operations teams.[^benefit-api] + +--- + +## Available scripts + +### Get-BenefitRecommendations.ps1 + +Queries the Azure Cost Management API to retrieve savings plan purchase recommendations based on your historical compute usage patterns. + +**What it does:** +- Analyzes historical compute usage patterns (7, 30, or 60 days lookback) +- Provides up to 10 savings plan commitment recommendations for specified term (1-year or 3-year) +- Calculates potential cost savings compared to pay-as-you-go pricing +- Shows commitment amounts and usage coverage percentages +- Returns both the top recommended savings plan and all available options + +**Output includes:** +- **Raw JSON response** from Cost Management API (for debugging/verification) +- **Recommended savings plan** with detailed financial analysis: + - Hourly commitment amount + - Total savings amount and percentage + - Usage coverage and utilization percentages + - Overage costs and wastage estimates +- **All savings plan recommendations** showing various commitment levels and their projected performance + +--- + +### Output field descriptions + +The formatted tables include these key financial metrics: + +| Field | Description | +|-------|-------------| +| **averageUtilizationPercentage** | Estimated average utilization percentage for the look-back period with this commitment | +| **commitmentAmount** | The hourly commitment amount at the specified granularity | +| **coveragePercentage** | Estimated benefit coverage percentage for the look-back period with this commitment | +| **savingsAmount** | The total amount saved for the look-back period by purchasing this savings plan | +| **savingsPercentage** | The savings percentage for the look-back period by purchasing this savings plan | +| **totalCost** | Total projected cost (sum of benefit cost and overage cost) | +| **benefitCost** | The estimated cost with benefit for the look-back period (commitmentAmount × totalHours) | +| **overageCost** | The difference between total cost and benefit cost for the look-back period | +| **wastageCost** | Estimated unused portion of the benefit cost | + +--- + +## Prerequisites and Parameters + +**Prerequisites:** +- Azure PowerShell module (`Install-Module -Name Az`) +- Authenticated Azure session (`Connect-AzAccount`) +- Cost Management Reader permissions on the billing scope +- Valid billing account ID or subscription ID + +**Parameters:** +- `BillingScope` (required): Billing account, subscription, or resource group scope + - Billing Account: `providers/Microsoft.Billing/billingAccounts/{billingAccountId}` + - Subscription: `subscriptions/{subscriptionId}` + - Resource Group: `subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}` +- `LookBackPeriod`: Historical analysis period (Last7Days, Last30Days, Last60Days) - default: Last7Days +- `Term`: Savings plan term (P1Y for 1-year, P3Y for 3-year) - default: P3Y + +**Note:** The API returns recommendations with shared scope by default, analyzing usage across the entire billing scope for optimal savings. + +--- + +## Usage examples + +```powershell +# Find your billing scope first +Get-AzBillingAccount # For billing account scope +Get-AzSubscription # For subscription scope + +# Basic usage with subscription scope +.\Get-BenefitRecommendations.ps1 -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012" + +# Advanced usage with billing account, 30-day lookback, and 1-year term +.\Get-BenefitRecommendations.ps1 -BillingScope "providers/Microsoft.Billing/billingAccounts/12345678" -LookBackPeriod "Last30Days" -Term "P1Y" + +# Resource group scope analysis +.\Get-BenefitRecommendations.ps1 -BillingScope "subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/myResourceGroup" +``` + +--- + +## About the API + +This script uses the Azure Cost Management [Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations) to provide **savings plan purchase recommendations**. + +The API analyzes your actual compute usage patterns and calculates optimal hourly commitment amounts that minimize total costs compared to pay-as-you-go pricing. + +Recommendations include detailed financial metrics: commitment amounts, projected savings percentages, coverage percentages, utilization rates, and potential overage/wastage costs. The raw JSON output provides full API response details, while formatted tables present actionable purchase recommendations. + +**Source**: [Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations) + +--- + +[^benefit-api]: [Benefit Recommendations API](https://learn.microsoft.com/en-us/rest/api/cost-management/benefit-recommendations) diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/README.md b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/README.md new file mode 100644 index 000000000..22df1c0e6 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/README.md @@ -0,0 +1,92 @@ +--- +title: Serverless SQL storage audit +--- + +# Serverless SQL storage audit + +Azure SQL Database [serverless compute tier](https://learn.microsoft.com/en-us/azure/azure-sql/database/serverless-tier-overview) [bills on allocated storage, not max size](https://learn.microsoft.com/en-us/azure/azure-sql/database/serverless-tier-overview#billing). Allocated space grows with writes and doesn't auto-shrink—even after deletes. This workbook surfaces the gap between allocated and used storage across all serverless SQL databases in the tenant so you can target `DBCC SHRINKDATABASE` operations where they'll save money. + +## What it measures + +| Metric | Source | Description | +|--------|--------|-------------| +| Max size (GB) | [Azure Resource Graph](https://learn.microsoft.com/en-us/azure/governance/resource-graph/overview) | Configured ceiling (`properties.maxSizeBytes`). Doesn't affect billing directly. | +| Allocated | [Azure Monitor](https://learn.microsoft.com/en-us/azure/azure-sql/database/monitoring-sql-database-azure-monitor) `allocated_data_storage` | What you [pay for](https://learn.microsoft.com/en-us/azure/azure-sql/database/serverless-tier-overview#billing). Grows with writes, never auto-shrinks. | +| Used | [Azure Monitor](https://learn.microsoft.com/en-us/azure/azure-sql/database/monitoring-sql-database-azure-monitor) `storage` | Actual data on disk. | + +**Waste** = Allocated minus Used. That's the reclamation target. Compare the two columns in the workbook to identify databases worth shrinking. + +## How it works + +The workbook uses the [merge data source](https://learn.microsoft.com/en-us/azure/azure-monitor/visualize/workbooks-data-sources#merge) pattern to join two queries: + +1. **Resource Graph** finds all `GP_S_Gen*` databases across every subscription selected in the subscription picker +2. **Azure Monitor metrics** (hidden step) pulls `allocated_data_storage` and `storage` for each discovered database +3. **Merge** left outer joins on resource ID and renders a single sortable table + +The subscription picker scopes the Resource Graph query via `crossComponentResources`. The merge's left outer join ensures databases appear even when metrics haven't populated yet. + +## Deploy + +### ARM template + +```bash +az deployment group create \ + -g \ + --template-file workbook.json +``` + +The workbook deploys as a `Microsoft.Insights/workbooks` resource. It doesn't require a Log Analytics workspace—Resource Graph and Azure Monitor metrics are the only data sources. + +### Find the workbook after deployment + +Go to **Azure Monitor** > **Workbooks** > select the resource group you deployed to. The workbook appears as **Serverless SQL Storage - FinOps Audit**. + +### Parameters + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `workbookDisplayName` | Serverless SQL Storage - FinOps Audit | Display name in the Azure portal | +| `workbookSourceId` | azure monitor | Source binding for the workbook | + +### Workbook controls + +| Control | Options | Description | +|---------|---------|-------------| +| Subscriptions | Multi-select picker | Scopes the Resource Graph query to selected subscriptions | +| Time range | 1h, 4h, 12h, 1d, 3d, 7d, 30d, 90d | Adjusts the metrics query window. Use 30d or 90d for trend analysis. | + +## Prerequisites + +- The deploying identity needs **Reader** on every subscription the workbook should scan (Resource Graph respects RBAC) +- Azure Monitor metrics are available without additional configuration for SQL databases +- No agents, extensions, or diagnostic settings required + +## Reclaiming allocated storage + +After identifying databases with high waste, connect to each database and run: + +```sql +DBCC SHRINKDATABASE (N'', 10); +``` + +The `10` specifies the target free space percentage after shrink. [DBCC SHRINKDATABASE reference](https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-shrinkdatabase-transact-sql). + +For file-level control: + +```sql +DBCC SHRINKFILE (N'', ); +``` + +[DBCC SHRINKFILE reference](https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-shrinkfile-transact-sql). + +**Caveat:** Shrinking causes [index fragmentation](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes). Rebuild indexes after shrinking production databases to avoid query performance degradation. + +## Limitations + +- **500 database cap**: The metrics step processes up to 500 databases. If you have more, use the subscription picker to filter to a smaller set. +- **No computed waste column**: Workbook merge steps don't support cross-column arithmetic. The workbook shows Allocated and Used side by side—compare visually, or use the companion CLI script for computed waste and utilization percentages. +- Resource Graph indexing can lag up to 5 minutes after a database is created or deleted. +- Metrics aren't available for databases created within the last few minutes. +- The merge step joins on resource ID; if a database is deleted between the Resource Graph query and the metrics query, that row shows null for Allocated and Used. +- Max size reduction doesn't reclaim allocated storage—only `DBCC SHRINKDATABASE` or `DBCC SHRINKFILE` does. diff --git a/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/workbook.json b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/workbook.json new file mode 100644 index 000000000..7f735d9f6 --- /dev/null +++ b/src/templates/sre-agent/recipes/finops-hub/config/skills/azure-capacity-management/references/scripts/serverless-sql-storage/workbook.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "workbookDisplayName": { + "type": "string", + "defaultValue": "Serverless SQL Storage - FinOps Audit" + }, + "workbookSourceId": { + "type": "string", + "defaultValue": "azure monitor" + } + }, + "variables": { + "workbookId": "[guid(resourceGroup().id, parameters('workbookDisplayName'))]" + }, + "resources": [ + { + "type": "Microsoft.Insights/workbooks", + "apiVersion": "2023-06-01", + "name": "[variables('workbookId')]", + "location": "[resourceGroup().location]", + "kind": "shared", + "properties": { + "displayName": "[parameters('workbookDisplayName')]", + "category": "workbook", + "sourceId": "[parameters('workbookSourceId')]", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"# Serverless SQL storage audit\\nIdentifies allocated vs used storage across all serverless SQL databases (`GP_S_Gen*`) in the selected subscriptions. Allocated storage is what you're [billed for](https://learn.microsoft.com/en-us/azure/azure-sql/database/serverless-tier-overview#billing)\\u2014it grows with writes and doesn't auto-shrink. Compare the **Allocated** and **Used** columns to find reclamation targets.\"},\"name\":\"header\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"7b3c9e1a-4f2d-4a8b-9c6e-1d3f5a7b9c2e\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Subscriptions\",\"type\":6,\"isRequired\":true,\"multiSelect\":true,\"includeAll\":true,\"defaultValue\":\"value::all\",\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"includeAll\":true}},{\"id\":\"8d4e0f2b-5a3c-4b9d-ae7f-2e4a6b8c0d3f\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"typeSettings\":{\"selectableValues\":[{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":2592000000},{\"durationMs\":7776000000}]},\"timeContext\":{\"durationMs\":86400000},\"value\":{\"durationMs\":86400000}}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.resourcegraph/resources\"},\"name\":\"parameters\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"resources\\n| where type =~ 'microsoft.sql/servers/databases'\\n| where sku.name startswith 'GP_S_Gen'\\n| project id, dbName=name, serverName=tostring(split(id, '/')[8]),\\n resourceGroup, subscriptionId, location,\\n skuName=sku.name, maxSizeGB=properties.maxSizeBytes / 1073741824\",\"size\":0,\"queryType\":1,\"resourceType\":\"microsoft.resourcegraph/resources\",\"crossComponentResources\":[\"{Subscriptions}\"],\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"id\",\"formatter\":5},{\"columnMatch\":\"subscriptionId\",\"formatter\":5},{\"columnMatch\":\"maxSizeGB\",\"formatter\":0,\"numberFormat\":{\"unit\":5,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":0}}}],\"labelSettings\":[{\"columnId\":\"dbName\",\"label\":\"Database\"},{\"columnId\":\"serverName\",\"label\":\"Server\"},{\"columnId\":\"resourceGroup\",\"label\":\"Resource group\"},{\"columnId\":\"location\",\"label\":\"Region\"},{\"columnId\":\"skuName\",\"label\":\"SKU\"},{\"columnId\":\"maxSizeGB\",\"label\":\"Max size (GB)\"}]}},\"name\":\"serverlessDatabases\"},{\"type\":10,\"content\":{\"chartId\":\"c5e8a2f1-6b3d-4c9a-b7e2-3f5a1d8c4e6b\",\"version\":\"MetricsItem/2.0\",\"size\":0,\"chartType\":0,\"resourceType\":\"microsoft.sql/servers/databases\",\"metricScope\":0,\"resourceIds\":[\"resources\\n| where type =~ 'microsoft.sql/servers/databases'\\n| where sku.name startswith 'GP_S_Gen'\\n| project id\\n| order by id asc\"],\"timeContextFromParameter\":\"TimeRange\",\"timeContext\":{\"durationMs\":86400000},\"metrics\":[{\"namespace\":\"microsoft.sql/servers/databases\",\"metric\":\"microsoft.sql/servers/databases--allocated_data_storage\",\"aggregation\":4,\"columnName\":\"Allocated\"},{\"namespace\":\"microsoft.sql/servers/databases\",\"metric\":\"microsoft.sql/servers/databases--storage\",\"aggregation\":4,\"columnName\":\"Used\"}],\"gridFormatType\":1,\"resourceLimit\":500,\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Metric\",\"formatter\":5},{\"columnMatch\":\"Allocated\",\"formatter\":0,\"numberFormat\":{\"unit\":2,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2}}},{\"columnMatch\":\"Used\",\"formatter\":0,\"numberFormat\":{\"unit\":2,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2}}},{\"columnMatch\":\"Timeline\",\"formatter\":5},{\"columnMatch\":\"microsoft.sql/servers/databases--allocated_data_storage\",\"formatter\":5},{\"columnMatch\":\"microsoft.sql/servers/databases--storage\",\"formatter\":5}]}},\"conditionalVisibility\":{\"parameterName\":\"neverShow\",\"comparison\":\"isEqualTo\",\"value\":\"true\"},\"name\":\"storageMetrics\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"{\\\"version\\\":\\\"Merge/1.0\\\",\\\"merges\\\":[{\\\"id\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\",\\\"mergeType\\\":\\\"leftouter\\\",\\\"leftTable\\\":\\\"serverlessDatabases\\\",\\\"rightTable\\\":\\\"storageMetrics\\\",\\\"leftColumn\\\":\\\"id\\\",\\\"rightColumn\\\":\\\"Name\\\"}],\\\"projectRename\\\":[{\\\"originalName\\\":\\\"[serverlessDatabases].dbName\\\",\\\"mergedName\\\":\\\"Database\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[serverlessDatabases].serverName\\\",\\\"mergedName\\\":\\\"Server\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[serverlessDatabases].location\\\",\\\"mergedName\\\":\\\"Region\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[serverlessDatabases].skuName\\\",\\\"mergedName\\\":\\\"SKU\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[serverlessDatabases].maxSizeGB\\\",\\\"mergedName\\\":\\\"Max size (GB)\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[storageMetrics].Allocated\\\",\\\"mergedName\\\":\\\"Allocated\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[storageMetrics].Used\\\",\\\"mergedName\\\":\\\"Used\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[serverlessDatabases].subscriptionId\\\",\\\"mergedName\\\":\\\"Subscription\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[serverlessDatabases].resourceGroup\\\",\\\"mergedName\\\":\\\"Resource group\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"},{\\\"originalName\\\":\\\"[serverlessDatabases].id\\\",\\\"mergedName\\\":\\\"id\\\",\\\"fromId\\\":\\\"d9f2a1b3-7c4e-4d8a-b5f1-6e3a9c2d7b4f\\\"}]}\",\"size\":0,\"queryType\":7,\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"id\",\"formatter\":5},{\"columnMatch\":\"Subscription\",\"formatter\":5},{\"columnMatch\":\"Max size \\\\(GB\\\\)\",\"formatter\":0,\"numberFormat\":{\"unit\":5,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":0}}},{\"columnMatch\":\"Allocated\",\"formatter\":0,\"numberFormat\":{\"unit\":2,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2}}},{\"columnMatch\":\"Used\",\"formatter\":0,\"numberFormat\":{\"unit\":2,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2}}}],\"sortBy\":[{\"itemKey\":\"Allocated\",\"sortOrder\":2}],\"labelSettings\":[{\"columnId\":\"Database\",\"label\":\"Database\"},{\"columnId\":\"Server\",\"label\":\"Server\"},{\"columnId\":\"Region\",\"label\":\"Region\"},{\"columnId\":\"SKU\",\"label\":\"SKU\"},{\"columnId\":\"Max size (GB)\",\"label\":\"Max size (GB)\"},{\"columnId\":\"Allocated\",\"label\":\"Allocated\"},{\"columnId\":\"Used\",\"label\":\"Used\"},{\"columnId\":\"Resource group\",\"label\":\"Resource group\"}]}},\"name\":\"mergedStorageView\"},{\"type\":1,\"content\":{\"json\":\"---\\n### How to read this table\\n- **Allocated** = storage you're [billed for](https://learn.microsoft.com/en-us/azure/azure-sql/database/serverless-tier-overview#billing). Grows with writes, never auto-shrinks.\\n- **Used** = actual data on disk.\\n- **Waste** = Allocated minus Used. Compare the two columns to find reclamation targets.\\n- **Max size (GB)** = configured ceiling. Reducing it doesn't reclaim allocated space.\\n- Run [`DBCC SHRINKDATABASE`](https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-shrinkdatabase-transact-sql) to reclaim. Shrinking causes [index fragmentation](https://learn.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes)\\u2014rebuild indexes after shrinking production databases.\\n- [Serverless compute tier overview](https://learn.microsoft.com/en-us/azure/azure-sql/database/serverless-tier-overview)\\n\\n> This workbook displays up to 500 databases. If you have more, filter by subscription using the picker above.\"},\"name\":\"footer\"}],\"fallbackResourceIds\":[\"azure monitor\"]}" + } + } + ] +} diff --git a/src/templates/sre-agent/recipes/finops-hub/expected-config.json b/src/templates/sre-agent/recipes/finops-hub/expected-config.json index dae5444d1..d4e041716 100644 --- a/src/templates/sre-agent/recipes/finops-hub/expected-config.json +++ b/src/templates/sre-agent/recipes/finops-hub/expected-config.json @@ -1,7 +1,7 @@ { "agent": { - "accessLevel": "High", - "actionMode": "Autonomous", + "accessLevel": "Low", + "actionMode": "autonomous", "upgradeChannel": "Preview", "defaultModelProvider": "MicrosoftFoundry", "experimentalSettings": [ @@ -9,9 +9,7 @@ "EnableWorkspaceTools" ] }, - "subscriptionRoleAssignments": [ - "Reader" - ], + "subscriptionRoleAssignments": [], "builtInTools": { "enabled": [ "PlotAreaChartWithCorrelation", diff --git a/src/templates/sre-agent/submodules/azcapman b/src/templates/sre-agent/submodules/azcapman deleted file mode 160000 index 7facce3fc..000000000 --- a/src/templates/sre-agent/submodules/azcapman +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7facce3fc438613ad990f00af6949291599416c0 From f7cca4358c4b77d6b697b9ae045464976ac4cdf2 Mon Sep 17 00:00:00 2001 From: msbrett Date: Wed, 17 Jun 2026 10:50:01 -0700 Subject: [PATCH 17/19] fix(sre-agent): unify template with secure deploy defaults and clean artifacts Collapse the recipe and deploy slices into one coherent template PR (the recipe is a subdirectory of the template and is packaged into the deploy artifacts, so they cannot be split into independently-buildable PRs). Brings the deploy-side security fixes onto the unified template and regenerates the committed artifacts: - Secure-by-default: portal/CLI accessLevel=Low (read-only) + autonomous reporting; subscription Reader off by default (Roland H1). - Recipe package integrity: SHA-256 (fail-closed) + https host allowlist before Expand-Archive; hash now injected into azuredeploy.json at package time (Roland H2). - Removed dead bin/telemetry.sh + hardcoded App Insights key + no-op opt-out (Roland M4). - Parameterized deployer principalType for CI/CD OIDC service-principal deploys. - Regenerated docs/deploy/sre-agent/{14.0,latest} azuredeploy.json + createUiDefinition + recipe zip from scrubbed queries and vendored capacity skill: zips are leak-free and the integrity hash matches. All 39 SRE deploy tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs-mslearn/toolkit/sre-agent/deploy.md | 16 +- docs/deploy/sre-agent/14.0/azuredeploy.json | 79 ++++++++-- .../sre-agent/14.0/createUiDefinition.json | 8 +- .../sre-agent/14.0/sre-agent-recipe.zip | Bin 346636 -> 342755 bytes docs/deploy/sre-agent/latest/azuredeploy.json | 79 ++++++++-- .../sre-agent/latest/createUiDefinition.json | 8 +- .../sre-agent/latest/sre-agent-recipe.zip | Bin 346636 -> 342755 bytes .../Unit/Templates.SreAgent.Deploy.Tests.ps1 | 143 +++++++++++++++++- src/scripts/Package-Toolkit.ps1 | 17 +++ src/templates/sre-agent/README.md | 11 +- src/templates/sre-agent/bin/deploy.sh | 16 +- src/templates/sre-agent/bin/telemetry.sh | 53 ------- .../sre-agent/createUiDefinition.json | 8 +- .../examples/ci-cd/github-actions-deploy.yml | 1 + src/templates/sre-agent/infra/main.bicep | 13 +- .../infra/modules/apply-extras.bicep | 7 + .../sre-agent/infra/modules/sre-agent.bicep | 6 +- src/templates/sre-agent/infra/resources.bicep | 5 + .../infra/scripts/Apply-SreAgentExtras.ps1 | 24 +++ src/templates/sre-agent/main.bicep | 17 ++- 20 files changed, 395 insertions(+), 116 deletions(-) delete mode 100755 src/templates/sre-agent/bin/telemetry.sh diff --git a/docs-mslearn/toolkit/sre-agent/deploy.md b/docs-mslearn/toolkit/sre-agent/deploy.md index 25d5ed821..86269d484 100644 --- a/docs-mslearn/toolkit/sre-agent/deploy.md +++ b/docs-mslearn/toolkit/sre-agent/deploy.md @@ -3,7 +3,7 @@ title: Deploy Azure SRE Agent with the FinOps toolkit description: Deploy the FinOps toolkit Azure SRE Agent template from the Azure portal or CLI, connect it to a FinOps hub Data Explorer cluster, and validate the deployment. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: tutorial ms.service: finops ms.subservice: finops-toolkit @@ -79,8 +79,7 @@ bash bin/deploy.sh \ [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] \ [--target-resource-group ...] \ [--dry-run] \ - [--force] \ - [--no-telemetry] + [--force] ``` `bin/deploy.sh --help` is the CLI contract: @@ -100,11 +99,10 @@ Optional: --cluster-uri Kusto connector URI, including database name. Example: https://..kusto.windows.net/Hub --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. - --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --no-subscription-reader Do not assign Reader at subscription scope. Default: no subscription Reader (opt-in with --subscription-reader). --deploy-name Deployment name override. Defaults to a deterministic name. --dry-run Validate inputs and write parameters without Azure calls. --force Accepted for compatibility. - --no-telemetry Accepted for compatibility. -h, --help Show this help. ``` @@ -130,7 +128,7 @@ The recipe defaults the parent SRE Agent to Azure OpenAI provider-level routing Resource names are deterministic for the subscription ID, agent resource group ID, and agent name. Use the same values to update an existing deployment. Post-provisioning deletes existing scheduled tasks with the recipe's task names before applying manifests so redeployments don't create duplicate automations. `--deploy-name` only changes the ARM deployment record and local build directory. -The deployment assigns `Reader` at subscription scope by default so subscription inventory, Resource Graph, capacity, quota, and monitoring-coverage tools can inspect the deployment subscription. Pass `--no-subscription-reader` only when you grant equivalent read access another way. +The agent defaults to Low (read-only) access level for reporting and analysis without modification risk. Subscription Reader is opt-in (`--subscription-reader`) and only required for subscription-wide ARM-backed reports; otherwise the agent scopes reads via target resource groups. This posture allows the 19 scheduled reports to run autonomously while eliminating write blast radius. If `--cluster-uri` points to an Azure Data Explorer cluster with `publicNetworkAccess` set to `Disabled`, the script still deploys all resources, assigns the agent identity `AllDatabasesViewer`, and creates the `finops-hub-kusto` connector. It also prints a warning with the SRE Agent known-limitations URL because private endpoint ADX blocks direct KQL queries from the hosted agent. The customer can decide whether to enable public query access for the connector after reviewing . @@ -185,14 +183,13 @@ The included GitHub Actions example passes the cluster URI as a deploy flag whil ## Migrating from env-var-driven deploys -The old deploy flow used configuration inputs such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, `SRE_AGENT_NO_TELEMETRY`, and `connectors.secrets.env`. Those inputs are no longer supported for identity or config. +The old deploy flow used configuration inputs such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, and `connectors.secrets.env`. Those inputs are no longer supported for identity or config. Before: ```bash export FINOPS_HUB_CLUSTER_URI="https://..kusto.windows.net/hub" export FINOPS_HUB_CLUSTER_RESOURCE_ID="/subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/" -export SRE_AGENT_NO_TELEMETRY=1 bash bin/deploy.sh recipes/finops-hub ``` @@ -206,8 +203,7 @@ bash bin/deploy.sh \ --name \ --location \ --cluster-uri https://..kusto.windows.net/Hub \ - [--cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/] \ - --no-telemetry + [--cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/] ``` The only supported environment-variable inputs are secrets: diff --git a/docs/deploy/sre-agent/14.0/azuredeploy.json b/docs/deploy/sre-agent/14.0/azuredeploy.json index 4b6a6d0eb..4b6d42abf 100644 --- a/docs/deploy/sre-agent/14.0/azuredeploy.json +++ b/docs/deploy/sre-agent/14.0/azuredeploy.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "2403415415579441400" + "templateHash": "9242331632702473420" } }, "parameters": { @@ -67,13 +67,13 @@ }, "accessLevel": { "type": "string", - "defaultValue": "High", + "defaultValue": "Low", "allowedValues": [ "Low", "High" ], "metadata": { - "description": "Agent access level." + "description": "Agent access level. Low (read-only) is recommended for reporting and analysis without modification risk." } }, "actionMode": { @@ -137,9 +137,9 @@ }, "enableSubscriptionReaderRole": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Assign Reader on the deployment subscription to the agent managed identity." + "description": "Assign Reader on the deployment subscription to the agent managed identity. Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups." } }, "recipePackageUri": { @@ -149,6 +149,13 @@ "description": "Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI." } }, + "recipePackageSha256": { + "type": "string", + "defaultValue": "bc87901a7090d36feb7d80664d57fc9bfa09056eed316fbf5458855b9de97662", + "metadata": { + "description": "SHA256 hash of the recipe package for integrity verification." + } + }, "forceUpdateTag": { "type": "string", "defaultValue": "[utcNow()]", @@ -165,6 +172,17 @@ "metadata": { "description": "Azure resource tags." } + }, + "deployerPrincipalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "User", + "ServicePrincipal" + ], + "metadata": { + "description": "Principal type of the deployer." + } } }, "variables": { @@ -252,6 +270,9 @@ "experimentalSettings": { "value": "[parameters('experimentalSettings')]" }, + "deployerPrincipalType": { + "value": "[parameters('deployerPrincipalType')]" + }, "tags": { "value": "[parameters('tags')]" } @@ -263,7 +284,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "11748842726639098374" + "templateHash": "400180081712866601" } }, "parameters": { @@ -333,6 +354,17 @@ "description": "Agent experimental settings." } }, + "deployerPrincipalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "User", + "ServicePrincipal" + ], + "metadata": { + "description": "Principal type of the deployer." + } + }, "tags": { "type": "object", "defaultValue": {}, @@ -500,6 +532,9 @@ "experimentalSettings": { "value": "[parameters('experimentalSettings')]" }, + "deployerPrincipalType": { + "value": "[parameters('deployerPrincipalType')]" + }, "tags": { "value": "[parameters('tags')]" } @@ -511,7 +546,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "6562535881153200016" + "templateHash": "2881433815087416423" } }, "parameters": { @@ -599,6 +634,17 @@ "metadata": { "description": "Azure resource tags." } + }, + "deployerPrincipalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "User", + "ServicePrincipal" + ], + "metadata": { + "description": "Principal type of the deployer." + } } }, "variables": { @@ -648,7 +694,7 @@ "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", "principalId": "[deployer().objectId]", - "principalType": "User" + "principalType": "[parameters('deployerPrincipalType')]" }, "dependsOn": [ "[resourceId('Microsoft.App/agents', parameters('agentName'))]" @@ -906,6 +952,9 @@ "recipePackageUri": { "value": "[parameters('recipePackageUri')]" }, + "recipePackageSha256": { + "value": "[parameters('recipePackageSha256')]" + }, "kustoConnectorUri": { "value": "[parameters('finopsHubKustoConnectorUri')]" }, @@ -923,7 +972,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "5168893811325309322" + "templateHash": "5025769957758856658" } }, "parameters": { @@ -957,6 +1006,12 @@ "description": "Public URI for the generated SRE Agent recipe package." } }, + "recipePackageSha256": { + "type": "string", + "metadata": { + "description": "SHA256 hash of the recipe package for integrity verification." + } + }, "kustoConnectorUri": { "type": "string", "defaultValue": "", @@ -979,7 +1034,7 @@ } }, "variables": { - "$fxv#0": "# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n\n$ErrorActionPreference = 'Stop'\n\nfunction Get-RequiredEnv($Name) {\n $value = [Environment]::GetEnvironmentVariable($Name)\n if ([string]::IsNullOrWhiteSpace($value)) {\n throw \"Missing required environment variable: $Name\"\n }\n return $value\n}\n\nfunction Get-OptionalEnv($Name) {\n return [Environment]::GetEnvironmentVariable($Name)\n}\n\nfunction ConvertTo-BodyJson($Value) {\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\n}\n\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\n foreach ($name in $Names) {\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\n return $Object.$name\n }\n }\n return $Default\n}\n\nfunction Get-HttpStatusCode($Exception) {\n if ($Exception.Response -and $Exception.Response.StatusCode) {\n return [int]$Exception.Response.StatusCode\n }\n return $null\n}\n\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\n try {\n return & $Action\n }\n catch {\n $statusCode = Get-HttpStatusCode $_.Exception\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\n throw\n }\n if ($attempt -eq $MaxAttempts) {\n throw\n }\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\n Start-Sleep -Seconds $DelaySeconds\n }\n }\n}\n\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\n $headers = @{\n Authorization = \"Bearer $Token\"\n 'Content-Type' = 'application/json'\n }\n $parameters = @{\n Method = $Method\n Uri = $Uri\n Headers = $headers\n }\n if ($null -ne $Body) {\n $parameters.Body = ConvertTo-BodyJson $Body\n }\n return Invoke-RestMethod @parameters\n}\n\nfunction Get-KnowledgeSourceName([string]$FileName) {\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\n $name = $name -replace '-+', '-'\n return $name.Trim('-')\n}\n\nfunction Get-Collection($Value) {\n if ($null -eq $Value) {\n return @()\n }\n return @($Value)\n}\n\nfunction Convert-TokenToString($Token) {\n if ($Token -is [Security.SecureString]) {\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\n try {\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\n }\n finally {\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\n }\n }\n return [string]$Token\n}\n\nfunction Get-ArmAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\n}\n\nfunction Get-SreAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\n}\n\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\n$agentName = Get-RequiredEnv 'agentName'\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\n$armApiVersion = '2025-05-01-preview'\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\n\nWrite-Output 'Connecting with deployment script managed identity...'\nConnect-AzAccount -Identity | Out-Null\nSet-AzContext -Subscription $subscriptionId | Out-Null\n\n$workRoot = Join-Path $env:TEMP 'sre-agent-recipe'\n$zipPath = Join-Path $env:TEMP 'sre-agent-recipe.zip'\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\n\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\nInvoke-WithRetry -Label 'download recipe package' -Action {\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\n} | Out-Null\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\n\n$extrasPath = Join-Path $workRoot 'extras.json'\nif (-not (Test-Path $extrasPath)) {\n throw \"Recipe package did not contain extras.json\"\n}\n\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\nWrite-Output \"Loaded recipe package from $extrasPath\"\n\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\n $extras.connectors = @(\n Get-Collection $extras.connectors | Where-Object {\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\n $type -ine 'Kusto'\n }\n )\n}\nelse {\n foreach ($connector in Get-Collection $extras.connectors) {\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\n if ($type -ieq 'Kusto') {\n $connector.properties.dataSource = $kustoConnectorUri\n if (-not $connector.properties.PSObject.Properties['identity']) {\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n }\n }\n}\n\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\n } | Out-Null\n Write-Output \" ARM PUT connectors/${Name}: ok\"\n}\n\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\n $uri = \"$agentEndpoint$Path\"\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\n }\n}\n\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\n $encodedName = [Uri]::EscapeDataString($Name)\n $body = @{\n name = $Name\n type = $Type\n tags = @()\n properties = $Properties\n }\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\n Write-Output \" PUT $Kind/${Name}: ok\"\n}\n\nWrite-Output 'Step 1/7: Applying connectors...'\nforeach ($connector in Get-Collection $extras.connectors) {\n $name = [string]$connector.name\n $properties = $connector.properties\n if (-not $properties.PSObject.Properties['identity']) {\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\n}\n\nWrite-Output 'Step 2/7: Configuring built-in tools...'\n$overrides = Get-Collection $extras.builtInTools.overrides\nif ($overrides.Count -gt 0) {\n $body = @{\n overrides = @($overrides | ForEach-Object {\n @{\n name = $_.name\n enabled = [bool]$_.enabled\n }\n })\n }\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\n}\n\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\nforeach ($item in Get-Collection $extras.knowledgeItems) {\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\n $body = @{\n properties = @{\n dataConnectorType = 'KnowledgeFile'\n dataSource = $sourceName\n extendedProperties = @{\n displayName = [string]$item.name\n fileName = [string]$item.name\n fileContent = [Convert]::ToBase64String($bytes)\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\n }\n }\n }\n Invoke-ArmPutConnector -Name $sourceName -Body $body\n Start-Sleep -Seconds 5\n}\n\nWrite-Output 'Step 4/7: Applying tools...'\nforeach ($tool in Get-Collection $extras.tools) {\n $name = [string]$tool.metadata.name\n $properties = $tool.spec\n if ($properties.type -eq 'PythonTool') {\n $properties.type = 'PythonFunctionTool'\n }\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\n}\n\nWrite-Output 'Step 5/7: Applying skills...'\nforeach ($skill in Get-Collection $extras.skills) {\n $name = [string]$skill.metadata.name\n $tools = @()\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\n $tools = Get-Collection $skill.metadata.spec.tools\n }\n $properties = @{\n name = $name\n description = [string](Get-PropertyValue $skill.metadata @('description'))\n tools = $tools\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\n additionalFiles = @()\n }\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\n}\n\nWrite-Output 'Step 6/7: Applying subagents...'\nforeach ($subagent in Get-Collection $extras.subagents) {\n $name = [string]$subagent.metadata.name\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\n}\n\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\n$scheduledTasks = Get-Collection $extras.scheduledTasks\nif ($scheduledTasks.Count -gt 0) {\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\n if ($match.id) {\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\n Write-Output \" deleted existing scheduledtasks/$name\"\n }\n }\n }\n\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n $spec = $task.spec\n $properties = @{\n name = [string](Get-PropertyValue $spec @('name') $name)\n description = [string](Get-PropertyValue $spec @('description'))\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\n agent = [string](Get-PropertyValue $spec @('agent'))\n }\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\n }\n}\n\nWrite-Output 'SRE Agent extras complete.'\n", + "$fxv#0": "# Copyright (c) Microsoft Corporation.\r\n# Licensed under the MIT License.\r\n\r\n$ErrorActionPreference = 'Stop'\r\n\r\nfunction Get-RequiredEnv($Name) {\r\n $value = [Environment]::GetEnvironmentVariable($Name)\r\n if ([string]::IsNullOrWhiteSpace($value)) {\r\n throw \"Missing required environment variable: $Name\"\r\n }\r\n return $value\r\n}\r\n\r\nfunction Get-OptionalEnv($Name) {\r\n return [Environment]::GetEnvironmentVariable($Name)\r\n}\r\n\r\nfunction Get-TempRoot() {\r\n $tempRoot = [System.IO.Path]::GetTempPath()\r\n if ([string]::IsNullOrWhiteSpace($tempRoot)) {\r\n $tempRoot = Get-OptionalEnv 'AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY'\r\n }\r\n if ([string]::IsNullOrWhiteSpace($tempRoot)) {\r\n $tempRoot = (Get-Location).Path\r\n }\r\n return $tempRoot.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)\r\n}\r\n\r\nfunction ConvertTo-BodyJson($Value) {\r\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\r\n}\r\n\r\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\r\n foreach ($name in $Names) {\r\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\r\n return $Object.$name\r\n }\r\n }\r\n return $Default\r\n}\r\n\r\nfunction Get-HttpStatusCode($Exception) {\r\n if ($Exception.Response -and $Exception.Response.StatusCode) {\r\n return [int]$Exception.Response.StatusCode\r\n }\r\n return $null\r\n}\r\n\r\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\r\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\r\n try {\r\n return & $Action\r\n }\r\n catch {\r\n $statusCode = Get-HttpStatusCode $_.Exception\r\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\r\n throw\r\n }\r\n if ($attempt -eq $MaxAttempts) {\r\n throw\r\n }\r\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\r\n Start-Sleep -Seconds $DelaySeconds\r\n }\r\n }\r\n}\r\n\r\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\r\n $headers = @{\r\n Authorization = \"Bearer $Token\"\r\n 'Content-Type' = 'application/json'\r\n }\r\n $parameters = @{\r\n Method = $Method\r\n Uri = $Uri\r\n Headers = $headers\r\n }\r\n if ($null -ne $Body) {\r\n $parameters.Body = ConvertTo-BodyJson $Body\r\n }\r\n return Invoke-RestMethod @parameters\r\n}\r\n\r\nfunction Get-KnowledgeSourceName([string]$FileName) {\r\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\r\n $name = $name -replace '-+', '-'\r\n return $name.Trim('-')\r\n}\r\n\r\nfunction Get-Collection($Value) {\r\n if ($null -eq $Value) {\r\n return @()\r\n }\r\n return @($Value)\r\n}\r\n\r\nfunction Convert-TokenToString($Token) {\r\n if ($Token -is [Security.SecureString]) {\r\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\r\n try {\r\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\r\n }\r\n finally {\r\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\r\n }\r\n }\r\n return [string]$Token\r\n}\r\n\r\nfunction Get-ArmAccessTokenString() {\r\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\r\n}\r\n\r\nfunction Get-SreAccessTokenString() {\r\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\r\n}\r\n\r\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\r\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\r\n$agentName = Get-RequiredEnv 'agentName'\r\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\r\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\r\n$recipePackageSha256 = Get-RequiredEnv 'recipePackageSha256'\r\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\r\n$armApiVersion = '2025-05-01-preview'\r\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\r\n\r\nWrite-Output 'Connecting with deployment script managed identity...'\r\nConnect-AzAccount -Identity | Out-Null\r\nSet-AzContext -Subscription $subscriptionId | Out-Null\r\n\r\n$tempRoot = Get-TempRoot\r\n$workRoot = Join-Path $tempRoot 'sre-agent-recipe'\r\n$zipPath = Join-Path $tempRoot 'sre-agent-recipe.zip'\r\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\r\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\r\n\r\nWrite-Output \"Validating SRE Agent recipe package URI: $recipePackageUri\"\r\n[uri]$parsedUri = $recipePackageUri\r\nif ($parsedUri.Scheme -ne 'https') {\r\n throw \"Recipe package URI must use https scheme, got: $($parsedUri.Scheme)\"\r\n}\r\n\r\n$allowedHosts = @(\r\n 'raw.githubusercontent.com',\r\n 'github.com',\r\n 'aka.ms'\r\n)\r\n\r\nif ($allowedHosts -notcontains $parsedUri.Host -and $parsedUri.Host -notlike '*.blob.core.windows.net') {\r\n throw \"Recipe package host '$($parsedUri.Host)' is not in the allowlist. Allowed: raw.githubusercontent.com, github.com, aka.ms, *.blob.core.windows.net\"\r\n}\r\n\r\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\r\nInvoke-WithRetry -Label 'download recipe package' -Action {\r\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\r\n} | Out-Null\r\n\r\nWrite-Output \"Verifying recipe package integrity...\"\r\n$actualHash = (Get-FileHash -Algorithm SHA256 -Path $zipPath).Hash\r\nif ($actualHash -ne $recipePackageSha256) {\r\n throw \"Recipe package hash mismatch: expected $recipePackageSha256 got $actualHash\"\r\n}\r\n\r\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\r\n\r\n$extrasPath = Join-Path $workRoot 'extras.json'\r\nif (-not (Test-Path $extrasPath)) {\r\n throw \"Recipe package did not contain extras.json\"\r\n}\r\n\r\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\r\nWrite-Output \"Loaded recipe package from $extrasPath\"\r\n\r\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\r\n $extras.connectors = @(\r\n Get-Collection $extras.connectors | Where-Object {\r\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\r\n $type -ine 'Kusto'\r\n }\r\n )\r\n}\r\nelse {\r\n foreach ($connector in Get-Collection $extras.connectors) {\r\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\r\n if ($type -ieq 'Kusto') {\r\n $connector.properties.dataSource = $kustoConnectorUri\r\n if (-not $connector.properties.PSObject.Properties['identity']) {\r\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\r\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\r\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\r\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\r\n } | Out-Null\r\n Write-Output \" ARM PUT connectors/${Name}: ok\"\r\n}\r\n\r\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\r\n $uri = \"$agentEndpoint$Path\"\r\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\r\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\r\n }\r\n}\r\n\r\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\r\n $encodedName = [Uri]::EscapeDataString($Name)\r\n $body = @{\r\n name = $Name\r\n type = $Type\r\n tags = @()\r\n properties = $Properties\r\n }\r\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\r\n Write-Output \" PUT $Kind/${Name}: ok\"\r\n}\r\n\r\nWrite-Output 'Step 1/7: Applying connectors...'\r\nforeach ($connector in Get-Collection $extras.connectors) {\r\n $name = [string]$connector.name\r\n $properties = $connector.properties\r\n if (-not $properties.PSObject.Properties['identity']) {\r\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\r\n }\r\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\r\n}\r\n\r\nWrite-Output 'Step 2/7: Configuring built-in tools...'\r\n$overrides = Get-Collection $extras.builtInTools.overrides\r\nif ($overrides.Count -gt 0) {\r\n $body = @{\r\n overrides = @($overrides | ForEach-Object {\r\n @{\r\n name = $_.name\r\n enabled = [bool]$_.enabled\r\n }\r\n })\r\n }\r\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\r\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\r\n}\r\n\r\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\r\nforeach ($item in Get-Collection $extras.knowledgeItems) {\r\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\r\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\r\n $body = @{\r\n properties = @{\r\n dataConnectorType = 'KnowledgeFile'\r\n dataSource = $sourceName\r\n extendedProperties = @{\r\n displayName = [string]$item.name\r\n fileName = [string]$item.name\r\n fileContent = [Convert]::ToBase64String($bytes)\r\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\r\n }\r\n }\r\n }\r\n Invoke-ArmPutConnector -Name $sourceName -Body $body\r\n Start-Sleep -Seconds 5\r\n}\r\n\r\nWrite-Output 'Step 4/7: Applying tools...'\r\nforeach ($tool in Get-Collection $extras.tools) {\r\n $name = [string]$tool.metadata.name\r\n $properties = $tool.spec\r\n if ($properties.type -eq 'PythonTool') {\r\n $properties.type = 'PythonFunctionTool'\r\n }\r\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\r\n}\r\n\r\nWrite-Output 'Step 5/7: Applying skills...'\r\nforeach ($skill in Get-Collection $extras.skills) {\r\n $name = [string]$skill.metadata.name\r\n $tools = @()\r\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\r\n $tools = Get-Collection $skill.metadata.spec.tools\r\n }\r\n $properties = @{\r\n name = $name\r\n description = [string](Get-PropertyValue $skill.metadata @('description'))\r\n tools = $tools\r\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\r\n additionalFiles = @()\r\n }\r\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\r\n}\r\n\r\nWrite-Output 'Step 6/7: Applying subagents...'\r\nforeach ($subagent in Get-Collection $extras.subagents) {\r\n $name = [string]$subagent.metadata.name\r\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\r\n}\r\n\r\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\r\n$scheduledTasks = Get-Collection $extras.scheduledTasks\r\nif ($scheduledTasks.Count -gt 0) {\r\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\r\n foreach ($task in $scheduledTasks) {\r\n $name = [string]$task.metadata.name\r\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\r\n if ($match.id) {\r\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\r\n Write-Output \" deleted existing scheduledtasks/$name\"\r\n }\r\n }\r\n }\r\n\r\n foreach ($task in $scheduledTasks) {\r\n $name = [string]$task.metadata.name\r\n $spec = $task.spec\r\n $properties = @{\r\n name = [string](Get-PropertyValue $spec @('name') $name)\r\n description = [string](Get-PropertyValue $spec @('description'))\r\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\r\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\r\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\r\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\r\n agent = [string](Get-PropertyValue $spec @('agent'))\r\n }\r\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\r\n }\r\n}\r\n\r\nWrite-Output 'SRE Agent extras complete.'\r\n", "identityName": "[format('id-sre-apply-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", "scriptName": "[format('apply-sre-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" @@ -1047,6 +1102,10 @@ "name": "recipePackageUri", "value": "[parameters('recipePackageUri')]" }, + { + "name": "recipePackageSha256", + "value": "[parameters('recipePackageSha256')]" + }, { "name": "kustoConnectorUri", "value": "[parameters('kustoConnectorUri')]" diff --git a/docs/deploy/sre-agent/14.0/createUiDefinition.json b/docs/deploy/sre-agent/14.0/createUiDefinition.json index 87e82bcaa..25d538b3e 100644 --- a/docs/deploy/sre-agent/14.0/createUiDefinition.json +++ b/docs/deploy/sre-agent/14.0/createUiDefinition.json @@ -101,8 +101,8 @@ "name": "accessLevel", "type": "Microsoft.Common.OptionsGroup", "label": "Access level", - "defaultValue": "High", - "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "defaultValue": "Low", + "toolTip": "Low grants read-only monitoring roles (recommended for reporting and analysis). High adds Contributor on target resource groups for autonomous remediation workflows.", "constraints": { "allowedValues": [ { @@ -147,8 +147,8 @@ "name": "enableSubscriptionReaderRole", "type": "Microsoft.Common.CheckBox", "label": "Grant subscription Reader to the agent", - "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", - "defaultValue": true, + "toolTip": "Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.", + "defaultValue": false, "visible": true } ] diff --git a/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip b/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip index 159ae7454137f5096b46f48672aeefb4b3f4c11f..3205d3261917753562b85223c53a3494861f445c 100644 GIT binary patch delta 342628 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Π>fU7$HM0wsZl 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%0AmKKSN=NQ3{-cCBH@+WC+Qm ze^y9;*94vvrDNoZv>%$lJTV)6M#E7Qsh0o8SBAt@_RZtR>a#lBe7f#(X3N@+YOi@N z*?h}pL8-e{uAZ*1ugtCK$SVzMuukCdj7dmrsL53=qE$aDpo+*;U4V)HWDEwa*}Ea{ zU*j#(=#Hh!qx~iPlN|qIVoEc2QSC`&YJFyZ<)${PR6du*I4qR!bQNuXk~MixpDub5 z>Eb=SMuk#iGc8UV!=wOmcIerT>UZ9j^sB8=c-hp&x`mx}8mFmouhuHNC8vZeh^(&} z<)X^PR|{JWkESQU`FJ)YIs_!}G&q^&Aa1Oymxb1AD9DLSgN^ld`Cg20CNVp8X_6Ix z@C?YHkgX}sGuC#vaiUKqB#V91TG-&c#a!%8W6@f8+&1!y5I7{|(fD*f?~7o=mNc@gXQ z_0x!rb9I?yz5Mc-*~jt|ldypU@->1htwop@XPLCqM-GE?482L zU3f7trV52Cfl1n|QWko2cwi_3x4qXQKqsJ_=@-#1`* za{-4GE1yYnYlI~1v<5q6uC7*p;|xm)Og_>$pLrB1+z1Y=IZEc@TlBR{w)5c|Pp9)V zD?t{OYT1&k!%+hzZ;f?5CoiCI<1ZJ&aU`)j9CaE~gwkxvph1=n?! z+#YkJT~4u<%&s9_kOR zBx*Jnd8uzOkLBZ*HViy+2Ypz=wa5*Z=n{OLJ&BY-M)I#s!LA`kUG?}|={)JX6BHD- z`T~Bqa_!&B(aB!#cQY#ISU5w^ZkXXB0KZ&3O_f;RCt)T6CqBTXcpmy$kDQ% z)3A(Dj52s3Cy&9BQi)H0qezI-^gH$>hXz6|Qsd9uEvz2Un>#LgV7QyYJ`5qNQ>s2H z%!{D06J9H;#j$b2^%G*s65|84Y=!T_t>+M1>D5(z#(oh;qX@T1s>L0hWF{7J3my7u zRUHb$R--Vosh!LdgKFG?0_(t8Hk#Hb>Ppq(5V9&U)5O3NmO!w7F%rKAm0$Ev+PnpI z8JpeH3z|Crb#w!me)Juie_|%W14qv>OmkzMsMHYC^3?%Djq^M%lWxaCzB{N}JV-{M zGs=2u&%l$&Y?N3B?^-f7>4i;$^S;=JG)sXF#?up+yLCgGtm^Nco0)k^f4KR9zV+R6 zH%%Mr-E%un9CWmQDvYgR#uMcMsYPkL$F?=k9Z0XE+$$BX3bN1$Q1iswS<5tCWDGy? zcigf}l)BhlyLhs8@fA-Ic8~WXJAe0Q^ix%>X&3tyo`);0e!A3$C^O0OR~~*?>Wvt#sM}0zyi84JbV9EHg)KsV;~%b*G=|!nD^SM+jEzeN zDlgiWN=BwFBlslH=b^jq+YXte*1V1{P$!-SJXyOTM~;-$B_a?n%i@|^^(>bWlp7Da zQmfisem3)J)aGG3b=&8G z@Cf5}T7y_Q*JGb;!7CDg>8L7z*4_P*oKiSf=ABt;?qI~zWh)_FA3y$sPKW9@rfxL> z5skZ)d2~XTDV>NtBG!Q0l#q>lGl|%!6<#RSGVk{l5z)@&+UEGagIR&tCR!z&Z<|2| zWW&dQs$*R@#^b2Tue#WM0U=TIF(&pg0dWXwL6Q0Qkup7QJkB@WV-Hc&mGQI@hzwNOKQa zZj*I@$oE0K4zw%S-&+1*;AmI~Ql6#$1mrO9To3ft0K%^Q_UYO;PYnpypq%9}k*ZyP z+UoJ}O?e<1uv+&3#92Icl?Sz#RT@-C7Od*>BD_UBanx1xX8`Im7$4GiYV}fyABzJz z7NSSBX0u*1RYai4;sv8J&BZvx3f_IuO4|Fo^%xdD-$$T;GT|sYEX~iT5Tz5brA-o=*1WD`OIvU8i8O#FPmjZWBlJ%}RXo}W zJFoWEoO^%m?e4)l8--(xlQ{QjifqoHSW$>Z$PG`4<^hkM6`S;wCrA2uj=~`!aLj7L zivl_N1%7V;Z=9u>3BbmnJc0*7n+@Ff)B`v2zWD2e_GU_cU+XuN(BU04?SCJA$g%|*Luk!pCY+pA_RZ@=AN5pn~;il(}vJG6vj+5}BbMK-q2 zcdSZH)%0q7PlOO1(*5VkZ=dUbamcd+`(}_-rdmRpoJxU<6Wxz55+qYm*%K!Sm<~!( z1EpALLWNq4RI{0rrYsI53YMQ}%z^_!wSPg7$SslHNJ3k(yAzZiMARCc0LfYkQEeEp zNUFLh1e9`g{WNje053IiIk_4wgsG@N!SNy|&Vp)^)2zhJigX;V9>H&agi0uW5%TS~ z`z{P{RYi3ZehA=aOp{vGeH4=WpLe^^(cAder~~$XIF-4wJ_0Gnjm^lZ)6D~Zv+3&a z_BLb_gc~$CET4^4wq~JRwP&0lS%;fl8XdX1ucY=hhh^W zAwakfZYlsosSXcEB3K50S1%N4nci?s=B+PFDf0$x$xiSd^`5amaCz`j2{csqoXgK^ zfghA$Vq<0r$Pm`>VU@sCPD~t@`%RP0i+BsXJVH8zOc>OXis;USi3bQ*^$7=nkZ7TM zH(H#Bfhb&|Ldp;@!K_1wk)?=(+oLUHN^Vmt;$~``R3?*Q)oP)Cy@auC+%H(v zJ4R_8+_3nsKjj>Mk4|{1-}!gAsj$P869cm2l;MdSctq2=7-;Cv@bpZK_kC zz~5};Jv|hX7#<=j(aePD2zeBo}_#`2=4-dytyEqGP^F(0ws z$@NQdBYNMPs4F1>>n#Xxq0oy2bs3v>9r3t{V%L6$8KOkeMfP5>r|*osnr8Aibo_ST zyqfVZb(?;YBtJ{@lQ=X;%iGjnYC3AWifXej$mb3q8a7SU&(G+9&@YLxMI#iQlmogq z>LvLxwYLAc1da(l1Pua~P2r>6!Qt^^86JhwjRz3m{OTj56qdv2JWk$2Jrw#W^~ zrKyCe|0W86gcd`ug^VxZqzD~#|ZS)=A z(N?eJ$Y(%q{(}4ioRodFYwaf8WniVl0I-)Omb@dIjV(%u>mt?S5yz-s@fNK6HHBsI z@`aq2we9Yld)SUWp5&xzudL3Eu8HD*WxN(4osv^h83bWn%Qm;i^GhB*co(j*sd;Wn zV|iD^(E}4}n0qozpMvRl7=F59hijP>NjfzB!?i8wyNA`X^DP5c3_76DJ$y>#gHEz!Bf~JQ5a4(3=3y88UFLlS!RZTpP9Tl@rgQc%pHjuA>rlb}N zol`@+d@z2Hyefr01p=5CXMjjO(aSLT@CoXZ+o_iX9T^!hbxR5JX0-t(?e=a?+LwY& zv1G?Gdcy{F`?HKBNQyGnCL}*q$I-?*;qHZTQ|4!5T_)rbPPa2K!FfpANgKA~1p^HZ zvA#HX=~L6X!LkrB7y;9;VNEE1f}wA0WSZG5T^I)PCDA|tp?`D<#~`P&G-c#6%TH;I zCDK%);vSPs-cX%i3AO>BEb>|*jh#HnHQ8tgbm+olIL4(q^bK!H&tay%YjkezT@l0X zEURXqlhvJ>fM~S81<~*57u!&1i{Vg}pc^)GnBYch&0)hltCDP#kIHm^%s{`=#i0aE zCL`xf;U$;2FjYAM+NV^FpjMC~UpiW4Lefj~j-t&@rA(FBwCz(G`nnb~VK5jmSe_fv z@EAxYbX6WRoFKw9ic;yUK5LndffI$NxzIggd^9&14bv1Yh#CLjm9ZL((kg)j^kIAw zissI9E_IDo(O&C@3Bmz?-~_jG{Y(66u1T{P_5wE%J8ukDB+3yWti}njySQC^y^FX} zlXmu4-UrgKK`QcW`Y=GrwTgUpQG6iG>2NL7;9s1$_a?7%6o{sz}o% zR$aa81+y@JUs{*Vy9>bd2N(MZzzO#3TL-9@v&D3m?mi;7K{{@K25U@=)AwfhH~u0q zbTy@VDi za*Jf&19}pJ#MQm%VgT4uqHhQ|M5-)t4I@w5@XXkhYoKi%#EZ2iUKE?g#PV?}@8ImR z@gga}9UBQJhR6b#>!b@2o}8k8Ie^4AA_j_0so|#!^4!n7X7G{Gd0WQ@4lc+eKq&D72|fLmKe=fWdv+F4S|FJ!NG)UN%P zuDYvSp(sUv#jp^zH=*;86L9|$x1(3q)bqV@fgIr#6JLl) zhd4MN%|t3XM8Z=^2~UH(H%c)*_!?~?KRb#)$zN8~oR5tA^7wULZJUXCnHPQl|JdAr zGRJS-_>WaLPe+5SW2aBzR~EL#<{rXMlQwHzDFAjIC zr2ZmG3ER+uMzB;p00#0Qr%C`7gDGKux;4T1gCDVP$@`1EH{yB=mV8r+AsKlRVT84w zE$?n~r)!djLIbB7H8T7zcT6n75o}@r;!QLipn{LOtSEzrCX^AfQMX7ak{Wc8H`Fec zN)2=gzeVY#&fo`h9DS{v5L;&Y^3xW%-7!t*j0p`$RWG%oJ)ydJPnVL-czAq&a6aUWT(MK*g&nye1w&=nN!WUfWrFKzxYOM3D zFb^y%DIfO9)}mC|)nU1R;VsWuQuRkCv?_Lu*5XgycsPi&wF2Oq)P)s0=jC!Jb$7=aqG16-<Ig2Rv|ANWu8{R8dN!dAwF-pyUgX!+;Cq) zN3@(26v~Ehsu~Jmd5j%D)J4UK308z1eE+^Qg_;?WfSenTIjSkXDA4WjypkRZ`77>) z%XnN)*)69;DL5$svSVeZ^GXP$h2ZRcu>S}=+q101*Cv*p7-F=nVn4UvjE-`MV2&*9 z11mjJwo?6J-32~>k6UlCPFoX1U{lwPI=Gs6@45zjYmssU8g%Deh?!EjnI=w5_fB|n z__~MKrS8zOzofFqTnXMr4Hh&(SGdk;G6KQCZW>>9G<+x?V~FRk<{fpK#%EyUueyDH z(9>!tnNoH#DiR@zMtZnVX43UuOEaJeLcl{9dPJCcyPj2lzXBBVSx!aY;;h2b9=zHP zk#K+!vI`3gPLNG*JEDXv=T1{pgSy@%#<+lMzZMUTA`G^6UiQL|l)PFA3Eh^uVEDV7ajVsS#Jr zGqArU0;a*7l@q~+Xfg-zY^v=yd)J<|h&ObpE15s5CV|Ja&|LpS5Ig>MN|SS)CjC4I zSWF7j4osSM#d8v|Ycn=cLWID%#-3~^ob9%j!5R~6=?lBAETri6VSyt# zjpZ|cI?#tLQ|1*gzlr3qacr+WTclydn0zz@PolPXux!cqI31U;gIV`wnw!Ia+1r2f z!`pY;uiyO{e-kqa`0h&}Fvbp-<&`Xu2E1Gz+qQUeyjaWL!3WURN$iZcPjEGWd6;+} zspMHbBgk|7P%?9I7H2|-L&=V6tU>LDz369uhgcbJ-5dU3KdS>)-9M{0qk>8Sa`mnq zXlN+?6UqPVKfHfMQX8n<1fdc^`#?iQfbPV|POnW3sgzB9^Rs#d-Hjy@^XYRe(>^E; zyp8qs-_$%>(xn4no@}4qQn3Qtse>dtOLe_huA;$bbuft2RELs2FWQ`N!4zzJI}J8} z%06Q-?2BKqP6aU5us<%Xer3QK>a*H0J~AvaVaYJC=-M=C)`RIT{vMShtP z{(_?FBT09exE7yuLC&z_<6~!%0OMlYA>ENWag^<47x}r4e$poRit(vJ(%}uycr(gddo&i|1h3=y~`GrgA2jX6MNYj&Lvo z{B0fPLUefMh#R|?HIO3CdifxK!SeYsp}mc_J_(++YpP--p)uloEm@&-8EZD*NENXhnZMp$Rp?7&kgkFNRcMAVL}yX8TG zZES!mZ#AAWT(c{VcPAaUPapZp$X$hrdZTqw9>aFB{xAwAjH-TKP{uv>hKLX2_-ox{ zQ)Et9!zp%0C%FCxaaAOLAB`Dh?f2>8$t3wO*Ft#u*~X%@ba#V`-gO-LQRTf}Db!Z( zLZePw(uor&mvG0}FkX0*5Kkvqh^-5WSevC}CSDJD&pu+odk=uRwGf=vLK_P%;3*L- zo(__BJ^-l3^<`LA!{k?kH9^693wgI*O-3zv%#@N=>GS;4^n0U!n_A3xFg@04u3bq#Zg# zgnK#EdV9=GavPkXl;#mo@$m`YCHDTL><4*VH_hH+a+FrG91?H&C39yMoH*?HF1;HQ zVF?D`8we_Y8&@8Rsyz=@BA|7UHCu0#>th7#YRGeR!%>r0oy16FYvFm=ge_*sFx?`4 zwpK(~gN$`JOvg%p?4~1_P8^C3>7D`7Ah@*Zqn!p}@ms81ib5VnG574pvRUmhXQjL?VlnqooHuR}+UZ{8;=_J$6L!30HG5SG z7K*WdY6N*8S3?bePooR7UL<8l7{Z9a{SHUZTrebSrHs8RH_FMXO|YsIm>`|h=3JrX zPYLlY3cBmKHYm2;a&b+H>{0IISmGE|jo zKNEzz1v+!+vz|?$=UyO*P&jfrPOiMX#3JE%AgC*=&^hELwen0%U?S@=MVQJe9t_=i z5W=vUoOAU89MOhKDtqgD^;)=qpOiyk(gy9@nTIY5F?1-*KTV*xxER#)2U*qVp(+D^ z4X|F<$mFZlfkw8tHIXY5+lgG-GKV%Bg#i+wQP)l5WMI4z#OYY`L$fct{I9NeA$M!}>gQ z=W<=NYgyddUZyUAyCn-ZPy#|u0tdD6iMMEQ?)IQp8>z~+gt=CX)qEhJKA(hyhrWQ6 zTbjI`S9_xN&=fDQ2sK@VBd{eSo;!&DQX^?*lOk04RG+DJiBN+arzZOZg;>zdP76Sv zO;Pg7bfJHna$|e7azv^eq71fw37J(mnC}P|T71 zlD-GbBqMP08+mYKe{zws zm=BX~NE7qqDC@`N&)t5K_6nVCQDEMqj%jV%R`Uv+{I^Vz-Uz$g`K2U(nPhyRY@t8y z;BAzw?x-q1a3t^||uC~D*r zjueJv2o3#bM+A%NkIxbf7)F5E7X z&uCXD=_3wZFYd5j)$oLWQ@bONk*7&JE+n+!j;}j^Z{7KuK=U-c#iNYSp%S=fYIXfl zYI&qdc3wgQ>={RKqq3H;NV+QoQDqy_Hw#II4Wpah5w=)D4)5Q-Dz_d#RvS+?8O{0r z?JGi0p6HZ;oJ2rN7{w@xRPg`!@ZZeoqBGQ7AgrP{Gy zs?Qi;xn>Dr@}4d-Cwu39uN0+jDko`@jXrvPkq4NZnIx!m#oKFbuBdWi=Lq`XGb7<; zFMrs1e?U1DgSh1l=FB!*n+}0GN%NBs0>u?=$5KXijni?XZT@r{9|Bl{E)f{(bYx-3 zN_^+P{QG~j^pIeG#*ujo>sgV!jNWxyU4K4G&$nOwX@R{y8KviO`f1@E4*py{NxFK7 z9=Cja&H3%z@%Uy$Dcy8gIAzgSLZM?C?9@U>Q3v!brt232dIwX&FQ~thz=AjJF+eu1 z%WUi2ywAX=(G)+|nLbS_3po~&`vpz)3AbL?h(31x*a)#*j`(6q}OZKDdQYg5e1LR zXb2==L38T3RMY`|spLyD0{1k(D3UkTx4ic|121oX|6$u2wXwfW`8gwWV5lx~9-C>4 zn4l{YKj)TFvk}g)Q^44u#`z|M*#Z{fUm7!292)4fxTr0hs@X+n^xv?b4PqPz7?EED zzzG2^bC}c?)(3ce-RIdZ37z))q#uzLWoF^k!|TXJJs^Wx_XIw zkzfvgy$+!a_;=8nj~ zgT>gB##vm<%+5$YMN;&d43xKY80Tew62UQ*fokDhrJ|=%+{3jAt|Cj8j4Yq=S{f5M z5INu1n9(f))1(YhZuH2uADJMkW6EvbZ$=M)Se%f*p+<4tNeB-4g{EIkz0Ri&>kD@J zq2=Wa1(%JDuo2)%TY0c$jMrV&TO58;UPS%}7>xx&E|p5Y;}DXq!QH$;rl>CqS99)a z8uN0Hmr?IzEz8TlrUp@3Qx9rP*5p0v5)oO?I>K@waD{cm+-6l!z;nltU-JPDVXYO-ap`Ii*-< znh&{6ayJTr+>717F~6va&!QyjqpS;L0%qr33^qplks6|?1HxIKXFco-?Wm7J9aTvx zR<5ivI_!f;ybR*AlZu{J2ZC&5{w*dLd ze>*Ocko;}U55sRG9Y=AGlWY0?tSC^*x#$abyKa;E^^nR^V0!t7k-W3=yU?LK#SwjXf5!1m zhv=&|b}vl}{w&@(cDpy!Op`FpKNvBX%s)&$AfxL7lR5zx<(_x)|Zk6y1BO z;=OQn_I788Qg$P+ekj}tgM@Oze<%n>EHV@?*x%mSVey2#k~_VYMz;1AbXVG?6IHn7 z-R+gTRZ6|y;ZC>Rvo2M&W0VcAoBKP>e%|gZvXY;sk=P#8Nt2h`SzlkDZ)Y#6b5o9= z^xT()R_zG#FZp|B@lUez+CT)J%eq2NSnIh@?JXOQ0kB1Xq{`~rfTl-Te^2}uQw#tk zc)+|KW#o7!_X{_}^YZ8^t?}Ae$0$w<{P74R!gsUE*BIYJ;lC^+XpB)8(|@8P^KdVs zoC7?p32;>AR5;h05KdV<(RL<;SAn1T5+f%I6@kK0fMt3}d=QP*<*0tJ#$TY%{DbX%aJY%(vnVSDNUK?|`kU1g8t#Q1QOLW4~)IGH) z(}t2WEO&1VUBB)a${1ORCBeBoY`uKUkO#w@iKMW30PqXxQx_AJM*e4H5_lc-jy3<9 zPqjPZcXLF7Zkv_$m2|qSgej1ePg@$4sQ5pvQvf2iFe-FOH50v@At@m*bwyKBtQTT0@N3s7CjEB_Vi2}+eez^9U&(rDF zAHZwb>^c9mUS^c2X9JR&FF&eQ;xO7w^Rb#OJgPF85RQ~oa!7#!vT*z|cR9DS64lwx zdaQW2HCF;ubZ&Lg`JxS4EMpLbfBP316JYsdSd9z#h1{t5 zsehLcFQIquQqD2AAC!!-&{^ipthcaw%R7I<#*%tC_DgbEm>;OPs1k5UeZJ{N`ls0| ztu$YlC|*j0zCPbQm~z6HZ#vkkSREJ%o<&SoMwBnN0iSIC`U<9z>yCC3(VbvtxH_eO z8MSll-SSDDe~pk2eV&01@U||k`pteHFR1oKxwW(8UiQ#aft~CSql0QQSPG>(+e+ob zA&~V%^2SI3iaAozGk&?PB|FhNy1lLynlK1uQgH~UNnK1uG~B0B^|6K07&Vzna#NWg z?c{Wo+Zc;~e3LSYk?t^v@{_;lE=BhKTHg%F%?0Wif2zQZFWN;8%TU_2+=jKPL5|^b zaTtkPI;WC(W@2$IW7~YX4x&;jNM;k&Oz3V}o(SSJLvIgyo$0F zy%O+c77xpQ?(IYOr7~aMuT9uKvhY(0n6s1V{`bCqjnB?#d|S6UMX34TjLWvXwTph? zEt2sOe~PPFT}!CCr-oFnlr^^&mlpZ52IqX9HKdcB4^pya(9B29vta~PRC|)v5yp(c zJA1iMR7{1@B$6w20XnpkF=ejas<@i7Ix=aN6G}2Kd~43lu#Vo@%2&1efTk=D$I=Op zIgvJf?x5y_kbM=DZ;o=zM#dzyemA1lHY82)NI4Z{Lssm6CbGIk3ENNxcPYSM9BBH6+<|Mvlq2aVb{?}9k=+>`fQW7o( z9!iVUgAe=V-M#zaDOrmsgc`-=xrPV?I$QiIC6H!*1rM%owdn3$Y5+b!iEqc& z5nb~zF%c6lkQS+$?yH~}fBG#Sv&Jawdnm`XtJ9QRzlJ57bba8-`*A`7 z!_sH-7Z4hWqXPbt{>Yoo#84NYWhdaDK0QU!U)CKrslle|D~of!T=x=hGML?qS$lX! zrB2*MWU{Dt@{}qYRvJ{>DBB7b>CT(?9W~H{yclb*k!B_9=;9-~4r zd>5QGuP*X*G%(cL#?jeD-O_%1kvL}KdptQ=WJ-(#Q?$n%|EPu?p9hQvmr2&kFKZKl zJ3*$Qn`hloQQZCB@Vzfmjgys4e|(&}3Z07+n|CsXhuwajBe4wxg2Mt?3X!|d=vMY3 z+;@DVl`(K9>^^x&UZd_fq9a6enUp!(E*xx4%5jwGXB~TXN8M=Msf5pVvxV*gd zY2F<*mPb?j(tNm3exF%8f;W&T0f{aIbU@om{UlZ1|CIE4;nSQC$$FD+$aFP(bFU)q zQ#aeSX2aYcktif+v32{{ipu2Owm)uJtp#6GOaRAcM%WbdA)|Cb*xVnTl!n9^{|+2( zGKxQpPG(KTxe-(CEV}sIe*)$@%KIQL&UHo3eqnHI&xAF}3nBcS4gVeYgxaxBsAZ(f zE-t}ym|yCm?CUf|8>1BcT@?W-?Dq1PjZ&SDJXUbQDHwG3!TD%@Uhv7iLkw{(9wv2I zzL#TE&kJjhoZLp*NLh_j&9K(BZ~^HXuA|e^msu;<%-oUd7IJbxe+N_4?_NOv<`meA z@{Z3Bq?#MocMDP0MHbb(D1K{)x756RZin1760V%4;Q+? zEm0Mq`Rr}mUr9Ci8RhCis&-AnysM;Rk_}=+4Aeq9WQOQmE|g0%W`dcWx1|s z@+jLo_<%a!04t=Zf7gY3r9JDvUglA%d`pdbuIFH~)~GC--LWV(oRo4un7Up_)GRAk z%Z=P}D1>23+;>wQ8-^8lG@b95fA*q%3!r>hkuqylu41q^ z4S*1Fecr_)n!%ocUl)8+(-zooURlOrt7s^9++!??FkE(uNB%e_D8#&e3A!f3MMULuqw594C zWmp|5_L~>Oe|}6+VcM8neKosCDyUgFH}KFBC-R|NrM9zj$CEErQJD_Omk5kbMs-zF z_7CN0<-|(G)dT|+kOIvjaUx++a%Ov^t!O5M4r#z0o+hVKBi$2lk$U|22U`mnWdOPM zq*jN4OsvyuE@0xWitj)D!h*RJ!p3n?nHu-#(76;mMsY{lu8$vc#d`Gb zqFj~yz&yheP=#t&)49-9QfLzEX`Bp<&&-p#EJ^ywkc3lvIq~F_<-MoOxpMM%Q72Yi zVqQ=le?A|T>6khB5afShQX?CEhOnYq8C0TMZXu(Bb}(o07!OLB^kI<$c5b)-8$pPe zTFqGrfPB^+^Ugnf#WjqPj%bmT!JT+dsxJ2uDw@#>MTo6DfjD$^WLDKK(IUJ1UBY%W z%g3*hvQn=M0+&imGljfXZRMwN5{+u2`gvF`f8Er4HswkAJi1!z)>q{-&QXb!pj=Of z_&_k8P%qJOk&d10$1!7`m)F8qCvJosclsDlekP&OD(rl;IkY?YL ze;rPh&Jaj}5;017B}JPM=}l80h1#hJTGGYXH+gq;JV@s^XWE|gtrvxtZ{gZuXpCF@ zqfDuOp-;DzHG=R_Qt3gtg?}k!p8i2*mOpKM%>DR{?-z!$(TypT8$LY6MQVQN_r!mJ z9ZPWk*g0_zG~U%_(obpMbZttDlY8&Ae`m}M8+mLtxVqX}Zp8m#eLAKs(A_R6;FuKD@{Z3CEP5Z8K{xA9sjfDN^)BBG;}$?u&0BJ+|qBF!r&tWK(Vf2$LA z)yoz(VUu5EUcgzj(ggwr;j z`th`SBS#s#RN#Gz0XeL6)??S|QmH`jf5Dj}1_4D@{@%d{r(Zam+4yky0`_fbgk{Bd zgEHApF+;#MlKE%=2jLH#WzXx-!pl~sDq#V8kY$ZUtvWUasS zQ7|bnPm5H;q<}0tIYQqzrwztu5m%dz2bA`2oR0z)t%D<+DP64CmxR;m@6oop;^K(h#92KWA&saH@k7#e;uWWiLMUE*WZk;8O+z4an+~TpZQRYAOO_Cc<_eP)5`c%D}52CBZ=gk zssZxbBtIOn4NSNb-T=2{s2@8VRnJgdh{I)Q>(#4$(!w!^IM5=K&An!NVdU>o_V_WU zA3lD(r4GMKsy~cQ==LjdUamh0E4QLcwqHRvR4iv{e{_PDInn$w+Gaz8^i<7%^)$_i z4IO0@FW1`b5Z<)Sa6hA55WUxg!n)AvRL6vDq75QkD2TPnadPI;QAU`qH-J+g08T9f zl4}L(u&#CPdD2DLUJr)IjzRCF4pbZ#I%WRDdbwVyr{E3Q`E^#+p2Q1#RCddaC%92d zjZDxaf6qEVFT?}XruPPEQyN91BOMO2RE`jmOEq<2g6`r=G31x-t?j&^o}3l_3_euf z>v3QY7>vr^mA%G!+@Zuc#f(AW@0i!x5)lH2!7c9&;w1IPiFQ5+%}uE^eM?D{m4WZL zIp7w4Lfx3;)cYK5yaCcdUou2WJIGYr1rD^)f5=Xr=0()ap;D*$89-HNH}}_tE>1AL(hu5kKp~jF)#Hm|(VhRF~ayxQM!e39^t+-<(k-*4WY=ef6gg)jrKbvXYruy>X> zqK#Uqs}+Y!ar}???D+WDWnMtMQ8Aa)NF`52DRi2I67+lZtrhBjANE zchdaiL>DYEw?`;$i3^gY3pIU|?c`a8e`3AcpSBry$-n-f3(obmB${g3gGb>I6KKjp zsaB3Mwr=0%soo|)3R{}k4~33?AVx^_H}H^?^*=i-V3$--TS>4BDA1U zz0SeaXgBl<8%84f-s)~LOt59Wwh#XdOQ0y?F_f#q{6xfI-0MLgP}b`o@&DZ1>l_L_ zLyD;Bu(NLjR-1W0lLmukSVUm+e_$2DHaOtwpGc@gGDHZph_PsuhU(4j8I)7ll6#99 z=qjdEUds*1?fnGQ&-(-05FIUU+Lu zN2h3({zw$-R>)p`AGXRB-sLr5pld1}A7!gYM-!AQbu3}5+P+c0Up{&Of2{>O?)L=Z z%EnN9j~;Z?(F4u~3_oA7Z8bKHI(ooYLimJt1Rtt{Hn|;${+6+eURdSrVt=NQhlf!e zJ=oZM^3~IS{ra~N{!#lseE!Y)#^%w3sWV44(ib{CMj;`vC99*2*)Zx!?Q(;LGKkL! zt;dSXKli-Y2QVjlr@=HCe`K7m)wZ7+oN`>p=5UAV(|?f}V$H$)MKUXxu6>i?Vy}aC z-Q@tj2B+28#F*OMaa~DcV=_+WL~wT01dso_(}Y6MQ+`2N%?&BVzqn#bDWCU>BkA8Z z0*A&I8>_YZy>5m;34@0$5Oc)N!X_w%9MD>F0;O#ZDRPtnRd zV*-cv6i*?>O?!o>eDx%-nvb%7r72~r$i^gGC(02`*P3M7u|DthZ106E7{rAl&o6(g zdu-I}njybsthX>ae^58iA3r8V1?S%1>)0fCTs~7h4e}2DJ-J)`^bOekzRBwAQPADo z#fHR&;Ea+pVg!W^eg`%xhNF`->5AKdx#J5WI~t{WOZM(bvBp2!f@@(d@I%-kMm)r= zjn(zlO@Gtx0)(vkan^&&wl;rB)=fw7N8rp9y05bmx{MB&cS@1kWhKZ~uVK>R^M*_9~I%(1mLjiWSYtJ1=`e zCPl6yzavRmjwV=!JHTm6_&@Uc4^s|bQ4)Su>5r8htE)^rre-3W8c!MX$TU*7jHHQ9 z0D$XA5I(psf8N+>5;%JMc(5Lnha+hWWIazXCZhwu>eSJLU@MkufBfP7+vwo^^JwqI z(F17C5Z7V9UnJ!)jmK=*H4RCglKmu02BU!$aa*e0=FK5(eSOs5C0P#PI?8&j<7Lw{ zO+CRqlYRP04BCcyik5ddO)S*yOUd`?wKm(-e@bSU$+|@x+-_#)Pg!g4ob(e! zjmB+#^V($RhV<>l?weOX{BeKx^}Fcx_WtgqPQLNdBdEh2=St)0`c6ZLS8)OUT!9tMBhe%i#wWpxdfme?MBTeY$e=z&+8X3_edQ@jwGz!tyMV|@Aj1%cF{ z63J>O8Fmy;@0K}dN?onDw_7}q{`NPd@)n4+Z~y82+uffJ-akLsdAs-K-QEwcf8Kkc zfByb=XOB!?mcRWC4F2Wn_N(2u?|y!}yR-LZZ};`P1A5$Q>ysDBJpcNKcY81QcDCv5 zyZhUFubLeQjH2eUy*aRJb@YH)%|gXrg3p}FgwGB?!0LudU^F2~bNc1q|6|tR;YpgG zgb~z0DK00S7vq0^ixg;t>>W%ini*FTfB7)}7MJ^Bi-Nwefwi=a9)+>9+9*xlqLrPI zIwXBPu4~;lPvxT;?Y5V;;T8ANDMmuMsP|LZc&c0w!N*gs++JkaB6t=PQ=ZV=^k}jJ z7R?q%{%tdk>^ET}$di#sExF;d;E{w3l|O+V7r4TKs4M$<+AFUSPmaTCVU{awe@y^P zUga+;;H^f6eXZkF ze8xj+B&5T}))iHn35|2=UrVUke~(VT@w|uO-a*7P%VE+crHRz{q}OIwgnNm+I`RRb zg(#@(Cw=PPr0o?(txcGB4u|jzA?7I&=J}$;R{;V2;IRBOJam(T!;bet#Y8YrUuru3 zexA$K0p%uALk^%BcW}l)HIo-fHLf{Fa8}a`ao3y#Pf&(?0&Ww?GV4V=e~!%NwWss( zWA)2F{?i>>;H7|#IM+nO(A8k3HeSOkj;^%j*(;g9?7CC74qWr9m{VC!mj!lbjCwvETwy?psS}uqr?@<R>$D9}l~GF)A_&zfifI+m8mh}IPYY;x<^czRNlmA&7n zy*)yV&=(VKFZC<+Sv|GudZ4>`)@y5oznRv`*H7(QqV!B#BlN|zHombvd1>$6)*-oD znQoP^m5ufFYk&;Ue{7tVdKQ>L4ZBr)l7pk+qedSvN&w%TynpP&i$*9o*Mif?RTKyn z)f)G_8Xhp~+ZGkDoww6Jh!6|!`!C(=Ht>f1G0SF@eO;due=v0nGtAt)VSTln5tSJ9 z@0EMF6KX;DM)X}Bh~lep}Yp2r-~ulA0z_!CXeh&rf_j?hSC35%j+#x9x%tz$zC@N)Zk z6`z&Cf_;l#e|ro2dXkNHls$)QiuAiqO-%wxR!K~AwCbhC8X~{TU8un4Y+lf5rES+`QgbUq6+v_&)W%`NlltU68duHrDw! zN7;4?^unm{=82{v@TtI6;kM|id6oA_RU~I;x?rTUpK0K?`9HMWgW)R`|k;r|&6CZ%S@65!zYwMLGq=aMpdGPzE%R0y3?l=POq zK%79F5o?XhZsyRyEGd)`r%=jbc(?Gxq&EL8vnSFTN6}ol1Xsoe_>wS*pN7|NQNH;K z7EltWQQRFwLis1};wZsXH!jkSXYYv#h?H(~f2?+!joxbNnF}2)DniiS-c=z2kBDQI z7{S+VF#@lRqs&FY8p$8Hfty=$*8E|cb(W^d86gJavjkKL#DPof8P^C9wB?%1afD1m zIx6k^S4g|f&J>6Vn)%@!3(ZpfQPwMTk64zWD3)=CKTd07G-c zItaPUSwGPQif)aeiRI!We*Cy~e4eiuZS9(gnJ{Pk!e}X%r2E`qqDxg zE@YZKc5d&DFvUTHUzYrQ~obJYmn+B}`)*ftVqN&^VuAx@8y&s4qLeuE^6gA8}mA zS(Ppz;P#}=2786=f`Uw>o6u2ivVl;0&C|BL{pwFEwKmHynKBkOS=-LstXlRGf50ZZ zVbwgz58gaQ&1zHvvU<1sdi(V|f~*A|`i5u?z4UI;zhmNtR>ju?4hD_aro%LSpdk;U z?N2h;A4&QgJusFf?kQCCDB$eAgf31A|LWUs)snlVEpcvWfV+R=mUSAV)9z2#0*%38wT%a`oO zY;zdGBc~O9pf2-K+5=F+WD3lXNOjwj`=-cyBX+WX;Uue?X5eQ{wN0wofADsz`&s53 zytrSRbg>iI%(`mHTGZJ^Qsjh)Z=FOFyEVUWh|@GVC)_Y#`(;HDNo<(AoY)t@M&v^p z!}JO6>5G>9uIY1(XRb=gdgEDD1V64PsLWz-u-e_KAhjyt4zOX>ceJSe%paH;6>=vs zuyvgJZ%j&+X-(K5LT&ike>}{b1Yy}N^-@>eel2;0tWD}r1ja{o64P%4sX-yeDnHkm zHSo~TduyyM!Gg@HBooRV`mM?PYT6ELQBZ{eF7HEwjN$!UB7_r^CC;hBCjUcz=?@cD z+$1Ge%Hv2AYMEESk?4{+w6aBk2)uJ6q-rh|Xc^#wm+v)!$!M7Qa8Vmu3uB%sEl@Pvu0_?0&1V(lGEDd~tnRcg0+(-K=0P1r zUQ>(h-Rhrcstl4NXcx=hFK=XFOTUbR>@;j;vw5%17OZmEf2{2je{p#(cY*hmBn%#) zNJdsA0jr9iG6;Jef19ug*tE7TXaI3pn+!t9P-GK$a{eH7(AsF8flS3_dd~7S#40cb z>c%sjvX%vb6x3-vg0Tw`ZEhj4@(>4O0K}h8iRpXvgI<{%~DB72Td^m%gZd^VEFvTh-4;u<7Q? zeYDuTscDbSpyE8nAVINlxtmaoOHA}6t4q&{tbA_ETdbEFBIu(Pblwv^T@F!p&GWbW zDPWVMTn$Ite=LzM%jnW@Ois4xTN39cne_T2xIoF+T<*qj93d-}C{rf2AJKpOjIaIg zY^Il|#?_AZlt2?yvism%a0z?j=|Lro;GousA|$n>HOjb#TUfiLNPb0gAAd zlVfgj596i`G-Y!sUfY8tM{ma5*p?*N*LkCE-J~r}e+$n7yGN;SNE&{`AAGy8MWzhI z!5JsgqS-aUn-}Gp3q84QF4d{*j+bQH{qN9F`+k%@w`l#|qdv5yI|2rJ!ksA#Wy|-F z?_A_&N)KUaCul>Qo8P48Vf~a`V5Hc(ANX+b0PtSN%WtQbF?0*6iU?ieSj^vJbqZ*N zL;^t5e+umaUZpKAhU$q=4gi+S<_Z=yxV)jD$=vLD`0`;~LHV^Fo&%dcbOn7$5EL@c zATjhPdt|T>-zvoEZIkcf^8B5A75$|3c{*0ni+EiAaEiZxTJ6PS6>V2)GaejekA#J= zr5R38RMGB7-Ni+F^uYCJRe#jr_%gYh>h~sFe=L-SDlSbX$^@3&$C*N}IiRX*>@@BI+0#4Ts`Q#{hy#TI9p^1eWh>7;E@ zAH|d%!tK_xPor{}CY4(1Ox-T@Y)j_pBoEM+%^>xrcP50$JlKuB2~?r~gz2QM0kZj# zBVM%}3q(9aTWh8*fr!+#-)p_XgQ!Tkf1>a$cb_AByC@WgP+A-kWm210qftB@)oh5A zZ`u(lK|3M&@in;X*(p-T15ZzDodb+A8T^6zvf}BOwX+>S|FUalz``H2%Ia97;xK2S z#$Fz3n1Tm{DR9$GtaV3~UYa85ki`fEC7_wMA+0ASxN;d+qGkjtVit1+m-}e<0`o?|JA{8O+e66T%p47=mu1b%cSa45*0VW}>#v$Y9(M~XI+B0O4&l;CZ2)*? zO8q4(%u(ZbwJi^h`c|N`fG7Bv4{rRpe!m$dkN~s1q&fEl0 z0rU+x1_J4`tp>?iAF%@RP{u~L&aw47 z`%pW(MZ%?NF&?UjQ>)Bgbo&Vcp@hD4K6St?xDWNYpBx8ze-o61uO<0%KZW$9ZPd0d zv#BMy)2t&e19aM4KfjbErEc2t;->UZBl{J)>|mHC6!i#e)o>XDA7qM^#sz{BZG{Fz zEbBs}BnPmRiy*9(H;Giq9Yz~9S(ZkrMH>^=pn0pz7R`AhZ<^kw1W;&A0D#VVan_~q z8taW{AYABXf4Nb(QU^m}G!g34P%)+^qQYE*ZFLy{l+QSsBU>NQ(EnazKdq{>&|eSU&UU?H=!@0)oEF=wNsx71Nf zy~6$Jux)OV#hduzEnc#1FRE^NQ8TZogj@{)K_bmBsoNqIP^(4i@3p$2_Fj}n*&}?5 z;k1@+f2kjs;CP_-(PPw-sU72J_v0|mdQzrkOe|O=OJqBe#5VW+4QJl5nq zjk6Q)%nSAm-@lZ2!x&)Rv#iX2AQF*;1+e-C!I%#wcEiBGyc`jme8&3b$ib$j|W z{E?g0Nb>wUIxeeG+1co9%0Hv{)8^g0bF=frz4OW4yz@zC!@YB3#&_z|vwq9#s0;WA zpZM=&&wntx*BI%I-@5rl#`@$sJ1P0gd5V8T_$HYq;N?vVt^8aeuwdY>hK9o6fr zO?ir;B3tTZk?5?K)^the9{h}}Pc4PIs2U?{+W6K=Mf?C+gmmd-qrnMu$01W1l4LHm zb~bfr44UV+XR-X6kJ_=oCE4~c4~JJ{f5#fT2&@r_1K~jE=E0Blq=tbgS5iZ>DWdR3 z8NV^afBEz?q(Z!q0mfZl=e`1LL_N9Jry%)zJg_%>#3nvS%Q?NSQc< zZEB4s``vvbVK?PcA(e}Io3 zwHU>}$Ld%bCz1l^P#J%+zL6$A<69^ix^=7k@_+rWwWvl+PAhhzfUS0H?d$N>fj+lw z-v6yznHTOYo3)=mpZ@bFwV&@y|M>>ed6410h3JU5Q^JY=7xl~k@qhon|IhyxjCIFM z?{HY;akpO|Au?t}2@~y#XnTgfeCRVpZ`k`w{MT?z0SpT#SWipRAfvQ(Xb0lmS*3`Ohb@Zw)jJhA#LPs z-6F7`6CEz!G)q@n1ek`>&z4PU25dhrWf}tS0h}L*e{2afOnvjq zz3en!r7o=QaJcELQtN+juZhXX4D~dOc(L=Lr!(YDPRUD_xt_UFYjT$Du@izU6dNmB zSrtFasxhVnFh*z!J|6YTGIIQbRIP|1vLBO7wkvw>HTv zx7v~`g^0uvT_77WO{W>6e^=X>kEpGKsBdMs(N1|G^K9K;Cjb3qlGQLM5`V9STLy?h z`GF>*96h2wYU7Xze|s=ltXXB3r0|A{5E**(^Qy0m@>i3DoT%wFw?pu^!)&Vl-w8^y)7SRc z1mO%M0-HLtkvc?B$i0bqM)*}FzOnCOP*4CJh@kDp0BG^+e=G;>t;LpW<6cNWd1{+e zqsaBunJsj@(Fh$k+d0bE`)VhcZOsq+^@WvfTY=k9;Bw$dXl?}**cJs#Och{ULP^I= zxO1ckile`*caL4}glMa4cEJX`!g+}XSXHFsjfD3!)hSU^yMz-$2KMnyc1Fn^qrkzy zJ@PORz^pOJe=ya7Ae2bRkzJ?7Hkf!?CB@7dS4VcGw+3=3;mz8*Y9duJ6G+WN<9R=LD*ftUR_7x6+@kG5K+Ef z^!J~nf1>2~?2f*uEkcwz?{eF4r0C#y@^nQNvRr&M9Q$)G#N4xydigU=&BjS_ksHIDd ze{C+Uv;?>9HEi`Mlhi#AR^Wym_iXCM|E?NTM=fP}QT6o*4vDK8lZ~#vn*OuEu&1F> ze+0cu<_=&#toh*$!f=8*a8+v9ywiP+xxM0%763*$I@z$`i*j_bS%Y4*H&mArbF2vI z6$hh}tMD5X{$Z8AW(bnl@-EeR=GyF`^;)m+wq1G|J#jrO10{-jxDk&$`__;QFXKUy zjyv#Bb-?&{8T`jXr9fC++-;N&ef7d%<2IzbUfIq@Z@lOT=;Q7IKe;@YM zDg8lLp1307v^z4)tkeM^h_+ZlR>kV#)9_EU7uwAGRa_03T?03@T-1-UO7TkkHF7-GkEd#eiAirHwKR-(CD=LNOv z)9c^sJd9hnc4uyI`Bg<*{Q$H?!b3MzBlI155UlDlk$C7zZhM}h2Dv@a(eP4jMqil~ z=zs&g&~d5NSrH@i9$BGII1zXV0X36mLUL@Zj-7_>Q^{|?*@Fzk4kYRK{rm9odPNk{ z?)@UMY*|wF0#*o(uqtY)fA+(|Zi9Giv`4ar0q1ssAf8G*=q#4NhjsG8e@4DT_ zk)(^hN;btA0u&44Mbrgux=l;8&1q3$i*)z61)3}Z1+qp!6}k$LL|d9QfA+uq@66A= zpXt2AJjq#KMBXc_08ortHDF2yj}GnfAB>e#S?9Xu2@q(or^05iy|}so8&XOw=R<`8KzTh1LYS#jhkyh z+70fmubIM2kHW%kf3IE7?bSrDm#NYxP;q1-c;r#CatJ_-kWfJiZWPE=o&h;jV@sBo zeDaZ@qia*z1c?5h!03fq1lp6D)a$dL&cd?N-Kb$bF72Dm__sNlDorY>EML z!skPAot6j)TZhmf>!nQ5shpDNMLOjqGD$HedT>?2gSHh>?zA_h*x|p~%Pvp2uQ~W! z=EEFPH%XR}E|2m_=~ijd=iHgT=YGX)+p=!~l@mNCc#~SbOEZo~0ws zwW)zPRYpa@s^N$l`t{vkxAIE)@<2MLCa6P3g?v6y9HQ3_2PA615#a}XE^UFSj-Kr6 z^eK}0)uo}%8^(0KoG-U`uKjvmH91}?*?-|>VRXa*PI0RqFS&*??euw;=dZtx`>&5l zg1L0QGt!C$oa^y=7MIh9sQ#ecTS+nYTu1JH?TX{AAE>V2&JV~0i2rJzjx`)z(TL%f z0kmZ=b5lhvRC!P>6=-_wq{)WLp2)7pPn@?>`8?|Df_dcNQz=cJX-Y2YfA08&BTy8$0yIPR$#0-FEKv zR^L-<;yYzCwW8gcJ$+TLSNL=crNeE#m0K{A>jF7=H)Sk=_J8n>364uGjlYU?PF80A zmmZg<<#BRv#W19uj14T*TRGnP!GD{Quj|x`;5z%_{qQN^&aOyTxam2PUIN-lyEl`K zvk#em+;%=k>_i#53}WRZjA(WJzG) zd@|9Wo_!cNEbX7@sCwj{{*4&Zv zVwFvT7bu&Fzmx#$dlx%m7<~Y)CKQ=*(M4b!S8OyeRR8+J7i9V_o}`hq;$L*d_U88e zX!B9DxivTJ$v^xS34YReGVU5(Y^3!;olH9ZMmap_)PBl0Wu1;d<$n$5cpdz$-Ps=u zuoYX;LzDMG<^#80Q%L-yBu0W0DV}Yc^!$57q{NAr8kF+%oqYc_)#j@W99a6waf_UP zpU>|h!=P*n^=%@cWKu&lS?(Z@4;9j|q2?l`Z)B5^^+hjR>xl3F}d;O(Ir%Ci3_`bJdtS0u$ zU9n13lzQUCbj{ZR=Ia5H{NcdTeHJ1U(hNF8m%Bt+P4jF`1{%>jxZiih8Zb)7@$}kx zh9A0OZMAhm73Dkf+7E+Vnq57mjg=QS?R(9$?9f!T5zDUlQcdH$sdoi~Uf%h$FW+*t zPd!g&CZ!{~D}UCW!B;hv|Nb?yn!;H&XFl5trw0vaFpDJ01VG|mJW2f|q4zi$=ZUR= zO=d;^8jerzu>bf>q*Bj|(9Av6Oyo7gJ#yhPb{e-&-YbhZO%ypSBIU4%YWw*aJYqGj zxsUXPEkw1(3s&bwT+IKqWBI@8DfKen@92eAX-j=L^na_I7D+sYU{yhR`q-lgpE22> zom7X2qz1b%%_NJ9G%uI%f90^^qYhR{St_WcuS%JqP1@DawT}2cBdrfP4edA>P7J zn3}}Jl=8gGI~T_19MGlCfKKQ8KzXl9edQ)ZsdwqzP_@WXf{@8XpK59pY9KE-KI|r+ zts#_FO@9&6XY!DEJXT_I+)(GczpS+FZfMvEDi2>>PltK&HZBITGF>QEj1#SvDXrw? z>QGKoD7g)D zLdBtyw_=*aV=+!BSAzw?gQKxjh@1Lo*!SX_B&Nl99~7SAec)r)f#dpZntvwG31g(# zV}Ifc<@bI7NlRBTxg7Bw`@Q%Y7c@-Xdr@5>E(7Hk=%ep!_!g|FT3oR2$_pyxZ=Qf< zdGo%*-g~c^8Ks>x-dH+9RV6mZdIonGNrStDl9CZdnJQL>Y&R&802h;F;d@&6IIS2a zc>j0nV*RA4WZA6pxxBQ$iEOdAizR##Pk&<+;)LoR4aq;CQ(%7~hGeTGgC7d7BoovY z!Wp6&GaZuU19rjLgkZ1?dbyyGAgUpgk5f7h|IT9+FTwV2oI83_D>N$XJXU^jF7? zpX$n8mc!eSX)hCsR%lQ{%-)UHcaWSoF(pLL&hP>QLlsJKfRF6l&*oNhZ{YW!m=2Dj z>puaBGIAeswVd|seYM+6tcq|l88KYb`5}PXckm;K@+oFpP0-xMe3mB~4LKkIB>jb) zY5Ih(5$p%h;tTzG^ce)2X=-sRhS&WtoI(3`Im?3@()4A|v1u6OE_>QCDFQWmSa~`7 z8AD|JXnyW5CxKkA1F3oa0t~~R!u_)jz*cU+i}~>G#g6F}>WzyO_zwBfq7G;=8$1J} z(X?3aAB?kgU$Bv#I{FuPb+t`#H9!{5)f+Wvi=>+_V_=+jVz)?7Hp`9@)wP7+(8~A$ zmv6$@H)h2y?q4Yn2X698N~A>0#U=9LDyd9~ejL`fZl^VnTW>w`pP!l%tdw+smr%=Z0d9Wi`JHPeJ!-&Ke65NVp;md#{saHRBp=i(9@nww zcOmUWcw}Y=`7cl{SMG0p8|ll^5K0PPHWFe64c3*XEIrYfPDesvyaKq25vVsHf0a(=IS45>n} zM~@{#f>rr6Wu%oJ(mniZrQL0g*W=__Fl9Gwb{TXEO%1k^;$zm=k$|WR;i7^Df*(13I zT0@=%l9|J^Q%B-t9n~Vo6_1wde?)Zfn4cRt=_W}z+vNbS&(g&~{`dm|iVPDMpLUOH z3Y=I3h~fI_V5{!smy`%SW;0riHayXg7+7EAL{mF%kF;%kIXy*vvRv&>|JO+?a^4!8 zzu)UN=T}C4p(phmNUcnbwGG#GDzJm5y}BLo)p6Zn1l(E~>u}NPLiP*D@E`1W;7N8?eIBlV7>Kl3xu_(X+C65=ffCE|yE)7Z?!Y4lGg=knT!Ax>_mrbF|1RqDl4MR$YP^Bchs-U}<8ioPYXL9Cp^o zopQGM2uSvz-5hoGrtzVIJv?Wka6OFv^p7CiS8e`SFDCC&UY3SgmvmHd$f|}rHL)LPdo=-V=FEn(Q->5E`hR-Q{Cn-)&z<0wuV9RZOXYjc99SPr@8!a zrl{7CK!t}-1efsv)~qr{zfxImkRlwS*^Efgt{BT~k>4;D_F$AbX;#IQC;@ATV0&^U zp?zM3dL3M;&CDc-$oy8}NZ0|Xy?X{JSbyzb7AcD(QeuAz2md2s(2+uGgMR@_!l9}P zSII0Kmfdeh0tRjOdpVIRrLYdQ%q$Ry^yy+uwl38?#7sN^U3-TfSp}x8;!+N}!a+u1 zDL?@8kzBgMQDrm6Qx$ z!Vjuwws679bsU!E=H83{El30bNT(`eJHJczZqufgIZm|tkr4x>jRJ7Rl!;c>KA$VO zX(IttYG|UNM4g$09!XRE(H`XU`bEE1{p5S1&Cf#<2KG>3*qS~hOnf%3HqZ$k6^|^{ zkqL_k6t`&lVeJAnsY1RP*h=TWKJP&k#lIutb=nBxFNV1X?41}*S$rb|$W(bB5@Ji` z;zW;%QLC!HUTeONZ%x;WzLfzS&UO3|QofQQj1XG)s0K|9(jU{nXG`k8Y5D}P_f6bU zou!pYCsnbOw%#Vcg&@=fycd~nl{%BeV%%C>TintWVZ-l!6?D!)6f1gyHzitVl@%X$mg=6r!J-va}$DQ6Q{SzO@F9oL1 zYra-|n@yk*XA}P+MB!s+_tU)g)!oUBVPkWn6Tf1IAdn%Cgz#6!+jfVs?zdmni&Gk3 z)2lj`t~SI-b4SXHs8&Mpu6jUL>>t%5hJ-qJG9Yb2n+#R^_v9^Lr&#z|PjWgQm@u!E z)0iFXg5ZC$q)?$vn&RM5h4S{IiM0t;yey%)QV>5veGYkIaw~VxgrdN5bTVUyAS+T6 zf)$;w!I+NGaTdJxY5jF?j~K19jexKaW3?H^)?%z(p{)mcZo#)Eg0!;*Gi6YeEMWpYcCQD(Wtm znvd$Wo|n9+la1~|yhS|()6u4*>9+r+Vzf!cAG-{fB@%3(IbUyfCj{ju6%P*_Ercq^ zSSi>^4N}1NdCnhR!O(gvI;%(7eeBpz4v&Hj zXL1$vwo1V+#G9RDX?RyA*y13v;_lt(#BK=~6+eK?!r9l}Uy%>lBu_C-2##KGS^hnu z*)D32SE7!K>z4wzVrm*RR@TLvCHfDx*d1uhVkf?U5PQ{Hyc3i+^mpEWxhu#>Q?;U) zEjzZ;_bZk^;nfezQ;FwWSZTJZJ$E4;+$#X!={&>m{PdPSwVm20uZ>Q&sk!kqJAcEdb}OQO3_Z zRM90kUDc6uEI1mPD+w}-b3pR_(xb4*%!zRfc?^T3<3zV*DO{%&<~~zW9r78Zo*j6_ zRVkz9y=7vJZz5CtVb7{|sfQNE{KKFRQ!Z|C7QxLY?uvdpe$WA4^#=s)-#Nu!S(R3o zZ{SrTwzf)5Zu}Z}(5)iqnN13gXwP=OVHz3BbH}MoZ)_@B+5zqYaas-Y-vyVZ-s@9y zU6=-0Sn9rpQIsT>GxMUN25QE|edYn-caLn5Z~HxhqvVprs}mi%PTwf|tnJAV$vCn&}Ut$wYA%CJ@3@+m+ON+;-RA(WSV>n&LU{G+%&R;Pw|TRCHfiAEg1^mX@@w| zc_!aw4zP#h;w-GxnO9In+Zb DcXP{$;(`_=4RS1I`fc}i?RacGP#Y) z`>dn8laD|zhgx3LLt_Yl1kDk8lI#*sv^Al*z0fQ+bD|}O@wG@(Xbj1>OocW$ z(|^zWQT{H-$FRDrEuQ7<(yM$%xXmFs_F`l$))9=s_8ppF|xU6{L z{_8sVH%~q8aWhP5kq`f+=tEoxcl)F48z{Q5UL$P}xm3h>k%eZ!!?T;G#_>VOF@3Zg zyj)?91)-Tx;0Y1?b#M1IJ}%!c{doKafv22LG}*c__>OzhHq-1#hyvp`RwG8uyIeZC z>ibp5DMpUHH8W7+m|;a=s$*`ab_wZwJ0<;1ns>1N&c&H^(_9i9i&^L0*@ZQ0hsv|> zJMtv#(ey0^?!f#3>GxSpEu0wkN9DrR2kWFGpBNJO%Z0@sFR9Oz>U-+UMJqyG`QAiE z*guAuax(mO@UlA)WALnPu`aNlE;xM6@(w~8BKsM0i*sbfV1ujxhm@OW+1AOr{*ly= z`y+^hvY6n2tz7S=@;eDMOBs$0=u$rHpM8N{+sVFRr9=yS;BFd`KCAJUB z5unFCSSE=;i3WclO9^9YsVC3kDRQF;#1z8^1S-!|c!a3s3N;{P=c{=zzJi%;>aAMb zOoIYVYxTUAA<6F{#w=r$jzgQ6B7IsyuG7-rFTr_PBYVm(uu7~_IXmRa-XaROIoqZp z%D@PC=^TN=-;l01>qJl0T9(C`n+AXV1^El}a=pJ#YaZLrfC$yCtZ&Tl;q^&<7_R(_ zE_XLQscpuEqwEkM3}eW{QWg8MsJ`_yJyn>WPrNO}?+EWLwlp}~FJ1D=ZSC11+PrOw zP|2?t>44X{#X#(q$J<_G^ZTfh)8F^PjfO%Io6P}*8}Dbwr_PNKaW}g^&=$tGNCqER zV*WoN_~b$BdIOdzy&TbYBQc_rYo7$gpq=nc5mW!pV7O0fXIoocXPXF7 zdP_o_f!p;Ovg(*#)2Vp#zwuYU4-UFVau2qk`H-p>B?B*?h+wb89pzm0j2msjBAZ_Q z@z{aQ=InI*Tj=MBzp1|F%Tli~^S!H*L&axzx=~=Z4v+8X2i7P<*H@Ecds`;yn^N`c zhIiwa8Q&cCgrF7IGX1y7R0-@=&7s?`h^x#SRJvpcxC!FS>)*Ze)L=l6e7*`nx` zd>RuKk75$Kp#JG$XGd5XZvxV4zn2h|fV%+F%jl|wQT={Wc;mYE%E>rPeI(npo{}qS zIx3P6_eiz&57eaL%U3pOOYu+57^qVX4jo^PUne^cJ4O2^LQx9Y*l5}qsj?0)sH>Ra zBn(=1^RwdGWcB2r5(r7p$PwVKY%Lv0A50&q+*K}UyoG-SrBcNk~A9L_u0zwR}u6NeG6FGQ*)AIQ=t% z+mz_-l1$LqRTIf$p@hpTvM4_-m5TkyZuZyozIA;4HHL#gK+{oWY;vqed|F;q5-oEP zm|s&Td#CGKM%09RxZ|QO*brAJP85LcK4>zoHq*m3@fQcD3M;dn?oEDMpo9kInbk^3 zUeKc?;`C;j(=1Q}?qsqZ@$xo98^}W?rm8<%9Jt`H=+A`zgmz4Zczr=Ttf(cb5dHBV zo7Y-J>`XF{{44b=pe39{OW;ZEo!?sHsD~X5n$DN?ydOp09%)bbBQ3i0iS5p@zXnx6 ztM>b0{(bYn1LmLDG_qE-K`l^Vw@YPCD$ES6$$+dcjTUVJ{keoW{^v&)uP`qoK*Rd4 z6U4cZ`}T9qeB=C>UKXKH5vlBDxSp<3rSS=fAM*i)5F;FFa17^kMsYrkXQ-0g5!-Pp zPZmEkCKG`+>0_$Xq!Lx>o%t@7ZJ$Xoymt0MdJ$J>uO6J0tD655P3H&PmBEF#j=;s? zD`w0m7G0(anQL0{b*)9>4bR?O9E;%-eLla#eE3+s_n&DF8lRddFOqeoZ^=YxG&xP* zQ&u9;LrcCa+^zXd&hMX2&rYmbn*5ru8OpK}8RluUlMpt`Ut>N#sV}53f3i+uyQb|< zGQ)e9I%xaSVG789k80GRt6!B&!+tG(qUly_hR-m|Lc${@)%H*3(WqIFV6v&gHSPaN zxp7#843MIr7M0~FG)9<;xt*C`UqKZUL`^r}Xf9gDHhQQe$`~J*CZRNkyjbk4Lp$*3zv-(4m@sE-oMD z>fLr^kK(lH+Dl%D&aI%zD_il=+FBx5YdBL^O$td(~pzrqnt32mm6N>R+AeXjOp_37Y znyy-x*_h1ZS$!Lr;^xnZ0BTR_-5F*y;iR#~EDF73J%xp$%0^I`VmXV{g(ekM-Rso8 z`0U9zPs~h$Zl?+={Ik&uGb?bU=9H;RZn|Z7>Zd#?B_X@okYM#igQC#mFL9{i@1a@2qmB)$#ZBN4b7w-k0UQ zG)7B|`jFtwB5coly(y~eKiu-02yVcIJGZ1fXE=GW)-ss6MwNIbfxk7UK<&QQ?E!y&@gY&Vx*M zZ^EitV(?$F%z5oF)g%byeNqvXB>?PVha1*;Xlc8ikiRGPh#un zM9iuXvArIS6{IIY+m17&c#zO$-zWDTcl1ZXNxykb+A6Dw4_Nl8Ximtq&#+DS3^SA} z10XcM{JxSKF6vS?y!naW;-8!kIz?9P$&b0bgS{W~WxTdH-9zpG%nFX60pZ+TI%i(mAVX-z+6tujhS~G{lkTlns)~O1HMN(l=+-X)jG@o zct&+;wdRe{vTftp3b^*{6ASs}9&K)E>8Xj_LG)f#|UmEkq*Vt0t#qJ0+ht5pL9 zsiNv{0=|4@I0&``8$(gr!r&341Oo>m4xd(f`Xny-d}_sUdojZ}P0u)W+z;Mm;092! z1x?Jkw;{AubQLqm^M=$NqfbK3L;V*+oIrzKx{AlLXy_Vi{ut9|$0q!#7cTG$6ECd< z9bG*pcl10M&%9XYIPc>lbu*0KF3}oTo3iU6Yf9c>_K%`XiCeO$GQ`zHQ6`$v#B2{- zlu0mg*^Bj&T}S*`w8;(>GN4ES{VlfYTellw->t>l1Ilg7RDAbN^1a|N5-CbyywEeg z0Tqg%XfCyDT{Vc{5H0}%I%;zqT55cALIYde&QiHPtlyaZFNSMdh&j0wm$CM4v&l7a zi>;c`A5@hm8?U=?V#eoG+quhwllOl+Ck#^+vTEdvk&$iGU2$~B^=TUCBaso2D%R|hFECUwm7&_ zZr0l!w-<8cJB9OD)0lW$AKQ@ryw*bAXATIfZnw45{ch8GTp&atn;qF4Gd=WTJ+Pju zp--TmYgzX7Mib+^6azMaNIbWxuR~jB*JtYUl#>hFn&mjY%+HR_TLYI#v7ZjqJwH9n zJkfjyY77I03sp6J%9_9_R9g35eh$x97b3Q9aLh|ZsrkU%{~Otxzlt`_Q?4RmsrJ$1 zL@Z_Z<-O~zO(G6^`SMl?8{4>Xgq5b@qhzpmYT%V*!g9SNteY!B*igIUgzRgP_zL@3C;Cn2pzw`}=C)$ZNiL(oS+HdiAJRVIaT zi8wF;Q{8q)aWT%sm$$cOOHj%KzoTy_#$;=`*!TWn0j;;1qr9UC?rjdQS5bRtZlp>_E-*`0TXDJ+U$B7TW&PsI$0mTe6zx3Af`&Vh+K3(aU zutisc>E26_k3H`2scOZ2&mX+I&>x^0NCOALWosN&qpK*>D8dD6m+Ca1NiE3DjJ-MK zF(kD4e9VOg(IDfcvQ7%sED%eExIz$t&#aTxr30MXQ{qQtKp<$5=MT1=_D#C;K|vkT zw5Ui8_U;O#LzRH7EEj)t6PIO89OGEu6RvCNaPpJ0_X4OcW%Jbj5?;pEpGPSA(#2mk zCNAiNF69gAIqAL(Ib$89D{j^6rQ>c;TA6~ReT&(>uKaGA0cxuZJuLqO$vcR+9eaZ3 zrSw_gmBqbE0L5Q15wl|r%`+V6>wR###HQpCWktGtjW=|zMxEk_@ znR=0_)8A%gO|1Q6pe!#+eM**Yns`EFM62Q`2VRBFGsW)3q4f9cH#-ZG=n#z;sg7Cq z5jBqO8?iqn0x#JZ^tSv%okK)6%*p~#Q_TZ>`39#A0PN8}&Q#5%4d4EOMUCQalRsZ! zbr`FBzz-UeBzA}e=9?0ac8f4XrBT|=d)sMQYfleH+E4z8*QtVjD|^)cLx76ZyhGX~ znN0ze3~9A`LkP$cHOYE*i#Vqse4z zRyd&10P~rYa?`5K_(~P87v-b1pf(w4r!OUX`)JAq)A28y@L*<+w|k>ppND&LVXFJc zHx`?Le92;ZnD3S>IS|~|qCKjxV|FHpBdLcNZr~Q0%nNn|3TvR|jmtUScv2ozPk4$fKSkUw5(ZfPN}1v~G|^YZd~taE{xNT(86ihnd*vwF)XTykfx2}5uS2)&-*{a*PVZb0t(F*%Ha!{+PE5Wf7U6Rt9B`(Ak~PfX@#eA zyK9CiNg#LloHtg7XDLTdx4|-%#F&5lLYC`_HL6mREMoH4ZNZKawe?X=(=|vMi@y$= z)NSSptBFr|AfI?!IyxdtXF#MklLrDkHE>m6PzNl}7df(Zb6oyxN8WXqJD@xV0ma+s zZiA|S=&1b#o+PXFbrsda%NgJq`=FvkoF!`p-{aIEv!Ob@a+F&1hTl9Mwyaix>W@bOQbu6SYbiVF z{b+ldcfdg&LxOAq6}WE>m`~O4wbEgzfyrMj456s_NWwN+tP4;!FS+E(B<20_ zRy)6}*yMLgrQ<%{5K(n*cS?&)T3*YASF?b1@9)FwJtWdA3%PoIJN>xX@W6VZysi>F zd@hyv-dHNO&(1wSngs>mTfHK51V>cqL>a&5eBE~^BAES+PMIqLpenAB|J6*^WmyX> z?x9qVkIQ&c1HOy-07w? z-6r&v&#VHL{sj_%fsBv+{qMgUqoX{OEksIM+>X=y66@vJ{;=x;=}eDoBWW7>dc^l! zF&Ah^>cOK>BClDPySMK>Eymc^ z!BDR;X>vwqtJeNa3O&krV`aE@U$7o`35{jFg@-fyK&q<%Fv)J6RS}0tw;IHGlqT`D z;Q7XMgaXyNMLsfoIVmBnpd#XR2EK2nip713rzrI&_~#ma`}eB455jzWRG+OFxoq5a zEAh7V{J#`%G+n|Q?LD|o0NwMBR)iBl-45ISF)c`5c!+OZV-kSuCM3+?>A_s*ArI~V*gT!p3 zSc&8CmN_zO8|;}%Yf!+$Ws5qkwD@cTQaW+fHVgQoxQB(yLPSu1R|Xln^cE48#5aD4 zjK@(ar!EKkfvE<@d7FOwo&-y*Bd@CmFp-asytRiydP;IeR*{}mK^E6u(_{M(jn^jf z>Qljk+Kwz(5e!MD?)Q;7l0$U}4}nQS*x9_{tD`diQRv&q_u?iMpSQu!f3c|utP2uK zD+OSfc*Ah3_*C@v!r^tHJr87IhFL9SobZ=7$qPR2m<&*(CPKSxxKJM&t7;<9-G8sl zEAyMgqA!qqnRCubq0YJ#|2hD!<2I$Uub$(&U5upE?2D(rv@Q+m*E8~%Mu4XSQ8bI{~l zEDkw5#-)%c$v4^36B{n^o<9ZNOSM6BR?$=)szh9;8@4xXVg}Q^@NLvkW)A|=*r6_g z)6|d@Te_ZY7yFK>(Zx{Sql$MKM$bTbC`2=kjZaqkA~&n(;5C)oU0GLGHRBKKE&5%; zx+DomS@(qwY8+(5xJr^H3!hJQvP~f=&)D;G?pUHQF{IS#gQI;x8AomxE;`_oeUJAS zr2((_&FXT4GmFTZwjG87ZoW55J19*-Jd$Dg#h()I3=+*lwjzMqntcrQ zbqP0(LeV;J;@X>X7wT?X^1Gmtx;BFOAL^vA4ExH9J>plmLuA-!=aLFrcELV4-hQr4 z=w-B%i_dC*>P_m=>J$6J?Zf&PGSP}DpH4WU+8<3VH1eN$wuZh6#_J4|cM=+#y?GL^ zpg5_f)&^UD7tQvRF5|MQxn+R>t^vL=&=)U}AR62IMC)IT%_*HN&MVJHV-LFOr~3*) zdp^d0)qxfuny7=Et|Lz`^m#7?l~t>bBRM!_DC(p2qJp$u_MH=IwA6-1iMsjRd#ES=?*W^|_(tkZOQTb-Wl??7c=K zc%JcGIN7L)OfBywbGHnQ#n#h2dj%xEb{OOU>e3qtztjn{yMOT}Xn0HEdQ-*s6MvVocZlMBh_6E4) z7$reyWT3>dzc?2Zce%;i4x0yrFgQrG$QgFV{>M4h1)2nilg$jXK*WMJk6!T^T-D5kc z*&MV)^I%cZ`J>t2>ZYIsjrx>^fa}N^_3*bp^jOd_@r;g}B>e_!A%(fF#^%0?l0y}k z|Nb;Vt6KhHMbh?KTT@0vWocK4sy;S!iXfG}cZKNqL%sYE5kJIEt*WQiKFNJwa$a_U zy$}HDt4t=8~&&`Tx#`5p6+6RsbLc&%+QLc#}Xbxiwvu+8*wm0 z1QYVS<^*ZC9enfjJ;=?vFXoC*JM^mH9bvt*5~MkbedGO)$wi&&zkpYRNg9pH+~*VY zahZNzf$PvIHBfrYPqZ=O{;PVqgR8Z&K^InklD!(^=KxT!VEdz;Vs>yhvSz-10BTCt z$6fO6Q=>Pen|Cp7)qawx_=T^;33L4b*$mjXwEz8+Vpr-nP8HCicS4C0?moDw2W^z^_H30D<%*U#iG zbO^l~d|r1F*q?p#H7I^VGCS|VQ_#b@hHy!{l$n5{57R>UK$hrhgbi8aXA#^*q1NkU zZ5S(jghB@iAJ z(Oc55XE7fvePRgjJ)ODm5qR#b!2l(7vla5tL;_0ns(iu}|BC%b_R&-OAP~z-P0e%F zk`;K~pYu)8ZN?sh);RVQxPEO$lIBM$6}k%P`h888bHldcJ)HsY>{W*QZq&Aifu2Jt zALZ9qTji-PEkv?`Gt**w9e}|u1`)M^OYkvBEau$gQ?EG@CG(2Ch}QGJh$cB*);r3~ zVkOQ^7ec2U`O7Ux5hb&aXSwqiQsg{*Kv&h|$3KkR% zOKmq(XT*jXmS%JCPmM#I|27{8Pl~S1;)JP7pW2`=#Kr%GU{9FZvLSp$eW8QxMFUd2 z)nc*2FV;<~$Zk+mPrdt|bGwg?o}%@w4oE~NGUr4t*9Ay9Cvu*1aCtYyM1MJaZ2lb; z(BVxjz?3b1Nv^D^cD0?_HPEF&8GjFJ!~Kq?zx6v7brB;9ou;7lpW5D*-QP_o(_P3V z3Hn(xZr^snJ-0Btx)@m-n&xdja33(E_vPSn_if+F4;;&f`ASPZBaV}eW>eyM4CLi` z0^x{Fy{>KBh0RDBwP!2;k|k|~+xHqJyVcF^Ptafl8QblA+0V%y73I0`L%=3zdE{jZ zJzaC@BG=Of9Z;%q!vXnSlPkZ&`EQSOkZflNs2dM94C&-j$sN3CnA^QD4^2;!p3u_mESo$`r?HL_%f1$-7S`ARsSqcu(kvs@y zeA*wy%>7M#2Sy(C8Lv1RB%9PFQ|c3*RNY- zsNw=#mkfj@khu`cqioW>y|SKauy};EY+$Pj@lz5-oH2yvNr6fn!6bwk3wl}Af_yq- zl~7-J5UQn%-YOmC=zpa|(R1NOUVUj90%dtbJ4yLT_Qlj*IF;xsU!={}?g-td*wjHj z>Q`$7CcX#p$*bS3vNhFloh_C$38h3&5iGcWIxmp8dgDdfsmd&%tDtAV5+3$7%4E%7 zWnOBy;W9P>HvEiT!4D*`&Ka&LZ<*=?yJ?UUpN7t))>^iL@gb$=X>-L0e&~(i)2kj_+ zeK~VUM)Ik72J;yCyn+#=7{*5KWhi1OHQ8NbnSKYW{M45w5M#`<-R8A~aP zjHpB&fF%wQ90Q0Nvh70ame+9y3K>KQSJH&!$6_b{dyY!_2f1ORIfZXn;SIH7U7YUx zqQuU)u1}?MX;$FRe~6U2>?Vum$8)}!th)_Nv422EiJ?Vfh&M-N_)vE(3yZWy$YqRNh#>~N=HoVU@kiY@n@-#2lD)6I-spyA`3({xDQtTVF}Vs zq*i(>HjK_5v9gOMC5gwF=%W%>`TYPCUB&Op^;`DW6SyOwB4BnU_Y|f))%)&5Nbs6k z%%T8Ad}!TDS|rdpPTsSJj_O6qRI79SjEDz6$gtYPftU8?yq-qN3PXhOjMfI8*rUiw7GnBFE3x?s#or9T{#}07a|b23 z3By^$=I>-b==kTLlwIPd3Bvd!qF+^oj$;LG(xLQPcw=_U3CV<9pq9}D@A9z6grnNu zGv#t8vB<LTonKk#Z<*ADs4Rm#mZmxhnAVo0H3&XI!Hh(NyDmqE+r?KS^p@>rQgm zhPA#OI;>mUIZ0@EY^OhkP2K5HR$&n*it|*yC2}zH@?M)bvXAg09fvm^whX1O7~MlJ zyJ{2>k5UU_Sd;7odCs{@tAAW?#NUmJJb(An|b3(+dmd2oC%>I_7+JkC!$-KmBr&|ng zo@!+kqL|!^L6DR5+|1sBCzA1J_9(fZ7u?(B!u3$rPDDjd9{1HraVK`Sxz{8kOXi%G z+T32G0fFxhW65Xgx+6@i0aOmqRbloHcH#=!f+6#;*Gqh)NEN%#Rb4Hw%juO>Ve;|) z-rSK17n?C|F8Xq;C^C#*$WXJQ?o-BS%a7mVjl7dN`dxy~YAiybow3ZLOj5g21=)sA z?x%&?i`LH>36d%Bcro88c+@|Vix2I7gRU(0)S+coepZrToK7P)>gnD9AO2|VA>7y9 zg#OWt#tBA)<7bd1Z=*&FR|sTWQZx#)NI7_+Ah}EGOdh`1WyVhq?$xMX^nN1zh!>g6 zXo|ary1$sriDgvM#ogZKk5vVzsPMVX!{hihuPo2QWL+V}0fHn4;zpjO3&-Qm!lSkv zTQ$Hw8+eFNk)IYg{9i+Oz-t&XM!d z^btnm&bEBp(W>7hP!a<9#=_^`6~-eu6lXvikuNp-eKJ<5hL03zYqJL7YAcO;JSO=} zX{$yp8Xf=U%PkNS7TLmm!O;8E$W7^sa-hkjqUeuf;HIQ*>!f~>@2h>v&VcNbO6mP}1R}LcsbJ1XzuIHer0W(C`7 z3enogrY`YPK|}|zL2bo@040S5Q;56IJykxs5-__huPlj3L=67WAqqL@f)IYx!jW0t zlg*5@ia!+6qG_b5JR-Atk&Xa@I7Fl19hW3shzIhd7GD$C zSC;;@iu3`O@z}Jns-B5-1Chn}Dj#jg5^Ra1PAS>#pOLl_C$3!rpiSLcPFa1JdmrhydyBbEuU2Mn1zl1hI`I?OXdcQc3 zaZ^7HkBBB?wExWxzpp*E@^243L-6Cbvywt^9YEm#&iPSmf4Cz=NvR51qfIFs<(V}# z?rV5-;(?P7UT;w8dB*qt!x;ibLK?onig{R(_#zhX;fcWf_~7DNIQtH1D$?{-7+58y zm}YJea>ASRjjX_TB?K%-tO^`nr#9R>ES>TeYl_<{wJxj1^dlkvF%30$L=1P_*8P=B z{oYN0$C5|&cPI61!I}SI8lw9Mwc~MP#3W#)5oM%Xs$pt{8da5Y%l|jhz}iq~CDo-V zGhIGkn?B|t&)B)e9DP=WRV(1)RXH`>j*Bd8VXdv?H!=HU$y`qFw#s|&G0|wB3K#FT zB8Szh^ua?&k68i?PC95ON{oBA66&Ij-b@rM6kAIz>g=;)>W~^LnVR0=FVe`{vj?Y* z6I;}!XMVQ(u{dT|6HJ!G#s4CkYKv!O z6S=|7AjHnk!jWaN$eG8WU;K-Es~GG6T6ruG(K?rZC*TbjS;*g+c}u4VwfpX7P5ss9 z?@p|uuI$Obw1ff>NfkF;1ibH$5|L?Y8x!x;GC2@vA5OG+|>MI z;Cawle-yNwu>5pfJw;CtGR}7qruKsQe9~a6X3LdxMAd=B@#FSaF+8)rsVp4xC^$^C zEINB=0QCMC+4)$cra(LBosM?hohq%P%=Hm_?-)qbwaGg&bBKE$)=gIw{&?@4VYAIl` zV`_W}&G9q0wd}CmYFC{Ld~!`e6Z}vg1{i?M=@SInDw{V*QD=bz3o`q`3aiz015RGM zD4`sO8{SKX;o?8;`gDWTp#6@t$rf!3LX7Q83HT4Loe9Q2y0q7yFNoFGWl4V4r)Z== zX6!o?9+k6Zd59dLHfhL1F;qRP!7f`^IEyrBh{xFq7{2+_&PnTppJ-^xJ};JBx}FqT zF(m*IjT1{dlf~cC2h0QSFyg)orciR2n&RmBJ?puP0@aWpAszhB*Q10|RPC zVI7U|KDH>9y|xSEh}x0j5&Zm(c-%|=(NYnx+3wC%1`j%rNAoLfq@~aSdlf@6w9p_a zS2*);p7mIqQo@`YVrbzokE|Bok`cAQcR;|#y)Q}}R~(bwr@k$UPPVGDB`hO*l>SS$ z9Y{IHRTC}OHAFiaP&$gacNa4%V->}xS#hk@g;ahOW!qSw?xutHBhRTKU0KbBZes|b z>c4l)3`O@y`L<&kF>K-8B+znH4kA4D`=FcpEY|oIV9E7w z4H#FPFICp4n#impmM-Ktk+$l=(5ELsuucn;GNdlf-I^>T+!@@zO-|T)Nq0Hyy;6zH zPBMDknhndgReyCK^E`oDtP3b_zs7Pvgo$=;;Mt)7KZ-Nsj7|kDArxC@v5>{zlV=7; z{3>VYy@sf`x|%-Hypu(bOL3HvwIE%iVUiI0;1O{oK-a&4P9vZ(LG6V4<;iuW?J0sTs9{$x+ZNL3JyW&LKCJWyNmC~ zj#RH0m;f@UDkVbCD+5!ilc2yA6>Ws+7;Pj;R_p2Pl-e2RJ3TcErzkqGnj4ssNM>2W zzKQacT!J-UYhE!`;aq~Qrg#h%oqwxr5Z;b#?_8faK9W@`==`ReOR76aX9|ayAm~X>#p|=o4WdELVE3A zonFVmS6%+lmfwJ`7vN-fHw!S&xQ$3%Vl0DKm9xZEIZG^G_<=pVqWR#&(UZ$n=1Wo- z9bny#h>I~A1fz>{kPE0lhMO*M6Ps+f!7*cu;hNwWJm4U=b(Y8x_G_T84PhEhIMKG> za1%tJ&<-~ZEKa{g_nJ&=b&q*L_w0SsoX{fqvfc=S;H!Jn7KnTyK=v~8XhlGPGHk*J zwF_dvT`c(Ea-$NF2*eGe$L-BaXluJ8)K_zqX*+sJCybkA}?7LsvTP4vX<81F#gb3|OSB zC35a$0ZY0tKHC#m5ZCd4t+6K}+98$HCmIhvrgb*ffrKUMMPuAr(@@FcZbi- z5v}o-yn}rcD@+TG&i5mk|an?EZiKYp(nM5Rn6 zL9+e-tj&K=8)*4~5Z&M#JCXc`i0*2gDPcx10zFtj#`f3!W?Ms&9Oo6-LiW2y^$D%(Ep<@Jeu0dz#08j}zPI_`gVE zVp-}%U>31ew12|awKtV*3SJbEm^(H@#F7HTaOtzEIG$Q=Wc6Trx!cKQtuAe;)4r`H z4%L;$s34n3G`+5RJLfrgo2AC(I&u~WFK`JO3?GhH4M8K9K9@VIUHUw%u2%(M#*h3Y zbgoyo!xfi49~Mhp`owB3SGVHjmp&<+su;~-ARYL$2 zr$Qt-3B>7dRO#<8-wN|1PVFxRi#(AKKm14(l?Ou4D7i$i)7CIPxD@HR))atqH7b!3 zJa3qw=pYj2SxFtPNar}#`{5>Y$V@J|h|!;U&k^GxW{>d4wAEAfzb)-uj|_LusJTpH zZa~+(={S_M-=aW_<-Tnv$Ynodupa{9Y-;PvgQ3HO3zs==;dvKw0buQzp!TTMB%~|b z_vn>UvAK>ebLm%o1S`%>bg=!Uy-C_kIB<6biQS!r&n*v)m{jpU2N5SNv%@eLx`{vR}o*zN4*9rs?_(~ zJ$;rhd|AeC^M_M@s}Dg^*|+vf3!h&RYMK zXqKqIg5Idgg>mkHMt%1K-u{cNA6)AID*xLCju~WGC}xsDLG$o5BT8$p({C5Kva^tB z^wx?A5>8WXc%K%^L=XYOSY3GFz=l=j(X{N1rv?ojf=$5GpR!rl=VfabZ0+}9eU`3# z>&A}^t|g@SQhzXYl@PEt$!4n%2$sIi@zf-#!Fi#91=poTiIRnMwBAl&jl!=Gf9GEHA6(-t4`U4Tu~JnwBF$vX89kK1n5D<5z9M)2~^-)WKXzcq57`x1$}3>!ZxzxViO~5A-N;Ud&{uH4Yd=p4N zTCj?l+>Yp18mqz`+t}EoYWiWfk14wxH4!iUc?*1`3MoxtNh`^nrZ*KGY;|Zk?|stL zS=&{7J_7J^{eRiVDP0Mo3e-@3Pg`)=-WQgqtH_0e?4P@RGp;E_i)(GJ=D~|po?Xa$ zC3;a?r<&9(6xszi%hFAAc0|l-<-Bp*nMOH~pH#V(L&g=HPZM14$}0WvP94`eVYZ|}@o(jvSKp-c zP@5iJ%)mVhmb_bErQc$|5n4)tjJtHav@f%Ikx=ln*53oLd1(5~GuIhbmobG0NWMv= zqR>;qW{Rq4inzvY?Kkv?RF!%-wv$kZW)vW#R9Cwxz;>yTD=`*QK7xtScR&fs0H1^d)$duS5Bf#&S+D>98B`1fb(iWce zrS_U*F&aLNnt00iN!(|o>6T$J9r+s*9K^Xl-HV(%rm?^Bh$Xmnm0^MrYU;;R+;pF^ z);jP!Z-v&EO@~aX*vE8TUi;K)iQHIm^8;L-)6@Wjon1Lw?&sLwj6O!~n}qE77@#4j zS1*5dyM&k#2EBBB5r76%?uYuv_~%>xJN4IKs(j`fEJ8+|u*cHk$8Ezuj{$r<3`f4N z?|+r6MS;JFIIO-B2JK;kuTn*V=OEB?#THa;6g&=A$b?sX@taCHcz*cR>k)o!LzX01 zsty1MUxnX(qo2ayo$btQLbu!7KPLtq+2>mfJ|C9FyJi~Lxov0#D|&F$1@L4y3E?s@ zG%tPs%;4iyb#d9K%^N&9oV&-r?L-k#UKNW$u5}L4qI@5s@-bd>i)4hC3GWqUuA#+$ zxB1z^M~+2}!x3e_JK(S>cS;sqOF0IG-%SDI2H=a5NcX{X8dktxthBf%s%Owhilay^ zlrZ~F(&?XWnn#=TbECratJ~(<1RfGrZ#y-Bn%em02DC0DwH^}cXVgfs2q~}% zG8VFjW)l;{^~o#z=@IgAi;(^6>z!5HS(&mK6Lk=w6^mYbg;Lv?RFNnl-d*}dH~QWpB>zMzg9ug@kh`a8K*M$)(ZA`P zv%nGIX*+dnrY{$ScHE#`ah{DC-^VwFb^ z{ZxGjnK-B4C|TZOn(mfNTUq>Bo0=#9K6HvlVms)(_90a|EbQkE)VyW2GYmYmbu($q zj}RhT7q>+Db!vzsBMO=x(hs0;@0vAyq&q|&?Nzc9%yqk@hyeVah*9z8t-^oKNZYy@ zilRggUrtm~b>4t4*YxC%S?Mrmm)cxz^BSszL3N_t0jklUudI$}6A}fl0!`|(0^u1~ zFjfyc2LFE9a(Otujk4uf#99YjaaBeqwTC?_QYFd>m1yz~>*}>LLKJYE36UBsZG3V8 z6C|j-nv|s{DHlBYtC7S@LjozGu{!TuiLsl6LxkBvG2E7*`RC^kN1{7&Ocsji5Q$!z5@tV9WaBZ{XbtL4qj zn)V4c<6&}TrElAoYEuD`h;$>4Ui6zE9|*et8k8N02rok@uuDG7j{{QgBE0@_{(w&r zs#D?U_PD;;8T%MJ>01z8AqRm|N8=4sUMGpQ2BKBz*&;G-Emf^JSqrtgasX(jqWY^Bj@1!knk{msqI5+fNx0eTCq= zs-I~E6x#~Ea>?@P6Dm4ePmJKC@a3MC<_@al)_A=xx0|b4W`7Eqx&=ql>`sX5Im6l@ z%O~#MajP{glwJWL8MJnjw20;|TY%bjzUT@g*KsvcACt%9r#v5(yx+T0ffGGyuBSq^ z#9Ps@$^IGTQ6~jwwl5OaYIW`4+qyX(*L!Y1nIt>{`RuG#^kOU3{Lil6gDZdYZuGdH z8pk`w+Si_AnP==OmN^pY(7oF>yONjcf$XUN%1OZg>PfV}D2qAsefd*n#=SN&wPW+A zwk&>4w3XtBtki8J^R#-7iPrY!z{@FDoL6u=S`#XA$CjVWT znjZSc-&QFHY-Aq)<9*47F`E~G&-*`#h1mTha9T4t1mQTy?Ql#_sb_dUqxkBvnUP!o4uq{`d ziD-3d5%8V!R{F%dtui(BCW7zTrVB=5k6gIXWF9Qtlj4^8o1(V;g%YoM<4ifN(K}Mg z8x8LHB2 zfBx)?!Z6_e;#kwp5mO@iGEJsL-{ugd!xA}?@8k*oMpRSQWEO#CvPQL)=ISpqA70I@ zx*bKyQ5$XKf~?{2tpK&H3KmNeXMIaPzyC7$-N`&c!F2EbiLeqViyG4(F}fdp^7b_}Q7;cwx6-=OG+u^nWl#5;un+M$ z3M}UG7$ zN6LXW%UGX*=BER0zRv1LF{|sAX(6QAlP6tmy%0&3%Nd1_%_yM?Cv7X&Avuq?^=y*h zB7ziJS<|e=mz$rXmr*wrmsxGFcnX`WNm~D4XFC~UEPN+Exa1QhAez*eQ;HQbh2`TWke>#XHk*j)y zK?FSf?j4=QJGJ#&a@lYG@z~%x{N;%#rFN-#4|OexRTM|nRkeG8^yHN+%S3ypZoK9( zDrs;5tRJr*0=Kfa#AAv0x7W5koIm>>0$+J}VqKfRc5H3>-W`7|?}ch35nl27cHTO; zO<*3)vIB8G=Te@_sDCOZJ~6d*wJ|adpTlNaqNoN(b%qgzPkk6k=|^5j2o|0zedDKj zyuHXL#*&udtY|+hSou>QANVpi26gM;e~KqiAzO!W!Y2v^8-e(S*)>yesZ1v2i2@A>D(hVcup%?h!F;4|gpEV(rFg;5 zWULY85^zyQCDyc>n%tlVr$1u;I?^bd%5)+4l%^W;m3GjtLtm`Jjzr?UoOLN9f>z#X zCTQyaY35R(=nHI+J`=YheoZk$34iY+9@?vJZT0dek~2$n03ZKD@^Ue%INH8zlO<23Kf z=zgSc69&Ki@`N{y<@?$wQFB8_RM3t8?Tmz-Xz(y{)!QkpOENEBF7hs-yO-(KE-(hs z^RK4wkW`ulbs8-Jtp-$QH4GnzICzgd5S!?R_Pi-GF434k^u3A1(J&?=YWqd(J<|)2 zlpq8CM%l>xP#ZqXcmJ&;8y0?^v!y9{xDV(rMIA10npgZ0g z{^sGiJtzwIYPBZV&_sF(=OMR^qMcK2eHCVp`sHggfP;hAnaw#OVPIIW^v`GXDde7q ztuuXF;V9VGjVR?jvnpjUFmMgK5~+4ub13-j$LKS@n_;$foTGE(*HhMiyFG+hs^q&8 z|ND`8Hu@%Cxmjwhjgr)W4DDqL7=z3#50H9*?SUuxQ>4Bklp7{87z2$@<`aN=#<34E zv8yu&(>s=h46v6nzn%QmWbsg6jmXq>DgHaKbdt}~w*c7&yy zUOau4z1^u>*EI2behK52v&o~sRdl#b0nzl<9J#C2Ao8I*_LCUZR|>8iXi*d|;l4s# zLu-eh07~7S18jcX{w~r*)&URYM~5LjKmkfCx{W_LD*{y_4JnNvKobjBLrs{0% z{S7(Y=%giu;E>q*)#lrPQ=2fhM+$Se_zm`f?TFp|kZRpSE~OtcXWCQCacMXK^6KP% zCyA{1rzfnc`G%Fw6!GWLHb#wXmh20bm;Mae2*$9U%G}e$IG(3)%E3r$^E&Nd1(;r8 zmh_3=8dy5uxN0{r=Te_aD?DwO2QBP`>7?C<(zXg=<83@mR{K_f*CCAFR;%(0eknBl zZ;H3kIAUAn2$0S!x4~?^B~rN2yWJ5mFr#)KDJL86$v$+b&hQF|rqHH)iDk@%W|J^s z?|pb_-O$M$BWUA<|Ln#xb){)m9ye^;_nKBkdOwFxydqzD^^b>i727Vq9x4plxi{L! zz~)wSnFM;#%a~PQ&8GeILHXDWW?;%G=dY+-;Iv(RQ}~&UIi*MCVr(c+d3a2LSMRD! z9B%VT@P9*j^B_bbZwJqfhV~^ zoX&K0^)XCT-g_+*?x;Tw*s*AQN=+GT(O%xS02u8KG1*Lj`839^RQV+af-eHRu{vRb zq*^EQ2bN7lY+oY?U2@Wi@?e3b60zgo%)+FF`tFb7q^%$`CsyHR^3^3Ku5as^Zwcq4 zg{Sd9HKoKLmlQ*ef95192(6mXoBtsoRE(UkG*2Qqb#=CTxl{42nmpRWway`%&rM$N zp0vf-r^ssqKoU@|>67x`m~-UBC0S*qBFy}{(-5jr=SF-6)r<|iC0->%gft{j;!|R} zK*}!Qq8X!r(~(3bncJ+%xWU7h7g&#*xkUBNYS3kEIc}y^`_J@}E zvcL}R^fJCg-|Vv!_q)0>KDwF2hIhNYb}Qmp1;h}517K9%#h9jVu+B{jZ<;1_bynrm ziSZJ*ch!`HRYy6xqg;dZHaJ-rwH(c#^YJFxqM4@eDU z)fN4yOQtFku!h>GeJX7+B5!0K;5D(e5>|t~Z>nO+el3D;M8jtaE|ezsqt9sb(D9f861;!6EH))us|MO05s{ zD{gihTk8%Xep3h^({3O3v)SPHEW2Wk%TR~RzZiYr@0@v9WM9rwZSdM^xr|sQd2Q8w z9^YOtiSg+d2qR(wgEf)BuPFWflcaYN;vkYzt-cv~#Axwe_bb9S5cM?%yPcHX+UmK0*@LyA z2EAtJ;LAVydURy_`M51rlZvC+q~u{}n=@bAJV@D%Shv_B7Dj)Ye#WDBD7})}F_}7k zpW3+n-rDtjHMEQkFB28>8?0&Bdaw~^m;OVL)}p#LDt2)T9NPg?WBzG6<|!7JUvd-gUjjkISDzCo#DO_GGL(fU6rJgfC9Ayfg=wJjux`mTQo zNERwABllL8eIK-5Yn#6}Q5=u~FPgxuKRY^y`rcpVdM%>TQ^u6q_1mG8JqVNd1jJxe zP6^dN+FSymL0ke?RioGSz0b~W%$6G5<{DcU)uvOdDXr<$M|Aq-g<@))b%@QlZInC|X7>LSq-9)dydkzk@(jz5S;d=|m?qD(&H$lpw=% zWRka1d_VJQG>^EWL#QgmBl2N;?saKLm!_}a8#*w)vDAs3)^TA+&q>P~_;EJ8(bdbV zWu}OQX(uOyR7a<%JzWD_f*uRCXQN%VaBlHz;ZiAC)L*0`Ri>)aO4TRi>!jO$M(oYB zf=fE(G#fdpf7wzxeG#{YkK~QtG0yhP?|s$1KvfFv8?3r2MP~95ct)^*az5Fk9Wkz3PlJDH=vnvoUYfza}us@MOfO|-s9e+o|cfVOmvv+~X_RsnF zFboZNPGFQcC|m_la3if$R;Vl$0S^veNyjkX(t9ANNr#XDzrOZx87MG%z~e4%(ZF!^ zbg>1!JekiPn&n*AWX<03Sr!ilaqZAitA=Xj4Bc^3E|E}Qm66h%QSIH$FL`Clr<8d( z8TEk-n;Ahy_}n}FjjT`)&%su`%rPR!%SApT1V&+pNcRTFE_D2r23v;akNwrLt`{?s z6dAZR$^E@ed-+M7t?@MNM7r7YVCy!N+rDeQRJ!(UTl!VE!LV`n#d_2FjWc><(>lXa z;}O?M#JjC!X>I*u6oqQ=%0s}kyHE|R(6N_K9=glrad%a89! z`!y2MqC|NBTEU%Cmk&N^3)i2-n|PTT-SUzfBR+{&6FuO0cc^T&z+UU<2&RKez+PFj zWiGRDDI^j4R*pTfgfS;8OMuTi98CD>obYQPsz)VUB)0TJI3s@Sf{H;8>82$eyJ+pK zo>nh>gp>P$g9*SEVdNyQuH-wK0xd;b zQuSfLi6J_w8#XIxfGxmelrQ}uw){rwIlzV82s>kMDZJB4!pLF;iC4msf_v(fV^E@Ti3HuFAu|;1~m?Ed3ZrbW@9(9$`9V)bh#;J|Hs(H)DL6r(?Vb z21^wARWvqxN}Qx1A4)oI2@91?;_vj2f-Cos-X_JBl3|9@BfYy}B?w;Pbcl3o-PHU~ z7$x+z)z|6njI_EIw@eI$ZKxjZ8W(b!6wYby0wL7%7S#*M)4hue)yaym%sS@-(9wYG z>$9I)jfInW9hfmajafNIHA_pgLNmOMV8YQLM`DvBf9ONzOxPYm8D2$%CmU zFxYsP%3CFyb=6>ZkpKqcl*K@<$#v#!CpMWVmTU4ueRkFB`*hWd{%uE5ecT5_AXncQ zjOO>%83`$-aV!dWKfy7l9ja2o1am;0!W`$yb)3`ebfzBy{JGS1rJsP{L2Y@Z4KrV6 z>fwFDyq6?A*RUm}^4rX`Q{pqB^Ptx?0*_#)_$>Uz%;P zba^R}=QwJP=F*5`1)e_2^Tr>dQdNS#$%R&&a|p9|Jv`jKJ)eMGE{>o53M9k3 zbc9=PBK-)*sFv;>a+KW6B9G*FX(<&1#`E=zsM~Q6Ji%#{6|YrQ-|D))yRIAI3(qPC zIO`TlI%V+evNlw3t_^Z1^kc#qQNM`NOdTbi8pNSPEclUwr7x5HRm|$c8sT$Ypx3?+ zODZja$2t{rlq9$l8!Q0s#uvkPpH;~ll5m6vjpAg=+SA>gZp@=lH~UP!Mi;8)lS!_1 zKh)&8V%6lrIiP)+Any5aW4TyrZ-XVE5q^rzSw%obj94uphfsjmC?(w`wKXz1-j!vL zvk3M^?ODpeo{lRGXMbzjU_q7dg?72MMA>iYaZ3qZ$1m)q(L)95)#{SfJ^Xw4M#sOR zyYu`I?G-iXs~8w)zL1!Oi~~(3C5C}=pqA!yqQZ0usLCrVf_j?2%Trxq9`!GY2(kz} z?`Wc>0$zh2r$T>^+l9)vE2rMMY3)yJNrcq^&JtmSZ?M zD94qq8<3Hc(hJgrY>h8b8MmkL#qc4Vyu~VkzUiF*p5ij}SCGlosx6uQ9DzLDzrQ5C z=&pAuL&@quAG>(&M~yFkMs)oAb&~s=L+xK%vBy6Rv_*zP#f)cE3HyLO3_eBw91 zRkM@`Y1+qF@h}~^=*^s|oITgF8S7SS{tGKTmswM-@F||J9fv=p&DN}OfxtdyWsHk; zaTx{Ky-Ju9!L%zngP?FS9D`5H={)N+I{v6=Xi(K>I1jJUvc(8<%jDO5mAbf<8ZfT_ zQqtDo$F|vRvb}PjkSu)N{+&PV6g?fj9?9no=6L702CP3x557>^XT)lAPgdESCM$Ck z1_6;7TEw_CaZ*No6bEn$WNACQxl&flQ|tV-un${}1MDE9_Ixbr6AiD9XXUb7_!mL|xB&rauDem+)XL)&g61LU5@k|0rF#9wePfdz z>228!0$-BPD~H+Qe2&_8aYm|USrO~_(h=0ajw6*xuSQStOhIV z({61RfAl^ock`WSlAxh;-K-KLwY$)C(j_V|))l$)K2%4Dk`!~Gg)recB^~esKM*i7 zI*~B`S-%~PX=z(J%u}h@>J4K<#v*7Wc+uXRyJzn7xuSnI*5sT&s;v{qM;FS_;A0qG zs%OQEvLDE588CtIdTaS8$4nM?{S>^vHt{TA`TTYOPo1C}CH8o1DL4jB$saj!l6cl? z(Y7$_8Yti{l>}m6xI3w-t#W)0DChO`Jfnj)on?VfqTD2pxgy^4FpDKZ*_nwIBMstF zO;v@tbc7zSUUzml9U}9fG0B*bc)iXZhm5 zk>E_$gPIVQrOF}gYm|DoE~QSh6yrn}8(Ek6jy(m@EO3!b*qy0D>>Y#x&m+9qQf#9 z9P2OX`(q66u$7zj-HZc(HM>M)p#Z^FEogQ?&%x;uJ$87NH;tyogN=wNw8dxX7q60H zh4NeLAQ;6W9gFJ;RG3s|Lk4s+lIi=L&CZO!%fi8L+HOOyv^$|Wnu%YNbVMA{G)Z|i zOD<~(uH4IMjar;|91c+Z;2amETqr$y8$F+~U2cD@NXO>IKR@{ZQ3NwM$tra9RNMAa z287k2B*!_wieg-kh@>RJ80GZxNpx&H--tJ*H1iL zgfm0a-LR4~=R5lWaaAfWZ=9j4U6-39MR=K4Cwn(j`E=b+(wq_CAk6_Vy~#z%$p-0p z<)RKWhX>yxkLzwYJmxXCW6B6E*;X;cT%qbuiB{3ieb7_ByM2$1P)xyekX(~xtalSM zcR|J|f_ccl;l&F}ulu(P+RTMe0KmB2_vxRnEG%3`7yg72mE$443t zQ|egGjP(}+qQQ+68nj^%=f$`0ySv)nfoP6~JX9MA##-eXDM^N7jZ~UYMG<`AfkCbd z*ipyV&|5sMmIa%0T~xf^I-xo={2ragqTm6+!q^`S7b;WIhxz*#6tITwHTeS?MPN4= z350CeM{x=<7Yx)13$rp3eGt(~csSL#CTb89Gmt^R#6z`+z}PVO+$z!I5BL*uVn>5D zDH^Xq7_x2dl@5Zf^68%kkf%4kAwP(x(_^pcn9^4cWU;iM+^p{;*mZcM&Edzo1CFuk z3L8aYnTCIDsP^}#nR2VgU7-ce{d;?aY4UhN=nAkn`pbWSv;C&{S@&YP8GP!}jHTHP zZvW+fn{snw;_kgrTxc(AD1-6t{%R1>@eNZiGz%=ieTfl8c7N;Sq>($5Fp#hip|gwe zrcX{2z}vsoW&G~nK6Pe^@k%V0OrcQ6ehb1HavZbNJe2@T7J`E2Mg23daHGoVCRa-N zFNGYYV0u0z>bt_rScnC-u@k*7Z|seP76*R>@SMw|fX|=}@*Y6pa%7j0%^h6AtsR3U zKf?-7gCL=RC1$Vvn}L+n zHqa{A6pp}n862uVk;JwB!)An5@wy)>4JLD1&^f^^2oLhlE>Zi!YRfFL+&*T^(@#&cG>6=9{?FVrQSdIseuU_HRm zcNUeT^3@y(N<+|?Qr~5s8J9S12p}NnI;J~}L*8O{dFCDusM_tPS}eG=GfLC$y0rGd z{Wy$dL{_qM6J#Q!H2qG@j;K>++H9B1ag-!Jms!2wl!drF?y2k!e53jYXYOwQC_#3| zl+of{XOCS19_0MpVvlSZSVdda;FHDI4j#_eU(JD4h6Y)V*uDAJ!I3gO^r1)t$MOWb zS6QBVfRa_6MX(#m+b*k-y#O76nAW9-AtA1+V$4?9hm4(rk<-NtmQh>-)TTyD6XXu1 z@-%2-iHeh5|A5L#rwbL!4H@7B4bt(A98l#f7iM2Ir!59)8o1gXRX?$TMI~lx>4*^X zwv2r-MAB2jpaG4xt%!_Zjj~@?XvIh|OvuJ?hd)5*QzS(C3k4S$xD30-3JuaM+O2w* zk!S#3Mp0I%_zoRQOPgj0B;3UfDsY<4F;l&P8Uk@@L(B6el`fBiQ7|{Jk&xqn1jGfObGb~z^ok)sDImjw!?VwAyrCWf$6>`;wU>|DwB&Oxja(`FxK2Z|f zm{%do6jzaSj#7IH_{pYyGi}{{)yxo!BafVMXkh9FQ%}tQ^+7h@cZ{7%iG@59#&kwj zm&c>Fgpi@8@D-cwFId-Hu&y6cy5A7GU$l_MA!=gP-^q{2Xe_Zn%OX6kQpBE#R6al4 zOWg7n;29-9GDdHLddC?{W4NS_A9(lx+e#_iw#Zg(EFi54sC?t=`=@46@O8bS&{LDFuFUa2a;%iwm=&z{Mue1ZxLn=V5gQ28Sfk9o6)Y>WMR22!V}sTC z_LTa3ua+VX8RqbTQRDLV>OYvJa&`SDmrKDJ%B6q;kU?*bi2By0j;53RyI82JML@DD z_q))8+{Ja-w;jqr)}nJ}*?NbaIlSJUeb{`qCR93IuWZ7Hy;hq_%@vFzvkUpc7f&mK|8cMCm!3c8x5!ivsVIV7 z@>nh>1D9TL)`Gy3<9u_X?ZP(y*1@rHUT8w8oUWhF@MFR$GLitjI%6z;MUVjnKl~CB zn9NhpH9vtN9r*|&dT5TCp{bTXDh11pQc9>$Z9_43SjD&+&V!$$HvhsusCm)+zM?ty zVId+^q9$<{W;y;vmKj^5nLc2QLsoT})oPi6q_aWq2p71*r#DITo$}TJV(t1? zfJ0V1G?H{%Ve28pbd)H}s#7G4@r+~=_#Px!P)rvyOqc&T(4kehiS4KP$L^5}i%m~$l;1g`PbXJj?w7IZwgQ8)yGtMOP+Y@8ep_uXDp) z6fXCG;Rt~p23E_Tm-b?Tr{Uao^WxA29?uG|c6G+u8^=u}HgTT8sto83Pf@6)c~I1& zxP~^YhZ&TOP_)J*)kU;!Fj^@{06d`{0E|8QjBTafPe7eW%&lHK?GYf~DP zxfwB3k`Aje=d)UQNnLJz69pl|F=p}Ug#6OKGD_;_FqmA^Nv8b+V9lXefG4jW*s8|H zs>!|+ub}$oi2WGzLdVeKTy9K~-0H1|8Nab2@7m-7hF!^j@2j9ON*}Ge5 z0+5pXJW&orf$c30evyGTa^4<&^ex18<>uS)&In-8Axns?>E17{JA}FOh#ln0E2-0S zfe$|~un{a$l?b$z1*$!^aRX0gW|pNYP)4NfJ;*mpBr3AoN5^+>MmW_l0nrZ^cId!i zpix5fnMLw&!1dh%sFrIt#|q%M!Tsp(=0pf$57GcTC+tP=zb9y zYBUZjFFh5TBW#)LvJJke`$PZtU$^!Nxu0=XpP7a0E2O51*G-_}xnxs0*^S+FF9KE! zZ{`z%pN-E4kCL-F=)YJ31?!abQ0#;;f#P{OQE-v6D6JhVch()kpC06X>v(}|6-s`# z%`W5qsQbjng|_Yr$-)px%!dPv$ut~vw%yr;7Am^rYyVkwYvl_NV|eX7ARoPd?3$ zb7_N?2j=}`LuCFWX($FSUG2nOOdhwHq$l~*3*U~Q#SY4Tbtf_)(Z(%yQb|!O2m4Vf z?eU^kiuhdY%*I_ICLcc~9A)ebh|Mv=PGsN_^I0-`gnGlTKe-G(H(|_h4B|$LzgEJj;Ceu3Lt@2f6suI_%V6(c@ zK-JDPC^o-!Kd%fL(tJbU2Ow&oi_i0579a^S#Ao-vAIlJdPgey-CU0rc?)3!FIBTIz zMJNu@C@CS?7oaAZV(01@U(-8%_@FLjsHiRv_WDQk-*9IZ)xt(*L+gW4(< zZ3~0(i+UTtrR?&aL$sp_*D<*K zg2pCMZlS0!W*1CCA%i7_a1#x_5g@lzn1?}LsVZHJ6K6B^cUIe;Cod z%|m?tbxULyQCx8z@9K!_qYp#nbT>xUL?lMm#YDW@z%q24zk!W-4bf{nC#$@OY6aT9 zu69}G1f+#OBk@JwAb#cI^PWf0td_fzv2TI5u9VfkDQdLv9xE2hs8?wz1e+RRVwl3E zRdi5fb5L{axG8?-9aLw`E?#&_6;o$aPp;pAo6=I2zsXjll5O=xNG-Nb=d{W#pTTUGHZzEzfj_U5@B?KzlZ1Ssw%)gTcZ0Vm2TgK}2`#DVh&p$iFL_N~4u6LvPE zfXg2P>LEsg@V(r4xJ#xgj1}g~P9}7R`vmzH#0?jy++G0_?goJ%Q_F6D`e2gk;aldm zyq&^8o2WkU(pT3`tLM5Y8qacebhGVRjLaUK|C*(A;xzAc5r@W0J=IS(b!?ou)vY`; z19p`Z*~8ROpqhtQfiU0szU_xGhn%N-E-F{Ti;c2X4SfC4$0AIEWz6Y8Qws07W2YS1 zudE>Dg+>pb9W#H)rpU$6#mc6MLWdQKQJGP zr_>6$w!3=&0o601L_GG>^2!Q_nfhutM+d7+eZ5;rAh+25Eks)>+ zt`3xPr|`ueo=0s;4if$D8?~^Moa^yu`W)my91#Eff&ThO4Y=_rm-=DCe+P4V2`uu{ z2C%H=9eC9qjjBWCNFj{^`k8C4lEtE?FGxhQf53YzWt4vHuA@H8J4j zcaXL5&l54aj++}yg@fH&|D+1FW8eu=A8j2%+Xn{=1=Z%P`TGMTn><(g+c%c)!sj4@ z(%NUm9Lo{4+nF`M*a_15oR4n2F)Rx12k0ULWwu^5&8peDlXTE(-W;1cvVIzA0lUty zB#CEyI=R5N2QWO77-ieG*=L@li@Y2fRjY0@0`}}ykEppc4(RqWnPPhk|YiKEWIS5kJu4n=+O34qLn`rMW%sBQwT1O${ z-;ApVE|>USB-Ripnj#7e#6Y68s{gqX#iR-Aj{wz0N017h@Yh}+x|tG=(2g4Y>I%Ia z6d=X$IeVsaheQC-Y5(qrBD1_95EO*uD|_h-Q0o+h_n3}bt*Pr27w4;(HM<54DQPY| zvzolS60k+u1z_sK?v{x#zS)ozI=-(rVIO0HS_SO5Pi-@oT@(_qL~iB}5JkNVR_)`*xVOc5RbWR5t;Q2}qU$Z*%YoOCc!n^2buVLTLx z5ur&~rx6vNr`jGuukG($v}x!?f4}9#*?}wKosw&@raQo-GeLz!J}jyv_k7l}{19*h zdB|iw(6vR`a-G=41@b!Y@w%=5{bZeF$OpkQ#f1I(9Ov{S(GVjx0-*>g9-3pj`yI?= zE-}JR2v!+IdT`M8JFixk?0kG^(NlLz)|{W*tUF_#-g3F(#2j>MTWVK6pyPu62-I^U zc>9nvyUtVZ;sZ)yQ)K`g_3^8SK*O~!pa|WXenE&s{M>j0kV{(=P=Ir?HwUl{Z)_oC z*SqfADF1(=!`FfWP&h_q$*44grIVvfmNvc?%u*-da!>!adidoyX0~d{nhw#n+GNQVTF#c$%Mt|^Sm-7tsn1x^6Xs63@_q?tHmAp4Fy6NJd_Um z2-Zblbnp`_&mF_jhNiw%h~CQ&6ZoI{ED(-N{IS^aa#_2($NQm695GWm{LT)u2SEvE zrMp^Uf?G=rIfDAa-nMQ6s&Y zdjITZdhomkm7Td1QYlyvcDbt%KQ3Ik7aBk}$;4O;Q|#MBsQM->y^F7gu5Q<3-URXs z%LKmt*9Z__wYsXI5UuCF5zge{*pFg;iA>3S0vhzL3L3Np-~SN`YS5GU_O1%D*459U zfRU94as)O6TwLHA^>RsPMFl$(WW5sMkLkiGG$x%jPsshA+Q|hzp@)bNNv>d$jxH zO|^+$Y8%sU{@c!fDou5U&gYSgr`GSW(ZRtjg*0D7{H12za*MAUHc!y#ZvZ{I_p0Ey zga;9oHvuI%X*P94*>-ya;ysPdxk!o`cD@)YQ!FRGo``dv={VyY~7$Yc1mkCQM0<>?pxhMgxuSFs!h94;(6H zl6eqau}hWszsxyEB3-L$?Q&)0kIDM|1RlVDfv<7PY8|P=uW?U9vqBCA&9_)n5I`*Q zJ~5a}2W_?(497}Y>Huv`B;b`3oyQM0BAHgqzxQ|eQ|BwMD+kqBBG~CnubwsftyoM1@P-J?mzH=?EzMJb4{!FP+6RJ zC~rXE%)SykS5^XtN_3hH9U0HhBMKbbvJ|9(VWOq|AYlwO zfu`GzfhTkyN`;xYPwHUC+pK??q`nD*Nn{RiA7bE9Xyr(%CyOtE9@E@&2=jsa?M~d0 zP(kjo8;dj6(j!{$e-`4R4e~08P17I&q`>;{C`;WQ!jZAEnzryuoqsD*&I^y&{L#zZ zgKm!b(pKq%6Ab*ZovMTySo&o?&mZ@8Q+-3aZ6LJQW~lsEoc}g^GsLK*RiFv{&WDqZ zl*H^$+mv1Bm%|zLe&RVy{N}GaKY( zgHfZ&?`Hu`e#OK246o5}Goypdh$L%p$So9?qLSujR0P1@=3PCNcAIv#uZag{Hc9j` zxNtZ~Y=s0ODjk2_g-I3w&>_Asg;8!9S;XmQ*}=%1 z-ki#Rbz;B@@=}NM@b~!h7qvO?h?zRk!UOcvUZ@}>toN+@laJB|&R#U{nX(_VEKHJl zx!ll9y1lfnGoKmGe4dog-_t@#Yi4~uKj~jgi+p{V1&0Hc8`;D;or(8{?qnx4{JflT zWzfp1^uip}wv*K8DY0C(7g$UD+hjkKzBa`uQNMuK82soi8Bz>iZWR1~7-A|L4BwMXtu zBZ7Lw5(gXl;kb<@8Uo3J)*mk!qT@^ezZ^>DjS9v4N>&0GiX?}^H4fY-V9`VQAYXC>H%MWQbFr;qY(5ZemJD z{?K$0Q+D^lP7?)(pUoF?BD_FYeP6w$Zn_(>8Ex{RHW(gKTmq&P-*kt$U~*R{dw95w44e`^JRppP`Hr4BG#J#^#g@X!RJ4)Yez zZ-5CxB^buxyGR=aRAV+0$1&^~SwB!ONxxwzSyV7ctzHlhk8(!IVw98uGcYP~G(B_5 z%1&0f6=s%Y^`qXBANsLci1!^%x5r-!1_=m<#@E#q%5?GfEg%$PqK^yAnVHx<^-IKY zAQn-;7WFyi2M`E0&5e&_nbgA=jcMqX&YI64udpNUd0Xg%DIlCFBY=;f-|Qn0ch|hc3M&|1@kY zN0cE{D+g0CXtx4g{QkDl87uANfXM%EJ;LQf)84+qKr4_Tl=yAW0;e=;kXf$GsjuH4 zsFKD|kfmkiUFO##tC9@q8na=HI#r{MMSfVRpjm)%u)3SDO17wgshc-m6Sq?OR&LKF z(voR_XxNE@Zw7s1eJc`;Xq-#LqZ&M4cPiDYwYGBoKL|~ChOn=Ze?YCaziPyEzPC{z-CF0xqL>s7l_h$hxla;V zq>9p2;o2f~gb+k}9!KS&s~fPSEthHfsEMP&dHWE>6T1+AARLJ3i5k)LLMC;# z+GL-`qy~lqeT(`Pqq%|31jT1%|=%N5mqH9FQyV)%bPNS9^^;q^V z5ilL*sw9pWyuVbE_PnE6DDbhkfR;@bEpK~^H9oNfR-`6O5fu7CCL$*BUOU1RJt=WI zA^!#=EK84~Aal9h**~qpS9!m!0m8-YtY^FqLDzG+$|@;KGDnKvkVY$Mfi=pg&N?;E zgD}1f)(2zi?>FM#LUM7ZaL#H_NnmIcOq}BEkC3>*tn3yhe+UqydSW1}yAun-VB#sjaLHRKEYSrKlyL_j0SP*G1_TB=R zbv&wy?*5U12=3kDH5rJ0sii8s7#n}}u#M2)0ghgS8WpJt_nLw1d z-0xXZ_H;nf5l>-AS}x`d{Fhsxk7En>)16u)_u?dVyWF?tB>CBYUW$adt-UC6SJ5xCX)y)$5WZ~UNA7Es7(r=;23@vec9=U6u*r#>fE`HK`UaZ7%5CP9W}Va5s|6$0^(#e2}b`B4?s}PV5H* z+PnWMGq+43%7E5>Cwm5z_}M2oZ)j!aJeiv?!e)J(>m$-(L&r=mxcfD?*g z5)RfF1Dv_7s#eC+{CV66CWL`wUe*;wcWAx@Spt!x8JN(nn%@Td1ko2Zd19$(39pm= zbPuDHK%w2~D|8pqHBtcA1~S56s*-N(DU9;lsq1WJ;j!>oZa(=Sth|*RCQ<-@8vyGZ z`4UKI=>Z{MgwkSg>0$3fC3o& zl}sa@17aZToN-0NBLniWX-8k^A0Lv^F9yK=fi3n15JP-YAXzY*_#U?EVvimt47U9N z{`>r50i#JMjH+ex@y_U8^h_Soc`CHLEXV_{KT@MLB6j%53aYNcWkR7z^1*ROK_y%%fIwW>SzAM6wI1JfSsoian zC(MoJ;Grn4yiHWO&vxhB9$}J#`DOTTTH;pWYRouvEem+O&2v|U&tn=W?F?&S7+9A! z&Bm}c(T9>?sQ{O)_UZe!ocaYgljj>I{7)N{xO24?jg2lXE~V@M)?*}hds!Ra^k+5P zKu?CV!vl?wLCQt^xzvQ4;OQ8Er0;@rj!YI~Pr>guwOTXrCqKzcagE4oYkad zP1gd_6|3b?^j0+YWcw9&^93*z#bjI{@fPc}KUQ)0kW(O)##5!iWDnJ(v#$fwv9<Z}l>a&Ebygi_+x=k1<&K4BUN8ZbuTa250$@jXl6 zdDTg&JxpYNgdTL)@d#MlfOkN9BU~Hx?^6#RBb5>ongH_xE~Vm%K=Wy5=&K6NXU%Fy z?2xpFSq06Pp_u63;-x0?yBpI>w&FbuM&Z*H8uCwxxMfNvx)Ze+G_lL7qv<)T!A386n=$zA) z-h+w)SMWpx;kI1*291M4R~>j8(G(tku~myMmC<*3#DyRWd4^ca6)G_9YXq}$jszpp zaw8Xz#XOZ>H=b&eU77alw!hmyWhB8gG70|*C0@q>r5#^Z)CGwGe3Lm%*ww8_M=U=k z0Sh_lA_8hF_LA0sGn@IgHCpZ(sg*jxh+FgK6`9yBKgWo8_G3LCgi|s}a|H5H#^?Vy zms0;N?C-h0>`K>j>=D5a$a(QaPNSd)_UfmlQ3M={rGETOL4A7vSB=b+=;kF_KS?bJ zH=r$#gKgUojSW=mX&wWNauge(v#4p?4<`@_B-j%$IBQJ*xk4W0<1Q{fSnC#v-vOGT zZt$5-SK3r$O-4;{qSuqAQ(y%T0)#4+V?=kbrBN(@;^2=t(SOGBN1j8(Arg06SHdRDj2z2&|x5CQ}7e9Pz^Mi z;g)C3qM0TAd;0oo9A+5wl@eHVwDv1RO!!(r`0zS=I#w51phEzQYn`k)k1M;BI*_hh z&;RJ4{pW?p;qB>iNx3>b(I_#27~D8=AsJpJ4(OpzGY*Bvo}Hh6)IJf~lj~3v0>~0f zI9tqiTHXEwp<`S>sNM*yrqduBr`m4vOv)+StT#K0l#b1k@{3qC7(EKEupT1BCgLhh zfjx|aZU$qtJnuGDLP$M+TO! z@XU#a*z4g9;l3vpGLQ)Z?J2!{gji< zG;1-&qnq7it85m(VAH_F<`?u1>lmRXWK8$_sWw!KFs9=M=y)W5A(YB_QmCHkiqsRv zOgJ}mnP3$vx*LO}hbsd?l8yo+00mrR_aG3QN+&4$vjhK!c2Sw#M*AegLUM47{~6B2 z+kS*KB>On!9T3}PnkEJngPYew*gjg;JZLw*^jOl$+KOytA4y^ilKj^2^YJ|Mq=qH^ z--k_2Gal$6R5RMOa`Cd9ZZS5_pV=ryLGzYFeRF4Kiz#5_I{*I%>XNwfe^3`wN~M-2 zvjghECTye(T)@?ZZr`Z{NBNq{9J|)bkAzig4m0j67)**L>J43RSfO;IDj#+gGh2L& z3i4O)`GQQdpA@64;mg3MlQ&l^^@c)A8lOK{qv=!l+~2fZPEuj5^9VZyUksJ~nk3ubQ`ZU0iX0{DwYBa?kWE!* z@;#{rn?mC%<(+1y8aHs#L+1~4G<_zJ1y% zzM%2$@o%u4b{hh*?1)XfiaMO3u$nb5j{SG>2Sq4MXi3jGqMhL7i|(Y@C!BW$F+JJ8 zdF6O^7kw7(K3_rO?0GCxKS>>oUdt;oIpJBAjmGWr3jhfEtc_3)2eTytt}sF+pHHvH{nwpy~|F)&MK>2-7m% zik7W)9#M?y7S#X1L_M)g_Y>bOZ03ic>XxqXO6LsJ3!<+PX2vr80}w`Gc?vroDpsz5 z)0Oe`WtF<=<_=m#UOp{dnbJGrX|~Q-BsZkEx${27_rsK1$Tq75J@h0TO73QGMd?SW z0S&1tQ6NEuVRP?onUit>NJIAmR@HRol${73iJo-%<974Y`ib_h?WCuG#stYH6>_p_ zKZ+9gG2A|>Y$Tz4?_(Pj;cFDgVEb3KuTEy&Bh&&P8wE9KQ7};8rVm6sbSUVnCWWKCu=EVIyjw9j>pHi z1t={&$`Yj<<~=S>F@VL)R&I95XNl;7dd=dod|#_nje9`dx6_rtA1k`2X4r?1>8u5X zSgs5b2wnO~t0_hh_i9FOEL+l?Gc2{3{M^ZvP!@Pk@Mgrepf^0ZBlkzJFHtSyZ?>rq z570QzW6p^*9>M9?CYOs=uv}0&nulHtXWDNJoBgC|5)VyGThKsM#nJmq`cZ3qdwDh~ z)W5SgbdM$?_q@XGkG>0ncs=4%9}EMIssxN(a;LvpU7DtRjPU;>pJqs63+q7Mtu*A5 zhNFgCy8z=4>6wx$QPMMJqFo1-N_0Pga_{3f6Zh?bDq``?CI>nglqGbEmJY)OD!Nvm z$Nw00Pm-H&!ewE)R6KdH9YJYaty*%#=0QH%)>TNLG%X2!GwVBzBm0~LLelx#rv+eI zpM2r{Nts>Qt;I7vb_4^26K+O$lpYUW>IVmZRx3HAa85KbN{B#g95QqA2}_&+IZ>xz z(m2Fcj&A>E4ljw(XfVv{^tvX%4n>g{yncdqOKArnOZJRkLhH^ISZZhRK;)bm_u;HN zC@-m|*Boy?WVj)O9u1a)qVbW>!9GRsuKEWR8e_=xn09m#O5n8`4oO84I6AZY;bi2KIu2V3GhthGx&}t!X*+Qtb7Su_Cm?dP2CCx z2r3>Y%ocW$r9pK&`hyNhxuE-H^Z&USxnP(Tz!=w=yGoiCcv)nLTD zsN8*Oj6kg@YfIPCz|vX*Cs#VHB8-)v6BwjRLcI%3S8_Tn-OjDDHa)H1Ej7>-wiJq- zQ~1XAPla{bb>p`s$C42m_d9?2aj6<3L)JB|%u|}UL|yAZyJ2vQRaA%-RHy2E9wvC8 zI!6|Cpr2=tj87t$%^B=L$`}5AwqmJ@ZB#eF{PuDU@E|QV&YQ>rFaHCyyh$5Z&Nuon4Soht5@V&_M>8afSc#eO)&G0w*Ntt z)W*YjG#i||Hd@vIdE=5O$E!GPnEvTdLpVO`w%w63<@O*4us4610LWN^YTPv|>WV$y z*_urYKncljldc;uZ!nU266%0etwwtfop#;;nL+)ZLN-ph`8bDMf|GqfCur0)#{3*1JdShF#=mD3`qc{i6Vyn z`OL1!lUbSzCpOY$D;kt;Z7VlM`uCLEzeU3H_?li5RyQ_%8OD-m-Trx-Um$X-@XO-? zfBwcNW4;Y{UWGvG4c4_Fk9l5^JwX(n>v;<#X>UrXP~<_ojp&Ds)VrmtgvoCx>Po{* zP!2cN3IzKWa{s~%C#^s3!0eWH>+M?yoq5BsMb7Warg88 zb^ax`?_e>3;-gR6MU`K=`_p&e)qsjeqlmKwrW?i>?!gx|a z@-E=BtfJ|>4oa@DDO>KKwZ8KuCxo?b)=;7!dWYrI#tqp^b-b604R z%T5s`@R~ z|BcMcH*yU-PqQ1Z-aW?u^k_kA-7i%5&X_nK*G?=XiR%z1g!Qz@UZWevUoPXN8< z+Vi=c(6#m#_A!tL6}-=NXlwZuL$`CoE98D$$HahMfex%Elm-gw?I@3jyn*LlqJ3kI zC>pq2GGVcag};#EjQ~?2h_|L?86eX)r@0#@o&kVtqjF;9wADKifFV*zD%b8duVH!( ztU%qwZm6FcC5mr8NyV^{N$^zN<@;y7t)s-($MJ|~ckpfGDQaxUF9t7OK3yjNB8zBL zP%dfu;0V^-oRVGD{|8&Sq5oM?OQbW3{{Vym@12gjHxV8LLHhnjk{E-s;w%~cG!d;( z-!Pi(l>c%XD7{9Ev2I9TB@FdQi<|rfZ*>3I3JPopSHkGk`K|e~Z^9?^t6dYN;0m8O zSkma1zv~iHcKcV0!C6J@d)u+j)W)=Rl&1wutZJ7d&y4X%yMM!hH}&cs$Hy2vs}8WY zX^pPYL`N)~q8R+G^X%gb%YrmtsJ$K5@PpaDc;s$)Xvt<-9D0v(19n%sY$*ed8E_?g z7CL-Jr7R~nD!|ZClGjDC>h+f%aW%O753G@^mGC(hIPY2W>A&^Y{+Z*aZ8>v5dk&f2 zeP)3(Ih{0an!i#ktKPOY`y__%^({~%zj9waVv;^7L$3T+!6Eyo7yHcn$&kHqo~ZP=XF6hVMC~j2Z7Y-Xqb>qIWs&=q8KO5GDaquQ;P;HO(n&XUpI1vU99RgNr611 zG@&K|W=r+q80YTZC2pnls3ms03zekj-`dx^r5sf|8ewWr`5_??YmOi09s9y>5FOiO z!`21X!_+o9IzU-sIp$ULN04{^u}}brEXO-?S_bHgv@eJ&B8@i&r$fq+1;;K=hR;d) zhomVwf#CxQ{l2uumTJ`|5oRK=ouD0e#OGkOZ>>3+IB?BaV{I5vYS?}2N6RTqSw^qxRVuJ;|J z8G`Oam4hraDJdbzaWiW%q(DJ92CS`S`WA;M>c9dU3XQ`|>?TyefA8I5+->HJD1xzD zQcc350e_oS3dym-_q)%huxtyj{`1ATw)0}pGbmUw(#D1-@mgV=uG;s)tWlFNeiVy4 z>A{;(lh%nMBx04IDK&hI>t?+hJVrv{PrO-|*~iij8eP7S=WzVjAcYfppIJf!);z@RQ*|LYxS*)DjDQ7L2>qFO)^dnpc#%#Wv%YS}uMvBhtPOJ%5p>z){)A?x-p zm?dGZhjXWnf4+x7MT^3jp|yyVRa>{xlph;xKaSi12wGH7z&@P@fgJ2|@S~X52ohD| z%uw))925(|OEFE`vDQ~dj}=9j(Ld*QcV6kW3}16Rt3Kv%dl_wa%83XUN^-1}lqdtS zHd>`bj)Y4RNpn+eu(Gl5bgxf40Ka2&Pm4bLuXm4wBU_U6Ghn~os&XSjeyR)P(@ zlk$>sVQ$RHv+|L>>D!Ors#Vv-s$~ysp@!80{fUh!ixMK{7>h@+=Io{3*xu@Bym#qB zwm`1O9Np5)uusKH8zmZ6kj9Rdl-V`V_Fia&b}#_iB9C^qZpI>mGDge6{#%82ydqh7 z_nO#`Nb4^T{XU<27S#CtZk;JwD3mP{qX1pv8>^(Z`%Nt)WYDdYE;`I*@=tFdYt4t8 zZ1>zCcwDxk_vH$%jXFI-9nutXehFsj(=<^&^j?TFFfCc}iq&`_pkwls@L#j0DdvS|k`pa^%+a~E$WhMy*aOfuq*1EOTujSbpXmtrp3#&xg#Z^od zK~VfTm61f8q$c|U=TP5|L>24$zBIygK%JM9n=w`prJpzqif#3TJE4RzE$fI-hF~>n z7}%gyPg9Wra<3n0_(C*4$1nXE_Y!Rl<`rH^v(%-6#bpR-KxA9GdG1 z{zyMUNo}W&6(!`j8ZlN@H>FN|Fq@gtuOpmO;Uv+^HrR#=1zV z;AO9G#<{&?Fhmi1T_nE0af!x3(N#TFR7p{iNQ6wD?>Yq3o7Zc`2i2t6XAb&Fq(l|Pib`=}_DCwXq)2if z8x=uIgW3gvt}J-vV(yEo<*vw~CCg}%E?R-x*hc_Hk3Te3lh+)h)g=zFYzFI%+1Yk4 zb=hX}*k@Ft&UVO*LHv3{1%Q6R;N|oZMXiaGNc06cM=)%-wvy;})$}G7ynb8sS#B4= zodKB*oy0h57!UH0s>s|<9Em50gVH1O%KbfC9nK! zAYQZrtUg0Fcwf~`thN^|6zmsOIm*|^JAXEAK*bZIm{2KHJ;!bY3kSp5Ewc?Ax!|J! zErAnoY_RFaJ)qz2TzO1WYR3=QqvCMu&Ko$-pgY$ zP3ix~kDqpkiaN6<^*q?Nt@{tK2r3}70=6T#MAYLU0)0&)mJdprSmGr^3--~;gS}L{ zNu?kF!q_z(rW0$y*9}_XyH$8D+d(ZwZ>b2FPjAYgUgW_bE+Pjvz+%5O@|MW*bX5%It(_$2ev2P2_fU<>NyLYn;!9sm_$ zrzK?wSLp47?GttZS(oHFq!)b84Z#KqCQ~ZGCiquYhxs$Q6XoR;4FZJ3EF1z!sL68! z?yked*8sx@{|*m}UntK?bK%1+y7XS8D$MFPdh{%!j!KU67!-XQyIcx+GMiOi)SNTL zQS}!QdWpt`7t*-)SJfLjV!zW)1B^7a&Q1F)(m^$_23!>Ak-R?n=vvMTSdoE?WS0k3 z!N_3?w;F0t-7JELMM-CCB{ z;g|~RA-;yb6-`lok>Lk`9Q3@mV`iASgTbCrUW=tfNo1C&<>N3}Ds})1_2ldTMks|0 zv>?&rh$Ab^%Y~UZ!Q78P{s!P5xS$0oBbV-5Qi6YEQJ@OgBEhIVBvA93M2V)7R-ECf zB+4YziTi&S61NFH9UwRWO6?N#{`;22M2h8cuV|=C0|C+PFMWt>V#iN-A=ukx07aWF z>QKW(0dYm#Agb<}V%4yHezKlqfyE_F5qD?{T~a7qYVKhiHZ};_?>_NvGLnv6ADk4& zoq1Fka9#Zj0mfZjlbx@AGyTvjFui94i{p$$q#l_9d+j>6lJOiRq3S1j z7@vMVZZdpzkQzxCT>hk@*yj!;>SkrQwSmJTMeNsMB_nV)q;Nx|EXqcVcr`yy__WMq^qQkMtw58vz z|&eY&%|9#LL#b=Y-!HlAlo}3LVX)&<$RJ?c>_W>UDR}!rUoSzVJUzNnGqXU$BxkaG%WQ#oX+{g4`F8(NO8l_YbCBYKZ~xyez1uwdb>&x7;KU z-~D3hU7VwoL#!@mNV^C<)VqoVAKg!4XGi|#8*-xJPs{OG!1HFuK+fVYvS-;>e5Vr9 zL(uV*!gUj7y8xM5ItXKptVh&S)zpGYm{d=1Q zRsO_Kl)D85cgRpcCGOn1CMXl_tGl>G7O@ogjy(TRC%oSu$dNt#z%2;yJ3!b%2C$T=w1($VFy+nvc)uv_1tadrRLa#SU+kn8P+j7tJP^ezSerCb&oG0vWYp@L3 zyR-DdB$a{O#G97{a@8C1t6ue}x_(bd<4`IV5U<}#)BXa_d63O2`gyTmtJ$Sv0iGzV z>eHa+*#;$eK55Z_QVYKKlJ|-UQB9t|-y>-42&9^Exj`=r@aG?C!4;x8SZu}bR4ALw z)gol|UY$VV>-PJjyY=;8`xP~HDxddJPaT(xKD3-FK9;FwD_%5tETf{o2fc@UH^h*Yh-|}d?eKJUje$t}y z1&&{Y$s~e0ZOsgQ3avDTc5Ns^ZzT=VPRI&$KY8M;+kM?jUi=iyG zX?hxDZ0F zEt!zp1&g|_IzhmCwJbfCnb%Z z6Q%r!NABR}%Xf?MJA4L^67KjVAx*a56((oqo;>A|*tioWgi0>O*Ps{~w9ycj(i>jT zy*^V_OV5eCyzbNj)2h>*?AT`>t5Hr99!t95LvWQK#EG7gT8&!xz9^5RN^;9=2s@*L ze{Uh{0YYA;K3HiFcMCBXn3AheX*mJkfEQkEHY2qDlNxlt z)|V#EL#_xNXu0!bP}yh8>13`|JzevfO-P{kFv@1^YCo5~JD8_wyWWWgQ-7^W6cFNt zk(R^c#B5ME?x}%mQetx@yU*fzbe5Qj!8h_C zuJwdaj@i2J#w)PKXC2+<=-5ms3V5XPMT!Uij_0p_!_4-)<(yYvYAHIoSd~|D7x*Ep zGXybG7N)U9RNWnv;1`cl8~FoU-X^nQ-{>UGF`dBloYdD^$TDM*xJNk|Zx(vhyt}Q> zTK9dq_5%&r|H8-!!rvDK5>ZLeSbGHDzW7(2OQ%{1YF18t;Aq?GwzwAy5@;P%W;o}K zaN^aB$9GYOko)jQ?h~^f&=?hj!Wg|<*#*9XVix`$tN*iMXQuy2=e~pc$Ff(OLxI}% z(xBmr@;#ugxfW~Yg)VOs8nq6?eXfazFKUsQMPJ>N$eZh{waCR{wjR0b2q&`T6Nv;d zf7|WZvW(JirAOoZW9n0p3;6G*`qzlA!EsMH{J>2$)0-CSd-JaDk^3Ly`%rdg`AzFZ z`_&)Pe%)8;T1!(~6~ME$OSmd^w&#KO5Br`T+SHtkcjNw}&+E4%ElIO$wPBY#?u+yj zoxC~x*~Pp}L0!|J`1n|_=T(X9m{+sy16i-bQ=C)}DvEdeibe~ep^ceb5$8W3hpcx!2@ zxtQDp`HZzoP^>lAZ|JJjuShzM-_~s2^o#*HPy~oi;3QM;GJ9+yLjr|t>DI)KdIUya zAt=W<*x6i=`p|L;qrlKe<=2)2WwYrxmFeTLB*chegA$s`veF}(Ka^y0uqFiqH9sR$ z9_TomQ4D!;z?Fi6MXF(8AUEph-wd)NjqPPl>#%a=>7caNUO$Jbs;EmpkPI)JT;h;F zBR+%}CuWo8<5~{*^|?833ATSZXLCb03b(i8p2_L_sZZoQ<^^7wVz-z2U=1$PA0(wA z*Df+kg7BU6owzj$i}oKm7vV0+JXN=iRTzr=xVN|eibJiUKS=I(2OS3^h2Z&@Cw0gg zQwwfv7>qWH>mPp0Q-VXPfCoOZFcPBh6Vbo0X^$oiPPhXa+ffnn$v%sOCVei_fdSs65(1ur1&VV>&<-fm$`VHIbYPu5bY5Y13ngB@AvMq*@Wn2uaY3 zbmqy{v_nPVRp&3GTp|Os4Y-+wuE$AP7G6{1jHN!ZGa2xtIE%`WUnR)@PhfkzS+c#3943D}AsNc)ir#`3M+`Zg?htt_Cv2`tK{T}v zp7L~8nBzt{nMdRPq=P0~J#C((F9jT4Aeu4CndDpw!2y%$T$xvmos<&a8az#BeqNzB zg;Kzo<^fn~jgLNo9ziVwWePP*UW|_#gceLNE^=vuGg9%wIL(-3A&>!Fxm&bu;GYo} zfOco-iK-oX#-kX5Ki#9q!rQHA*B8=Sf%z9MyjQrWi{3^8p@vGRo5ii=yFj0|;_ZJy zDBY&;h+(tS5)UGrn)T6O`qms1F|5)PEZS4hnyVXcJp+(syBIk8(5987qd zXOM|vAu_EeQJAfx-}0m}j0JRcT@zgyCpE8UxnyExj5|Yu_`Lb<)?#gKMZ5`09nip6My?%*&p zvm8nFei*NIy&gPxyC%aVhZ@Hiqq3ZS6%1~2Lc4R%uSn%~OhDCLyPLwK4hej!pB%#w zC=LXxbONUOOggeHlRdw9eDON~_0F>?=%&`?E*I($ro+`8P=attvdmKd7fkb$)t*v6_H+k1jU3%lLhTLUhB zM8~MM$y=X=3`Pb@e%+oFGXtz0BCDE@Itigg`#f|<#(-ve2d6$boY)DvEX9VtBI%Ud zx7#D#KR^l9%Jj)$HHiaBFRNc_T0E#p6Od(FmgTPPv{}xiJ74L&$k)r zI*)%+UX||``5g!Pl*en``p6l!f50BG-NXglz}i{R?1vk@3R_6EJZ2{PGq+(`v1la= zq6FbzLa$%uHzO1>pWpeK7WbumEhf^E?vOjFo?E?IXJcsurUt($VjHszIcq;ju935T z0l}hTmX7A*p~F}ixM{K(7|xo@XYc4_McLA@P-}*jb9i5^S`at>JWeN zbhk>dm++iT{$?)5kD%#BTxZM!^?cfYy*{x`G_kQ#h)DWik&h-D&35QI?=hMoJOzAg z`zh~trLRDOC}or@w3%}zuCrzT480KF+5cExIkS?mFxf6OTa;UGiV&pk_NsoT%W#8I zvZUw9fQzgqRECiCF5TMBwLB0+e>ktM*w8q;qM^IMJU!nXXP(YFM+}Yzk`YQU=-~7% zQgqUlU)hcE|=%zJ~OhYiD9ZpP!C5}J~Z0|ip_%G;)NVLS7 zmZ&4JgGUZ9cZSzb%;T8U1)^V*(1=$1ufaPy`6EMT5w{-f6Cy~w2o@_wsNr_(L;MYo zI+ECmSDa{sK&H-&1RMk5S+sZHnk;l(et z&zIh7xXCmi;)c_ZPUe4k5x#Po60^7nLlUM0p)0;!A8+3VyDKXYBv4kVF&zL6x>QoG z07#!L0?Xg&ml)&9lnsz2iLh?xbGWTf5|F{_-2jT{22XO0Q{|S1Mz^NRb zAviNC6Jb$M;6%b)pMHN_EijPA>C9&?Z{`obe_^K zzE00dpaxYeh=vAw0e4FX9hrn6bh{iiy!7*WbO>r{{sJx*?|cao3OP7Cs~MP*NlLTN_d75UvV$9sH_a+0ry5f zbEkNYI*X=?R+wOz+(Bq|+P$DKgxZSan3%w24B*CKX9E2~5oaf`+c_xG+~>yLCQ5`! z_D+l|v7#VYDbafyJ~S*_?k=VM>qwlL9D5deS9+YI_7MO)YT-O4_?w6mE z0u_HvlTPTEO(&q^$jH7m08*Elkg{29r7DW7ZV%Q+lTEai)@?r{Hr0)v3IR90(3Io# z=2jV2CCk*#XJhXfHC6YZ+H+*WaAi0e$ZqehyAzo9WLnm# z@Y%O{-BO6Rve6Z~9Ymww6v{#tF9j&=?ti8x_?@j$r5(k1bPU3J7(n8K|stZ+R$T+SUT%CMK=lL8PrTwzd(*AbA@OWPg_a;t$r&Po zJNAM8{SfHi#V~`r1PTsU-Vq;@bw_0yCdvQ94E9(ZiV@CSw7BHCz3alqBX7TFttt6} zm2ICs`Wk;pb+(3sBr2a1lUJkpwwogMm1t0b#|i+ju?K-ncoEnT^N6)9zKxR6UR0no z-Voin=a%GaOp$ZV?i|#I)evAU|21zerM4Usqbce&Y0o^2%Ep3{2n%hopjVCji=@ax zO_k2F+Yn}PGdE#>`6sAufAy!jdT{-2&?DUxJxqV|<2>1z;$-}|bTf-bvFF{Ne>suC zX*!H|F|j)gL1-VBZx+Pn>un?2cM&Bgez|h9@Wsh|^nMhk1G6C9C~f0|FiGqNY!m7C z7mlZMEm(R=p3dOZnR9nO+B9%DR`JI1IFH}1ucy&v1IDh|P3QBd0Cv3%v726G@4zE} z5EXyr9(inrOs4<97mJPJqc4RPB*zj!RAJgcJ7-1xJRK; zBOt7^85*!jw8^z1b!tQE76U!$wCGMMynBBopQ^M^exdKplC5?`&@r7&a=EUJ^<;_OQIp>rbC-ws7!f!{ZlsiFI42l z#=^Jp+4%wz85vyA8O-buwx!|nkYih}lkf{@V-@^=?k7EAk z&X#O(0EaF#djWFtWoH9(Kk3gvMCfX3|nvO@P|*?Q~7^5F{Q}o zHJX83No|OYvzE<1tr}SXwJ_K!E<~^&mghhsMePgR+i1VIaHjoW=kSO^8vy5_)!MZ4 z1k$XGFlEh(V*{rzN59G7wDT|>Bp9p*?&Gje&Mp*6<1zz8l0Fav62D*`UW#vzj`o%9 zP4uE9yTo`6WZW}N;1HV#{wjYE!aSgus ziG<6JKhHxjjPb)rM~aDD*Wx5vUg|BcK3xtTpDu;L+LP1M;A#I!FIazl(i<$V4xaR% zJy|2S0KSEWI|?n}WH8LfiK3Zek#XiRf>CF9sMCq8!iRi>Qi2>e^69h3%a2zcF9pjh zYpcQ9>R>tOtwm3Q(`Rd|Px{f|^mOnP$)n3`gzw;)0A-p{5Htc6GZ{rAFFg%T z`zy=A+Ot6zJbUsi3Z8#``SjV^>GGFfJ|3Jx1^Y4=>tI*f;nE^5P_34^l59TT#$Z;N zFo@}cP}ADeXb`S_xfU$1J$)Rk4f>}+_~nzeV6gOT>G9z7@zUe9kj5Kgam@@wTKux8 z`eCn$W#d@d5Vh|KxDjMJ*9%r9wx(x39YI@= z5IpPW**GuOnFn~ihyZxMI1!Cu_};j-(Zbk{3owv^uNs2zfxQU|I?B*=8UmLS;C=8@ zp(}`B=K(xkb}C;dz_zx?h5%s!r0ZpwoJjN5m1q6($8ngZH2+m}=m+ zj6-b7v9Xm3vAy$Z=V%AE*epP2u%|F*m33fyrBN116YR6SE74D4ir?tYZE{drch2xX zDnkcGI4%@mjpx}Kh%W?BBJiRz##u*(eacDIhZKKA9_YzcQ>*-S)v&f0qd{aHm1}en zC$vfmP;82Eei~w=aC8x+6ilbiZ$$x72!dwmNFiQrQAniGZf%$>0s47S=Hq@j&O!c& zIM1Ubx`0^FG9wed5dyD{V!Vo*bNZ_(@#f^$3Kc_`^O59;a@AB`iobg?S-Dy005DS* zI*5NxA#??vImFdws#vgSfiWF+@c`15S%$SSw+KBzmr?XCxq>JpC?+ak1M4t*vK6vC zKy)8OibM!OuyS!JoQ=1;xV0_z;}J5m;Il8|^4oEb)20j9vQ*@Dbn!jev|6oK*%_q9 zk49k5Lqpm)r+}!E0!uM~iqA#2MXCwwUUh$vWAvm%vzq)mx&$+T`bv(k2=r&{uENCk z?%dv${>IQZ_}d?GBza+&t4}|92&7j)T_YM`gxC(tsM*;Z3_vGoEH~A2P!t&Za!7|; zRv*J--=D&l(3mV8gjbf@W7x2`O}gVjerA{r^s3s|Za%u2a*8|LPzYZ@9AprC<_&)= zHLjij9qWl4Wp5(g{iJeUeN2jJP!96AHwK^)d=MsmWsWXoL%QcKAF9j za1B-_(O-4$A6iJ0q}GCZa&q!+T$EWi<)g{~`^^?9G35b=;k^<mC;r9FB+D zYyU0!gXWH$&SIu8+#aaZbur(ty4^V(51X!!D37x|E@AEWuGl?+=cFwt&E-`$bhg*y zn~$$I7UW5~@aLV4kMlowv?~Ol=hb}cANG&2x>e(H`;jw zo*y~wvOnURk2`h)w>L11>84FzsezH7PxeI_o+t_I=eVHkSc{4XJF+9xNmty3EJuhp z0f=_6&r2=9&=%eQN_~Ivbv4)bTD*=f?XW*U#*9m`vKFj86=bO>67~&oc#5LZeAZ!5;JW#6*^0DpZ=Xhc)gK|6N87}iD(Sd;= zN|3+V)-$jsj6Xgt- z;6|fTBMS5|K*E1Hrd&}rJ;&1ej{{N;|-SZ4)P=v6~j)&cyLS<+E8E zImC7V;N0+z7(BBx1PnkMO%A)LGST^Y0DcRqX?2)rRi8}<@9eqvV&V&7`K(0d+A$acR>VYz`6n z6lY6oxNV2;+OPebP<}uF0CEDY3f$zMY%*@&Hf?{bG`zb?E-sR5!&t$8=!sA-@Q(fK zIF9Vyro}gzET`-=K5rrO2y?N`voub9VF_~Zp!CgGf3wEz2(diwGGdNL9mM>rzfBp@ z(>TpWMRha#2JXIV-n)K&pF{A8wh%5YQU8+gOab*W(hf)=eJuudN(@DhDOWcE^)ci-m}Fk%Dpoaw_lo{un^_q zcKe~8J&PA%hFf{X#^Icv2hI(rmr#as=^`YS79C(!h3ykuKNH4cFHIIlPjqKO2uo#B z+U<5PdBVws)iZhP*}qoKWvXHFEc|~e4dA`0)h4%^PLqLJ?Q}ZTh6z`R3OC4lyFule z*EGELDGjgPpy745;Yar$-l*M2_a8QU2^*;W@+WAAOE|$-HFxR*;9<~OU2RoA2T+)t z2Z0wmcW`fhY27|R^)G#q=q?XV*9k{K0Z+Vvl*l6ZUW5T*pV%n^gJ#KS9b|uD@>lNT zxF1c_VKkn=AEA?I@MACG+c>8fZ>lA?LrW<6H^&6iSmI;Sx%9H3lP}obsj}46d9P9F zU=FeUt4-^@?O~o!UE7rVjJv{aFtlc}h3(O+mX5O(1`XbT4aAG^35*#bU^BwTYP-{3 zTT+|sKVsX|l4sEh><(W-8R~ykZUXzHihKG~F{P<2ag1%StH?KXNwKpS%W%mx^2ihS z%gy_gD$~?Mqp~uv8`YmG;fduC1%QlIt`r6m*cFb`V+Og2 zoCG2|IeH7T#@nFxqAan)VtpW@h0byBaUm-`Ahe=Vn{8hBZuyDP;>v%6xw-VV_ICDe z$yE3LR~fX;Sr-ULiIjY28w95F+YGj({-C;nGz>St$MEzP{^pmq&j>mPXh!HJfNXb zWoQ$ABTX%Uy%+M_va&{Q?tFUOM*o_~#|MK7)Ujl+osQB>y@`KdP!%YU>x@oyh9_#? z9}cg0`954(QEuVtRk&tJxfSTX$RC=e4-krG6eu#F4d1X=5}ZI;Mt2e`@7E%Z#cJT<)-s{;|cnNNt$i4 zo@Yp%J6-ckY-RZ(D(Y;Vb9Pv)3qZ>P!n2K-kPnI{uGoLKufRl77A30J`vh4+wdM(v zBeqBECJ1W*Y|`lR&fi}NJIoDvrM&mX{UkBXc__b8H%qF(S#)`kW;gBNZyFF}Bhgiq zWohO{@i?J6D=#iU)4>5d>UESMj)49G0Qr!v_>`OAg%Qz8^fUPcq8%oxLZK$5L&E$w zP1I4vw<>=#q-~&N!W_j2O}J9K@8g`QdFW~!Cu$I%Q20int)nm{l6h2HM-|00AnghS zACkO`bu)^`F@u1r!!(7-32_+-XGJg_W|Y%ww*~`n>L8(!(tQTgK5zz+*AtE6Tr9`D zL1F8Fq3%jOBYRmTq#hGdmR+eQ9);XW3I_J(mjvntFB@G(S&UQiFs zhsLKSI8_@yqe&Eyt*40zDP025=QTkqI{2+k#$3XfCZ)GUdoLhVI!5zxITA}Pkwwd- zq*Q;?7^Fz8GG`UV)V3f%(AN_P;(wkdky>r3 zwa)58!tCMoxsQ@7|1u4;BFa{_k_6#NWKtYvBwX>e0;21IY-(tC8Ax1i&CkI3hPhB9 zO<|XNpIIYF>+^9+VcbX8q~IAxfPg5t!&ZM^8@X*I8kvvT&~HdX?1>Cjjoqy#HFq1l z#g9>vrK1rxr*srf1-JQwEG4@|V}JWo+84w>e2_eo2J@AV6aH7}#lUStu6I`g-*(GxjjWySoi={;NSEl9W5bTYR{$C4mIZ3f0=NJAMwDlw8!ac=q*(mhCezja; zX^G&}eC1ksRFHM-!r;Jd1e57e{YS8Y^hgcTC{LCOgN5%&8>VN{t@<=zlX>12KbHD23!l*p z)rzc+6%uo!OCIRI&ICpD>EBE?er=LI9_Z8@&eiAC91~ODTi^wPhj48<56n8@iqbo; zE{X`?ulr6s$|3iWcFDEZI%{7Aoi+LbC!oK#5G4bz)I((DuCHozVyFT3eg1!pmtV;= zzdt>t^^zT)hRIKlIzJsmS)WWWUTJ<{^LXJY;TM)ESe_YXqrAGF~Z?*Hg z58!I&1|#S&Ie+pfIzwUBn&W>?`gN%)4c9mHHAti(%O;;r8rU)Eg_c(?oL-H56uHEI zY44FI2w-5Tif8B4!rjEv1SyBjrcVRt!&7W{+O&Ge&_xqaedelRQ^Z?krp1=Jh>lOw z^ek_(qAH(Y867BE*r>1N(^BMknyEdF#_sm3?%a&bZOSk-KWxr{0o*K~e6@i|k3eY3`m(+otd#Lw}O3yA_}WWc*yu|q?1_wfDvNgRy^HwqHGCO}YT%SPa_v3NzJ>rs@I7qP?j^c>oX zN6sXIx7+#iMYj9PG#nkKV!k{wv*kqo@uH%5u1-L)XXV0}TIYQ{w?{ZNkF3(8U*SzJ zYHe%mqHyF697TVoDsM97F1qsasi5+EEpizfed?+g1}JH72h50W8?X%NFLJfgau_Rq zQw>s5Tdu{qB_Jlc4TMsRY(T5GU`AmwoYF`VlvPXp90os6S}H2~ZK_YmW5(h}XoO<& zT3+U1B@`UtRMeSI{eCvp$!4s|0M1G8OsZ_>p{4<`>_>kC6(xfpJqd*QWLAT0;fF1Y zgsOUB<1Vh;->tc79&G8=oLwMN8lwqM5d(M@xyfzU;iP0`t10)3ej+8=4p&n!lm}AI zHR3sJSK3gA%JC4OS*iI=#>}fP9s7(HxWl(@zy+IqVbE|&7+9jKm!idL6n@53yH4fz zbTU$f#kzlF?Jte3Yy_uzPpZ#WPX zNScY&Ht`Hcu;psvN5iie7SLkuVRkVCOn@!%(VE1V_|ai7>m_SwYdaku#~P8&yFPL5 zqyT2QcvlThCS}xm$-3>1!u}c2zES{O+&_y7csYO8@s2KdE~ld+2HcjtMJ+F@#)Hni zmU@K$pyy4x(&_M7q#B&ZdCYkKz2v_BcJ^jU2j!L8@<<#<7N}JuINzsQ!~jp6tPVEJ z12l{LNSh$DybRVjijHwCnm(-+4Vb&-*+xIhk#z{MA0x0?1Bh9=Q+dbdIJSsUd!>+< z1Yv)F4C*~Z-$~=_)Y6;lmRaik>iU(ecXz?uDCM46`}jVy!YfzqEPNG|hB;J+iNb|t z^z#Raf2uxa0hRZoB+TOU^L%rb2Q<(uvcVwg$JpmLci7#km3l8;9i6RiLY*L-5?JRU^u8`BeyxC79w9>p5!no)n% z-K!akywE)F#QZ&q-izEL!wWU@J%5tJG%H_ssfN>dfbT)EA7*}{z=~Ga#c33dic?e; z6sad>`a>uT7Ayeo^Z8Bs;Y51wyYlT)qQJ>s!rbn0u7K~v-d$%w0-Lxq{43^?r~sd*8}Qg7w%1># z;9))-WdJn29%eE9A*-v@B`j`V&P~&xYNsIQ{E_0QST8@pw8moxhU63M@+fZ>)hU z)w!n{*yez4m5c5ZN3J38=|VNkR_OllN-se8y#br08i-Uf+}JYoc&d9rt!}%^2BT3- zvm_S+fW-%$A6AGNkuKNX5+giNo+1opjWG-S3-v}mbg%i@3jB5~;IBpk47l;O)c!X9bFkG?+uehfI@o&i6d?m? zlBZdI8c#~a^tGN05n%hXpTIPzEhPk~wZA+Epf`sb3gNu1k9Mb%lPpDKg0Vl$`uP=v zw496*6T(yqiinqBvjP==AdY6|$k@5kWwv6W10U$b4@X!yS&ATMEafqAojK}RZja{2 z)63G@$MRZU<~=|%tfeO40q?VnwNxlpX2{8kwtP{^DEiWxk<4j^C368iRquudQM)r0 zGj22bM(RmKX{X4hqf0eS++N}5XbeK??9z4-UrAb47AJk2prs>!3En}TfB}EE2GiF( z&v`+&YU{Z}Fgm-3b&QxqBGOnRl(2#=%Epw>VpPS+Nfv5M{;1_xU!rh-OtRSz<$D~CNY11uW_WSb z46#%QPD#hS8$huO+=IM}fO$DB-%2QONpEO5$@F?#4C1`>IRI~jjmJnPd#;e4bAqFa z+-qdYOydMLKiwb)8waLY`U>xk0@OqS=Hk}HO2#iVsApH~qKsUN^xeBQ3DhD3_h*gyNtTYi0jI^#OBVSzI@c*BbhXo7gQ>Iqfd0Em z|9wRNU2igr(qt6&#kv@h^F}u;O^%}wkmwDs?W+pd@78&gg+p)w@IR23R}6NdbF~TU zT54OQWXrSw61(OCRR1&X@RQfo~>4cDOzH-QqYR+QVaWO5>f3tiBi zS>e_&@cBiI6Rok>KR3BjKu=b|sKBySzp9UZs@C>vB*p3ey+mFXYPZySv#BT|`xs|) z?Go=Te4~!DC_K}STjy0@-TGCpWoK;oT*0${-zLB|#)x;z*U7HhP_?_Nw=gRU3%cCH z&OMa@d*P%`P>TbF)xLS+3W2T!1EeEe>zisT;|5vE4egYic_HP}X{`~6<8`dClvU@2 z6T_r+9uLU*MoJ>q8|!%Xz;@JGj`PS#`7?Zcq|3f17~Rn&jY@h#jW7Us0|K7c4WJ8u zamF;sWI^b`>n!CpxKfE0DN2T9!Xi9kEk4M|um=<+a*L6R29Z|voI2vqVhTRd$DCuZ zmwW}bo=FrIYMK=BNX1E?4>1c_PKsy}4Mj7om2O+ZVHOS1rJG>96FpMMZV;kE!a|6% zs9#_rDw)4k^mmP-?rK(>s&ktx?zuRB@ko!dNfQ^C1j zL2mH3r=hnxz-%`9gY`G{Z1lG#pEn~A<7lWb%hSWpWtW#m`dAc=>&fMtOpcCKftq$@ zWKo}12Ac8`Y8NH^RABk9WrDXgDKl8tX5L@{je6&-;snH>S(c2b>%d(Z1+;L0uMIP zva<28bFWG5RQe?iRgM~nNgH1vaUQ$pJmDlmb>snJVe*-APF_|L*?hA+!mctw$!+d=KTZb`pyJ7PLz14(j&K|W zWWKYV2LE4auo0M$kCU+9N5ouIy2#IVb@6ih;b2eF-ln6_A{)*KEvjal*M%4D z(y;Tq^3>CT-q`KF#Jn{qh=nfafr?C7{LoY@9JozSuhe&I9hk`-nW9@fhg%~UL}RS5 zNfr}>AHCg?Mf_e^4WohZ7_8`vtNG? zardX0wEdG`b=cU7s7j6znm+8SPVk6cN+96`fySOvQ;;H1@M30FbUMRi2VqX{lP|=d z_MJ{)dEd9I^tM;b80$Q5O!Fv+iy+N{QA+=$d`}FGiJT*V>PZ#}6)J2&WPQ|*-`(y@ zp-#nHWQBi`>RabZCGQ?z;etS=q!~{WSZp0z7+D0IiR9)VdCg;-o%Vx(4GtKsh#eFp z=Lj5BWl<8r?#YG$nYZv5Y|v;G+eo)uZkSx|L7+wvyk1$Fj;W`-iTT1WSK~l$AB+f| zfS~=-GXRrBjFZ7MFTk@CNQQ8cVYZ3tl1zPBNaBCFIEBGb!^^ACdPS4zm@v=Xy*}GB z&2lUT_I)LKVH{4#2#zIRZeb~(>&`Zmg?ms<$IHtbOqlc`QaW*-mT^nPI?clg+b~Pr zF_MOWBFxK1hn9@eZujMiBWPDHcoT3R5G^^5KSbz-xxu&s*hCZ*^&`>J%ce}o?%GLP zDja|OjO1l!fzXj6yowwZNS)Xv15%uyx<*1lG!)ocrxC44kc&BqF2a$-W9Uxh-ZyPqKk`*Hb;oJ(`>k625ZHv z0%+9uPk8@A~C`#R!TXZwf?vfu0jUY^laX8YI^2* z@}@@C-0m9oV6O!Itc@Nx&*7uRd9}s9hvQm*jpMB;bC(>v0vvxFPpN;_nod3R#k7Rne>B(!~3HFTs8N8Jjagir?z84_#b`2bge6)M#xD8p;tiVWV zFhGOeAAvYhOSDea@V`5kR=olse|I)UIA0MD$nOojA#>ixo&4R-B;e&BQZuUBKJVb&tS2E+|4-$=V<(z~ncU<*tNE3IX(?a%IEW_t zo&NiFO`SXXtQGrL9h#5RgZ*uPST$nMZ-^D-jJJM!e;GFDvjKy2`v=@Uqbf6Y;3t1p zUmD3*KI(tEZ{wu8Pe7M)YJUd46fhHXbFc{gczWsQ`uufy+01h2!cJl5n>;!XFe>Kc z1Tx-5DnE@P=v0xqBdG|1^xLeU`FN5`8qh)&{!GLPFZ>9?Tl7t`D=VvZAlc24tI zU>iuxEX$5RVq9+~e*VD+d^X&dY?LzG*ZlP#s3$MBUv+h|Gg{~+-R&0#yMXuj^ksb~ zARUVzsVBFYvXztKOfFf2FdkiAKZQ31FXCl$u;aFgxPIT8MVSekLpkJ5)hh(Goy>8gLrnBGCY}A5SnfmGgcY= ze_<9T(@}^N0d8am>*m^S>#bS`qgG65@es~Od|vJftLwOSc<-B0rWUM?)?)@tEQ{2( z8gy0XHy%fWm?Dr$LPx+B^tC3N*2;w! z-QQU-tYp(E5YRU)JO?M1!3+Z`MJW%qs5pCX#iS?gMHP>mN!q!H~b|uPJl0Q}w}ZPE{(rzIwQ} zzVYDejR#-f>{Nx=!ZAuoRYny4e-YM`Lg_pMp;;GX@*yje`(G}^P*T^H8YA52Lo~Rq-~lWnT^L5HrT(A)QEC2`m8;( z@{u}qt3C6P|3P-Q8}FAnSV-RR099yrOW6}st#UM+idN)c6(U%gfXiLOT*4!!c!F z+n`2)NzmZnS|5oM%8%qoh5qR@ITJjj@H~wNnwum46gVQ8raOcqipN+T(Lg(iwAYN4 z@LPis`5r>AO&cyiUqmrrj8#G2me2nt%ODb<@qpX?Os^X-LHk@aum}kWZ$C|<0!h#|@S9lqu;nS)aT3M@1)roOuuzPM4fvG61wkWd zo8A!C#_}@7rI`5Q2unFoQ;Fx4qHwVx=*3n>Tw^%OQ^W|v9sw~3J094-QwdAR3%33r_@@_U+_thv&?e|E zu79SqbxOS1}V&QYN} z3+j7;V)ETIe-=pGIEo1xH|Zt2ThtvKaUjUDEKyqrd)R0ckQI73864c_(@*@4E{F1Q z-w8SoKHWcHJ`E3i;9YC$M{41=1dd6rJFhL^{_Sqj5;8-v{p#h*-RFlt9qhi`djXVh zN+l=I`s9`PTnoZ}6RQ(QsDH%Hl`Aw>Q9_f8@`f4M16$g^!P;VVqziyW@VW zf0XfTsa=ZEbIWkZq$$8L@6o_5qT`TT6upUDb=R@O5>%eJlgl%=zg?QTKgr~1|Jk?x z4=8fo^o-J42ip3)4f59#QQ$P+++1QK`qI1h$1WK*ym6&pTIxj>gP(2WK1<~{PEg}S zJirx;e=PTmm`JJ^$n@%x9IWd3=j`bY7ennHUEdH%wQDtjmvMfELd-U&PYr4ehf17q zM$^|E;#y|Yfj|tv0x+;uq>WzkeDC@0;hUd!w%&C0{tnK+{JJy1HV^KNgL?x?#~+9N z7hSYgR{@5|FXipMg;LFDaWZ{hYp46~B{^?Nf68jQlVzr^q<2660*ie%WO}yV!lE;s zy#=-Ow*B^Gc>!Y{) z^hRKm)hu;cXM&n`1%;flB}!n`+oh^4qkDa8fTmn!R5$k{?v%jGqi4}TB|yKl;MTL- zfBkMoyOafhF9-e}<=ME;5x-A?s?x6al5hl=LJH{0U!EU^H^XAR|zFhX3f0&YVgR}oz?&^1+f8;yI>Pw-> zQ70fJVCCB7D7c=Oz~Hc#H3WoM5qcy=e^Qk1n(p+#=H=vI9C>;KnlZh1x~O)=<|hoMwEx_`aE26JBGCY6TiYKc-nvp)?2vEY z5sG}40k-2rmcL{tlhJ~aDx|trj;Ic|o1RqrYc?&{^0g+^m47l}l6Mo=90q);f5Tdg z23++kV89QX|O-BQUr5GB z9|C3o7KHY&-BPc*J0^v5+a1L?QI%0Qt5{0ns&Ea#K<$b?fMG!zLGS2qh6D2@*-_UR z9rldT!KrBWsbiBUwV=)Z+i3=Te+{AzG4)L}qFszq%}dG%ESROO`*P2w0y?iG*$Jgd z#^_lJOMxpuWwAmX5FuKMef(1j%il`z`E6vTuYJ?rm0$Gmd-BCojeNl<#f^LnDJNd)rQR!tG%E_s06aXs< z3B^Jyodca;Q90vf{Zxf5f7g}tOj}Y+;6{CQk68Ce)#g=Aob4X~mA(Dgv!Yf%jiy)A zDjl%SB(G{AKeQM{1M{~$f3Amv`Glk;*<5z(=_~`;e~oB75l90`iW*AP z<XI4pDkSFjuf6ww6zQ)~)&jS5T=5*QJYTf}eM-&FMct(MB-v;vG`CoANb02Ug z0_g+${|*UC!R@5&BgX3vIyvr#0i`)h_MMD{-w#LZ>V12=EXeBZt=h0w(LSM3s5YPH zv>b>1{>?p>wWa5|E8*`_4XY>XghBiDjwiC@$E3OhA>5zge=SQTaon*3h+dUyaud=5 zLI5?!$n)0bf#Px^&aw620b_tSfpM5qB7F&2hk?%cPNJ5ViOcka@VIFYlb6$Rp;IR#%b7&yFK`U`f`(sk2uH)7zxQ$k)b6Hky& z8TVKFk5=dbRb<)!x4w7!HF%78ihyCeA6ZX}XBU zoPu0+0}}RykO*mARwE8;uV!yS9f!#5ZxEOT^80}Z^j=m4Iqkp?G0R6QAMY+t$5AB{)xVG#uoy`fzY(HyOur+6^z+~e}-=qCuh!Vl+FpuHnWl@2#y|O z>eVRjM^N@CwU&njeqP&GbWcFU^-{vIgd?x;3LYbtE6QsYu{R)EG2(~<7U%Vja_~fm zNs!)bH(@nHPRzDcj+2SX?pD`bc#!5CR%z}G_!KRA`68?_z6@5zMs19{Kgfcy@(<*C z-HG$bJ}A7TU)&5W`?JI*|Aj`dG!cYJ!wa^0z4_xEtDj;FSmojSqSw>Fo_uw_x7LY% zxwqE2xAxF!!X8-n)*gPBILrcaf1YLu2nI;Fvak^Z#z7?LzKSpLWdVczX3DU6jz;Gz zozc+{WG@P@`t$F$dQ*koZ`M@7UJQ_98&idiKzH^fcJF6z&3EmO<$X}HTC_lW#*^Uf zI=-^qerL+P+b!qa&HatX=&JtKtC&?}tpP+U$U`%d1a*7^~YtR1RBBw=hlK-kFE_BJU|N4^csIp5I8 zsCsWcp_cowFFR;$qRxP&*)`oytw1T@HG1T*$Jcdx>GQmdG)Z2x?P#!>RuB zfAjNPy(0W?8#vKRI8?t}e;**}fW@+6;y?el;*rMhEGW!!s_|o!kNY}rcAZaK`tzM7 z>i*CFrB>Uk*Lkz0p0FJKfB!EKIMWlCCw)H}#GnB)EqEl)QvX};y`A>gHSTGA5IE?p z>Dc=DEkVUTOs_?n@O`SAj#=H5IMx_YqVZUbO)0*06sJ*~sq`XIe*-x<*x6_G;YpN) zBii2bG6GkpYXciZHi)X%PaF8stkA#zAODvzJ$~t2jB|QI8p%)lL3EomT;2(48f2f_`M zA_u&?A(pV^e_cY^w*X*3pTD#So^1Wg{BDfx-dTaUFF3)lN3i7wVSW}3piSirQl@+Z zM&wwl1S;Rb87%KRv3K0OHyWj^?%M-ty(zohi{N+r=xp^nHpAlPaIgp5I9>#m7g)#T zC%l3+>6({(hV3`aCZ}N%0ftU!)NgJHzCqo2cHtLN-2gt7(SPC$Hl>Dx3MZ!udc4pf zf?>E1(iHOSFvGMoX?mnH8OTfu@NquJKSWt-0Y6DahrNmz2B%3_6d}+pkV|rwxAYsH z?`;!pmAqpzJsu${}AxP^;smt<~V%J)D9>yb$gPRk0lxgC5_o=S@eCtqw zyam{+j3AX4pns;zlW>xsVqFSR?@2_oaS2Er#Ornq;q{CWgphtz9WoBSK|KR$VNe+D z*tuB!z&+*Tq^55|h86%oe(&T+t*E0Q7-W}0HcgJ$Yzp9=9ITYIMYOyke0Q%?WE7S& zCQVqUVS6k98kufeqmm5tXO^fePA}^g$(TBeGB2tRaeuV&d+cw*$cQ@-=T6~Xi$%x| z-BTB2nTR1JUj;=noULM1$N}^_P=oX$p(6_(NIqsI_2$x~;@EVZ84H*w6({H?E%dg| zZ0(2epKgF!l-_Hpi5Rk(7C8+b7Px46Ewy(5M>_HuRThmRQn{#>a8F{M35S~O`mz;x z<@y^zjejC&Kr}L2KXg@p1m7v>IKvDdPCCKiX#^rC0c#wk7g1gW1gJ~EOdhbi#o{O6 z`iMRdvyozzGG*myNVxtn19k(XZAt-*4h!eCfW_jddbXz;N8txX2RR~Fu3mN)n&W6Y zO_Hb&J|j`*j_6*BzzS#~%ge045bZMoXnVOu_J4Jy%^EV`aU)6qCPEGcO*lqM)@bBJ zpzXp%ruKHAnq)8y`7G{`mKZ;0XW(x1%E~*|FhuU*`3|j(I8jHo)Da{T?#Xh;=<}De z4+7Tv*ZXb6<&oRTMil48hFV;0Ke+$*fB%og)wQ+uqem-v5AFm4$c@2?;j6<&jz2I* zh<_WkGc*G1QU$*#m`u!`#4V9Sh{!syxv7@CGZpB=^um0}7WHl4XYe6#Rr|SAT5d9A zI3Vypi!kBS8t)ARAR#}Ss!g~3{A}8$>he7P5IsHii%=Kv`(r6IN}1YO{zN2`P7?Pj zIuFoWCW40ViC=Gacv2bTn!>gLck&fcqindExB8Y0)l( zb~h^KR+(h+d00fd$$+>_o3~v><++#k_9p(!$CGXMUY5V@ymJ||bghFe7Ui>7!GH2H zf_!kBqUm<0S{hN2d`qqxN3*|F{nMtxV6dcoz2EIBc>XwU!mC(6s!n|^Va$n*6OOo> z@FaRqz?=hPi8E)nIga!R#_RaNC~Ul%^E~ZCy%`8cXL4!gqzz9BN9%Ndc;%>id>sAT z;(Gh52SP3YwVZQkp~&6+s^*u+6Myq9b60g~LCjsFNmx8(mGiTgCyTq1jEg6-?8<9a zewJe4NH-=#b6#ow{Jn#%QmOd@ZLh3TlOS{c<~dJNcNyf<<0LA`a)&c|0ML$qTU=jj zKhkqO8BH~4G!vvi#+^hGOmVluEG%?i=T5kEns!@=Y=oai1VvU`W|J5iKYwwm=a0DA zedfkOhE;og;SWae04q3j_**V=BC5#S>Iu1dD6q%WWda6b8PZlQ6VF2I>6}^>OtN%H z>kVJ-5Qg8W4q>|GOiPi%8;4`KQGYBq)we1frj7Lupxdrg^u9pU62BK(mfBQB3U=#c z=r++ub@up#l3AxUM37#Z4u2$R(Qq1r`nzO%y0Sz?e@^2>oyEyu6Gw8G6tQaX7Ia1c zf8Iiq;^KNe#e-hb#3A47E#e(*_X9WaYZebri#E!Arog$0{?xxlS<-EpPJWv9M8d|u z^x)Am{~AOBhiwADej&D#G#%x1swJs0T;F`Rb$gnwIbO7*~(OJnq+3gYI#XMc_Ir;P?Sq zd0yzOOI(YiftpT?TC!Vj2Eya5@{i_JdcB{wkw7YTXmqtjFC=S1e>8=`Lf971<1A%j z8ixKMG!k+O8}o@+WqI%9E`9&Wfj)~lAwEym9lB5JFG0`u zwkf)sj@UVK77q0NnmL5dqwF*a*=}jx7fulvm!xt28z_?U|MkoG+vZM~)Yvl@s<~5E zQ(8~jAFsTK1OZ)oP9d*qbM_l$gecs$IeYE6ym7t}^Z2rCx_?B+jcrG=7PXN?d-ti8 zE5}kps{8;p_i9#S831tpuf${LT6a{#+PT3VS8JMSSaL`RLKtV7+T)H>%d-j*Ss_DL zo=4y4{6%XolGhdy(n`V%xxJ^zEvmO1G`%~X<~cLhu!bwx(I>f*?H#!NOHy@Ix)7E6 zDRgb_#h?NCFMmx!^;h5_D?(E9OO4CYtZTA#_?!NUTY%f=qvzRUx7j)kfm*bxbVFZ= zY2rHV&V!Ywk2Teu4x~U^uBI(EXFj#0DND->FAXOI;?2{^H>ONbq=6~lKSdaC&D4<5 zpuvt3^y&!?$OhhZJWBg#xjuoKeg~Ok&dEMvE42+0;D6wc$}!1lOZG)_AbN{aR4OB{ zxt|c@-uQ6?j^HhIQHE%eMS*MSN1ts+6;?Gf9hZpkYMmnb;BhR-bnuIpq!!y5l#@u? zp~=(@HUb z4C0B1Zxt}^{kQne^gngf+vm^iI4AMj46NXLT-@yoMsX!nxbCvV-^=t@ICZHV1I*^aFK;j-X?9f zSsuDZ-rT@A$WUn#y5Nu~fN#)W6~NaHa|(L8C|yyT6jr6XqL=e%ROyd&;;*diE?q|X z5|)krq=jA*pQwguH%O$Ak)_@@Zyl5Oynn4R#j~iO&_oj5iv*R)vKPjl&J83rXw4ny z^KJy!Eh5MOL>736+$@UAqeF<$5<9 zVAt7P>V7#7^N(Rh{<_{m_bi@F@K2dgdLL-e%n$xZG&j`ZPkLH@r5W*NPEU(JNq_0d zbqhFm0^+SYW#d2mb5KG+M2`cT2f4oqQ+gVYkbCTxv?%**OQw3&&=5M`u5_i@Kr?kX z2wT+VbcTB!$@ou3;Sf3V*r6OJ<4GI$cI7uo-r5>Bmu=KJddr>;1F^M3`YXH~j$wii z5&}aeB{wqhn85`YdNpOV4S+WxH-GhkMtUB2_?-ZrG*iz~0P7GEYmwpzlAtapOo1sr znLgfx_lVVm)Dlk2MKln_)uP!$;^w}Hj!)C{Y@_znsq`kBCdX-drgijQ0(7LYHjuwP zz+X`jWsQAYeaRLCx1D-^67XS z0^nY0g9rt#G|1wC9+QCfdd+)P1;avhj41sJk~nuabc{ZkRXM1GCXWQLHXk?__wRRh z)W6~OdLP%<7A`nrT)Mhl{(bdfu-Iv@KU#VExY^ck!a}M9A|k;z9t8yXju=F_P-X%7 zZnL-#adsY#VkR7r#ukavWPelr%@Kx0T#S%l(OalQCvsf3%V|MJ1r=Vb9j2;CV;0)B zM!%yY-o#O*0yr<>TSlY;W`vW*57XeEbC!H~f`pp02!~1`j?>^(7OV2|Q-M4^z{CWP z@zwn80iAc8YonG3!-S1xD?jIHvgF=4oIoiHP{FcM=aAUcjF*UXntv@FMLvS{V@7D= zm5$w}f}&(t?eog#SpWm4G{eG6YLRgBguY{flV9A1*w!#ZF5s=sucdl7pn5NT>TOuo zhbWxDl4Qtj0=hk|%ph|wkLjh#LnJchpZ7LtWQCIUqRf4%45vA3o#XYE? zVxU>L`K@frtZcBGynjnP3jnep*TTw0oD9;7d<6)zfo(Bhg^|e!h=Tf#ncpe-zC!)} z8Nu8xd-%=6xaZcI7r^ai>XbsaZF+q@J@_1Uc@~647Dwl_=gEd_LWnGcM2U5`t+tYI zbol`}8Dz{1M>=e|r5JsY{QyRR;aF7~{<;Ka4v;pWB7Oug2Y*Rl6LO1obb^)Xrn%z2xIGr+;ouCQ4u$ zTdI2rvn^$X6M+c>L(ziX)58fLw>lX`?{(6KWaz!#2e2e*Z^*$Modg1FBsVV@d+GBQ zA9Q|L0eA{A+<(MlMf%_0;ysge;yf$yHr;+^kD!7k1PUXh2Z$O z#hT3RtP8U?%u(B52~a2D80?ctpjHF^jAWqJ`JY9UjX5+|;Jw74p{J9`2XHeYW*=G7 zc@g%{{1ai$YM0n&$meM8uF%1Eu(_~;mlaL{_6SFirG1 z%$i_9+`Ks9ng}n{_lJiEDtgaH01t2skPRsQ@V>+Lp7y6$8{C!2G((~zr*N5@2^5kD zxE!R$V1L>55+ujZXF-z1*1a(qlFWQ**8Zv!)~!0eGD_1k@DMWYuZn(AOCSB;eqB;q z&vzUZeg%t=OX6R@E`6~Wy`O~1z-^aKl9uyBI2!rg5%|0)b*c9N1b$l)s#w zC^GW!9Z)qWD-Xy>$_X<)YPM9K>b~|zF$78;52E^ep@g6D7x2{*%gq%jw8(nNqW9aT zT7=U4lIn2MKjR)|QSjoJjD#Q6;!kaSmI^SR&hfbf!$~D}1;e11c{ET*vY?Jcr8E08 zH-Bs>M>E&jQOkRXrBwQfZv5rnJWJ0JpO|g|&v135gZBs);8IUvEO8U=x6rAc(KP6p zfvgy$5EsrI8ACbg18BFLesAvOavL#!yB8AN1~_SAE>y7d?->+)8V}nM5iq&Dp-V~N z!ufI%h;LMt6d&)d!iE-ZwlrmcwM>y%AAjb>!ySfodmoc&0ggj8K!B& zgE2lrn@5t~EGkP_4$<4__>fze2U zADX04vk9)AGk18YMsMnLz>DJSPf&7p&e45r2kV7VfCISI2o zQvck2@w}HTveba-$)BOswe|ZCzIym5z&}d=!S7#pR@cZY1Y96gpQ{S-Yd%8-I=Yz- zWCho3?dM?q&C(Y~zlH9@!x5`Z^>&)Y?>07)=%RrELQsXM7Mt4Gw)LT6ZhxC*aeM2S zlFB3epv`ShcMp4sqZB|z;O2mjggdIW>^;fSv9awLCFGiQN9##7NTYxTuLUu~DzYME z$EA7q8VfnJ8EHq1$rZJTB=Bz7KQ&E?@imM3=)q4;wo;wj@8v#B#~W}KWl_H!X5;SJ z6q2Q>?W10KTsh5Vv?(XnH4TbjIfydge1*fPd2dF0hjiFV zV_4z!AA=wLm=C~_;R56?iu2spu1kxgM&8Vn9*ZT9^?xlv@#m5Y5civ^alJ%n^425| zk~8lb83%2kt=sHeoXJ>i`%#!rZJppiD{xfXaU;!L@Iq(uE4=38W`Dao9aCTRb{K`X z?5m?6{!V@Mb{*pxx;sqjZm6Thni;@4scFF5lWq&uajA85Gwd%R-uSo-o}xx(LAZRa z0S~IV#35GPF13G=>ZeIDwNadq;;*q0vVjm635-W@3_M0g!WRRP4&I4BXe*8wx^zwJ za3Nb}ScGUqU8(c!G=Gbv#Vawtk&E~#p&^U_0|kQ*X-1EyIl2tuO$~M&<5ui6Z%m}P zu$*S;ba*izqvei5TPrjDU%}|8VgR5*^<0(+)5pS5@i9HFc%d%0J#$SL%NG$4BZ)J>ntVsvQiseuF+r z-ERV%O@A26Pk_1RcE^Ds;Nq)fJ|;_7aglnxtdw2jvI3fKs8L|2^@zGyJs$#^OuOsa z%KrcZUQC~|3vl08T}DGE%hzO5vvPj~#P6$a3AM(Mg0UR~7I(!C^iphw4uGf&$`HB7 z=K3q&+t(+g;}Lh90?8&>O3dI0!=Ydnc5^O1=zp{j?)<8|gZv5w)9ZOSB22m%w-Roi zLY-5V7OQK4WL=U2zO8mc;Dthyj}w{eh@4XdGs9j)V99WHzEIrgAwbtf?-C-6EA_PRBqr^;4CTzQ2 zuzy~Ui4Fj{G%+u4-$sSdw%nbRMv}6tmEPoXymWr-p4`^4_$ zooE0>4(B0dGCHbHv!zHXijd$yCi;PwzTWFHHe8QV3+V_v(P&eNE5zI7zpq^JGko~K3DV}eUwu6)AI6+$QXiq?)p2aj?A18jwbrH$bj}f=F1;hY;iA z2rYQ$S8w4WMz#$B8f$nM6Ib<3>5DldLi{}xEFx-z+a|{~jA7w1+mp?x2uyIlTaVAn z8b2?6yyu#epV!;fD~LS0-+$KkG5Nur=~p(e4F?}^)8k}VNf9iGpdBJsc7o!x^>t#QzW29f_R|JCU6Q4GoWZP*|YtXVoU>Kd0*?SeZ@2o z&hsc4_)phYJyZG1-R_|du=+h>mu?qibO+M!TH+1YRLPP4QT|sN?0-!f>@R9;?&M4Z zyM!8g<6bhh+hQYk0zNak$S&DZ2y+mqt-*PmBdUK!_@~PQONyzx$#mti{|u}B_5Pe7 zQ%YNP>maINkGyS03KU2)_hf~knm?Q7McPY3e*K)Jj^2Wef|SxLxu&`b9cOr^h1?`AVzx2M(x)Yk_ZS=(i-9hNJFn+w!VOi*7n*83d%9=&0j@y><-H zVtPD^km%?lf`H$_F`%`jlmU4x|okLB_Gc)Q#C=C`{L=p3&1n0aUy?<|q zOuL~qj8x6C*P@)%!=704#_krZ$=zVGr|+G$b+7N@V*rzLn&qc444J0v`d3a_ z8zD;(asVfuna`8mD4&N&Wy>P=s+Y&=0wWtz(Prcp=WqUx(I#KEs{pJMk6(y zoMe{;>jE?sasrV`G)-|XmM?xkR3tL9_rv^Dmrd&e9|6LbZR-M10STAB>jF^$N0$)n z0w4jomoe-DE&+3wVC(`e0ppjC>;g*xK$qL>0wni>O=cP|F4{vn(YD`2O>+8 zAsrr9m%Qx)EdiC6>g@s|RwpMg>rNzEiQ|f zZanlgu8&WhgfR|O`h^+DDvmcZzSejsk2O=JfdY}^m0s~9%@5`TLQ(T~&x?X$zwnip zV(tP!e-VwsXcX-84*|i^Y<+OqP{_DIu0!g*j8|F9FNT z@YZSY0b&brVo!J_H#lb6TbI%(Y4uQLGT(M>?*y8pg&MKqvw73}ekVih7TNtbN_Ne| zbCQV=ngOXYewHhB#Qmt!7~EM$v_=$YZNs=0e}lSVe>-#kd{U~udHea;b^t90Zln>t z*b8HD{Lv)p$eaIrXChO#=A7s^riAmlq(iFfhri~6duN}`&x5)-sjkPF?$*!gj+_1C z_AStFtM6|d2tK}Zf1qpM!Lg7$nZ3WV*WMx~w6 zO%#4X0kD!0n_nhH_+B~=1(($#0c9{Ze|;x7(;GJ}>o8~P4lhtP|aA5AxK=;nY7;4O`m(RpS(o6KdE3Xrhb-ZfjnX!&PPiZ&-Vqnyd z(x5UwZJP+Q10ALVIAWsHOQ(FNA*LwY(a#CXvUF#tnG7e+3e$Lfj*3FD=>T8TTg56_E-2&lXG{wN_R`Qx| zeLo$CNsvY1fHZ2pP95#s&lUHEfB!`nvx6*70phNkqcy~=@=k-0RQMMV1Cf|=E`|73b2n8ipzU{ydR;-ymwbO-N z44?+m7G=6uTH2@lcfANIqtl(Fg>C@WJFhM=%u8BHc`$aO^TQ}F++U>`e>a9k63uOk zdu(WCoP9LAs@_Clh8EZ9U*>Zl)%W8B7M@oK`A0hm)7oFD*Xd|FjyS6Vrg)fvuGCRS zQjD=JC2x}1e^Q17Aej;ULQw;VN)5qCoJ9OLaiq&{!-9Vs5;qLf4fT?d{5qmk2l{Ck zRSQzw85-&(qo`EFc?OA0f6st>7>?jq??JsmVLob{#L;NbQcD!9x&-oH z*tvLY>55*An;SOW9f;r>Xv#7>Pr3mi&|>$7120<`%Yb{k0LK9e-to`N2G&*yEiUg zoJjUqOPLMh1WuLHBeN)n0}UCHRfxS?jmFXMGZ;>vc|bUd8y9U!m%H8Al+c2`01a&^ zch->M>;!&c0`lI=yIe@lktc&kJ-ErB$!F8=-=~Fo_Oh!-)5u_Y=wu%~3(q3+l~1E& zt$wwc!J0Rw&LXp6f4(VOsi1(tPfwiqH$ALA9*p@&g*p&B+THSxHI zP2b^1G@qtZWN_Hr57be_3x?Qn0V!F{vj(d3C5? zn{8(+qG!HA%sir)%@MRnzPr|U8+0blUZ(xBs_+rLg{EGJ&NtEDxBsYeuX$y7?XKTN zyQM5;5+wZL8)O4GT3l?r9f!r~yN!*PfT`tK;*PY`{U(7Fcx|i(ml@PM(@aep&L~kM zs!=Y|SXF^?f6J{nFK()3pyjvJYO`r@6stX1zfn)tZ`hOd+x5f+XqbO#u7P5>R!$=< z?r#k%s#^$ej_~g_`v>2g`0qT$RXEIxFpoo8ss^tBZCPY|=_ZifDq@Qfo~Yci)+3xH2=N{<*K5q1(Cs4Vn79$fkXmvSi@`EvA>yH})0;v}#-K zyPOm8s=Ffz47~*&nJC+(1O}ZoAvkO^N@13DvIfT56rwUO^MxHCe8n^= zB)iCu#D^)Hj1OYee1d=93P#|_*;cUR5H}QyFJ!RVFf_@Z(GY`XyP;ASf;!Agjj@-P ze|!x#rqHZ&hFTuy&gWtKI>Ae?y=v!amV=zaBcVVGMla+jmWTe#oqLA4q&6 zom+&S!B3cfeYMk3F`eZ|9iM=Bgp+pM&2WTqiDAnxYGGYZrU?f%17UCrI8bIS<@zik zXvv1*@L*FSDNm$glyR_bqxnchx>~l}BXu0DOE!l<*TOL8;<7UUBxLG^4fmmcckxqJCS)zZw4XmCcOXf)k zIkeRZzVd9~A}=}VagPzrEQ`><9{l`EFPUbe%|F5#if;1icnh)-%=m)(C#*&g*Yy_E zJN3mE>a7YA`}o~AYLFUocbewSf5nD1#c?rFAEW+hir;j}ip5Ka-Z21+jaj9GOf7j! z39R#jG^tZEK@vQaz@&vkhxZ)>HQyqvnds=&AOHr&tsn_6iH2!`%$fn4ktxQ<1cQfzpQkyVNdwX}g(Zihfbelbhd7!V zmkk3>=TSIR$I&TZCq=lprQz3tG10V3esKyUiIbu3D1|TOU>{;`lNN=TAjKrl5mQ3h zR7g7!5@|pS76nBxf1BQVK#?-!)V>Rmpp12Zhl2EEa$dg&4B|jF5WhYzTL6)HQK;`& z%gfqug9vO%*>*>WGjw=-0naX_zp?RiwjU;gA^>?Gz?=93Yk;!cGZ$5-d2})z$#o8q zSLa@MmTF)fZoyxMe>~PPVCsM1C;9gqW_Y30GFA|r&4b*+=D)kXH{fJgVe9LL1b06LNP zw|f6y00E$1;u3^u&0ELVrJ3yltI&QIq`U!~NwXFCHf+Q@X5zwHzDpvmGAjKIV>IVi zn-`<0Wd%@We}5}3E?-d1NIj>#v;oW&ocBQ%4V_xZ86H~QpTpRt$)&z}a1R?@Y#1gx z&Dqm8BJtwbaGP~x^OmlO-TdBu1NS}D^c#(bEd>L7nyIfiZO^2K(K2OFywy%MhqMA* z5t!L?<43{%T`hcf;2G`94JVVFLnueV|R&^_)g znAV>8DCoTfi-GQxBHw&(;b8TR{?K~(q2F=D%j6*AOOO4!qyhgSG(L}i8ycTyzXgp? zTXvhteR5s)4Mc>t)Wsq1;Xw% zgOR7Pzr6+g@BilIc`+@3c)pL*zHcabTp~BNW)aL8m|AgMJI9Rx1#|t|VO|jSfXBr_ zHxUVesfE3;I0VBiOs1m{k>2`h;~@=EQ;bF-f7Ovn$JYhU^Ja0cp-25TESZOYB{M%) zk7@Hsd_o$8wU9q@I!0!$ z?O$H7k|nLu4^mSKnY!hPRR8(E6t(`ndzY4$Os#E3YoLpBBmk`*`i9g4WPn@mRYGK# ze}Yn>F)F-{m${jLXH>WujF!g{VJ!X^qq4j)JIf!)U)lJ5cpzA;DA^^!xw z)mcTt#+GQQa4=9ur3FUxF=h4`atjl&t)9^~L4>DMOrl3(dKbK4N!p06`dYn}E3r!o3GSF1yrwFlk{oibK2;&PR? zs>&G(K6=nzD;1olbfL=EYwh(?6{AdXla)R?Dih7(gRjaZ9QBCaalc%^(SuOn!K03S z{;M|!vkrrrX((?X{lAYhrszSt)0#Eps~E|f4Bw;ns@LOrFQhdwcam>7e_=O&XN$r~R%Xg}1D-Tc3I&TQ3TdcSi+@q9YyquHl>m}MbTTp*qfAy)u_P1J3u@QAEA zPWq#%kWnxyHYq!z=hW`%BbBm4I2>KTs-UwM88eQFdXAwm`L)a7f7&P_`OzjI82cVq^u@Fjkt)o$Hb?dVHOQ6zM8qtTOfxZ>XH1k|XP zEb1fQ(u~%e==CoAd23h&!$^JIapFjvz;d5fFMxg{6dTtDop^3^J-MPQ+RaEbnet^- z%Fc>A{(ub<(ZC>I8ppiTjt@m#X+&GsOYbfp8BFh4!_K)HAmS00e}Q%W7v}kMi8wLA zNkq-vWc~UJS6);y6E7C0S#(!T+BK|)p-3k+d(gQ=Y$}~Ffm9;&qqpGvi2pg8eN*WH zD6i|cop+U`VVkf4CG+Z6MZA^A=->KH`e(-TlY2O~h1q@N+z)4H4UOnwDzw6LBk)MX zh!<5~?ewa4DF)nUe-)X#l>_GshYsPp^3fq50R+wRWmA*rAXG)O5dZ~+L(j)#NZe3! zMH8$sc#qg2IaonIBy>5v6TfpT2gSZzq|*`1Z$fCmuhj8B-+kS==h@9R)i6!H-k-$9 zH|pC*oqKB2BKI*|qzm)-k0+5AMXw|e`=+97I4c0>_Gkrhf7(q1WtsA>o;yoO-<`NO zj^mO|p?Mp@Z<~{msBO*}rAiCV=y)%lH+bGTQe{d~M_#Xw*r8*s6%&rghb_|Ooi)h5 zWg|<~bKMlP7J=dG2HI*TrJn~eF>D=Qs?{}I<`EsH4_C%vW(;EqFj6_d2+2smW?5n> zG<`O`5zaSrf5`_oDGYIWuD4G`!0c+YQ)e?~sApmh+>J|6qpTT~ciqhWh}XLLk$p*y z^nulEk|bWfsq%{$P?^F|K5wSoI~TS&@8k#SSGs}#wFWT}qj-)?09{L?R@89j!w1UPtJz0$N!cJXb!Uy2GgIMYaennO>PCc7qz? zA`Tn00H46=^!X3yTDF0Rj9nm3O)_A4SvrKq?pAZdVMCbBQ$Xm`2C!HsPr6OPq3M^> zBm{1ue*+Yf%ccDQ!B_^hL4)bu3?42KBoCsj+47kQNRFIjQM6KI6u{%^u?}0B!y;)B z7#*rge+mpZ`tq{nz+=8Qp8{`rSy-Tu(XUPcyNn~b0Lu;I(?b^#4oRPF!KaT)QWM$8 zAw~G1LPx0y<@75pCzP|E1z1pn_x2-}em=t@f4c;T4iVw)OrZJ03I&{4x=f}U{mY+% zV4zXdLi#s9oq1qhi+4{+phvPyG2n0L&)^v7M(7e2qBCj~h77#)2}M^U#yhLS_^+iX zxFtIQScxj61iqx(F~jB1x{V_&eDV5Yh`vuRv=`OmW~*#eCxz2ta9dtxy$)Erz>uHj ze^C$@L7D}ll>UhWJLZUiRj|H-)G?iAEg2ERF_?q)Aal6iBz(`H`>(N4%Jb4__pigt zCO!$x1}m;`kRC9E7h-z#z-aC|rm*JNdFq8hd;k#sR&uGP?0t4`1|W?P?M{mg7Pe zkR%;kPh9aw(^lM&bfT0}Hk`%)wFTQ z5udLi?=4+W*h+yd8z(2i_ge4ueMmjJ2q{6tVOeHkVTZ~i^yL-D66*cmq82PC$nx^T z5-EsqJ`h~4&?CF|q3Vav8el-Af98BZQJA+8yY@asd?C?AB~}T@yXJf1@i-dbtf5nv zxFIP%F;UFr7MKVpOqblA&9GIrKK4SGA#+Lxq0I|WHxgAt(2i?GN!#kfOSuWS!A0M^ zjU`!)f1X|AtR6L> z(DL#?5I(>`nj{&CPC>Szj;N@gX@7c&8fA}@%gk>c$~f81K*<7j{_#<6r1 zD}?KvxE{eVpGPA1r4}VU9tniP)&~osaAZ}&K6pC&g+gqd@MlA6c~HfA1;h_3RbuG#X8EjUIieQWDNUU_ndyWS0t;X2IVuUiy$~= zP>R-Y3E8v)e;a~GVgxa%$$$+3rT%URtjA+-5dC`In$i{AyKpc0%XfI$+wJjS6cvx5 zTqeUt^Ib2Y(?&J8!M7$as<96Q8DiFg-x%Ox>icLk*^hFP#t16V*)IC>JYUW=dkc6U zy+%-w#LwX_rIsEOrz@tKMsDdwMPtcGgr$}j8!msbe-v4o@ygP&+f;6IH}1m0>KnWc zLFY5xL+f{wi}XMj(@Pe8n4kK{`p)Ns(;wX|p8n(Nud@T`Kd$|{^u^I{5lO$Gf|Jsm zt3|(iEw#v5k&DwT-h4aF;&&SxNp!*BRc@qJjkcwNS6K`Us<^#%OqAFWehB30)7`^f zvWVDTf5rrJymi~00d1ojo@D7*;v2LhR`Qs73)VMletH>RsFeQDnCVWdH)_DS+PRXA znzLPQ)8W;g$-XWVP=VsSz5}q{&l9QFc4XFK;F8yagWe5m+@}!5eJ(W|s4IJw03e-E~ zzlFQ8eVV3uRJDuTSs(iJ0{5cIFW}e1v%$rE2ZrMAo^WgDC!q}I&K92l2V!jdEZ(G)Op2I)ltEV|r4 zI$2}9gLy}WF>;>dYWv_7$UnwuhUBVbfL(E>_Fi}fEQ5R@jKxIj+XvAq>+#1^#F0t9 z7<+rsRN3`WgvIna)Q!@JSa`kH`!FyMe;BArGgE1^VNe>U74<9~a!h#<_jB)KcnnoP z9U&G@s=IbP#9`*A>1dE|V0hHQ*ALXUYOQlm50nbehw59k-noaW96dwWg>;+&_s(aT-e^`=<7 z;r`rOG)W>XH^-}kY$lEAt>U_WUhfP4mavfKb}tnVfv!}WS%Dhr?^4zcS<`?J4uer|8!?O(GRl+4Y|n?Yp0YkRo; zy#6=LPS}r%kerqJhrNN5KO~TY-LvV2ihMvz=-U>D(5b`XVpbIcK^u+(;D&hmC!Fp#Y`{2;xws11qBr*5>Ifo|EMYU!`F z{H~?sm*k2=O%Q@?eRz4_EY5mYm8>V@m7+KSEfsxgJmw0UP7q2>_fN;>QzMMmHk3Y{ zs!9c2@8mU0xjLT4qXM+YMt>qNl$dwZ6A6QW2T#0)bhHfcB|tpmf7h(u|NFoHhqi>K zC;C+!PT`%2Hstc)mDjt5SFBlryxw9DeG7^X>wx3%J+(oRGpqOM)g-aUz8+c@)kc5l zEv!^gYHGo0hO=yGbb-_);2J1=<>UF7AZ$FTB^q6C!AVNkK6vGoA>TOzgDy7cP!Fam zfK6MzPldy@x1heffA=Q1HxBL%4)1-xac_U)UiV*{PBT$5C^vFV4WgMn4@c_YaP@oV z_i#AOq9MucgGbeO76`T!$$S#_4Vu3kDJv^=o%PqK?yZ3`(#Hoz=qc!b=~DC^X1lR^pCuKS zc#*}!IN@{TeB2H{jN71{u?4X3s9#)$`%*5z&$e___5Ne;xFIZ}{l~6wKMaTYTjz}{ ze8=de^(yA%AD;!)&QXsNFs=t}$H`*Njm_}*(?{K!z|XoF|oTHLALJu6E<${ci= z3Y`7MP+I=5h4752ThXz~YKRlnfay3KAa$=B^;6(5e;{?7jJxF@QSk9)^>->}ursQkI5YV=9F=BJ7sAY;dS%91^kv@3Tz=%|#U67+hO=k6)0dUGHHBaA z*Ojl_LTpOnC@NHc0^RE%%1&-I+ms7ux9$N4&8EorWC!9D65JNJr%VxQUdoZZI}wr# zD)}5Lqz|ues2vUb?d?r#MJs^=9_j}`jOUD~NJGfaNM9)fU~x8!w#{9!bq?rt zMV2N*Yum8~!%~H{&fow2KkieV{dB<5kfv};oktmrEo_i87ll$A-zje3S$u~0O>3$g zf3y_nwj?*kS`5+8^=tash)--vR{SXzDaSAg&5Tgf1n=)7vfkrV#5YZpp$e$@vsBputw;2Gz|Nf zPUf6wvSg)aWp;mmtJzk&j{Q@t`194@{FHLeS(C>%)5YzmB#~9EaL2nm1aP&@h25h{|Tv;UvHH(ie7y4FPh_fzbk?Lz>rtl}V9He|{H zf}n&JDZ&6L*_TiViK;{)53@4Mf0(xTS3f}C8_|EdpQhi$Pjcg1!ya;|0i-;f zwmSNl$lCL`_FCWi*0%@@!;w_F1D=sC#{R|1!|lIaG}vV^YK}LG1}hQE)`|stm)JG> zvlmA;FX~wgAMpDp^P;|mBll6679gdi08Blk3ymN+5?D=urn`n?gPG_HfAj1S{VUCl zgcfZDKx#~J1SMogP)QR>AN|npjSxetih8uHs5?gS>5Jpj=)i`td>U>3sRQ~1Sj*B-)EW_q~01NvX4Ww^@U`J zXKsFkAqC9X+Z!yK*PV7{eM-QT_xrUcbPJDx0WlFa$rl5TU+dk6z;RDn1f$y zF$bTxVxHS#)Q4|XInPnfBb4(T27Ey)^+i;Wq&NjFZ)Pi zj(+nSYIj|jB&YE8EXe|nF@|IW0Z0+`4JF$@=JT2B(kD}woZ#Me=>4)6^l$LUTm5{t zyYTRWiu}U-8VCTf6JN$v^Laqdzp<%iah4?|UHyps1phQL4Y<>2T0GV-V4ktE~cRUh8tmAs=&NqlJ;T{?Kidlzr{KeTf|*9=})v z0Rn6HZ)e!Frfw>QDL#K{3+RVi3IBm?sB739{e8W9@3=ViI2XFJwty3cgrP#D??15TJ`rwz_2y|XEaKE3rr*!f1aw>- z>G>x~fBe%r#X3Zav%wy#*+XoR2!s| zc}&nk_J8M*@M0bu@U2h!6#pTrr=?xC;V4!~O+LPp1*tvC1b++uP7xr@%d}3#xY-*H zvZc`Lu`YUgCLRS5CW*q}S}EO0;{rCEc~;z*y_b9ZNy7Uby@^OEMOQ+gjdFTQ9&SYm zu&JK?`k4*j*1U{w3~=V=I!WGT9)s{5w!=~yBrbI}nX zb)%@j&7{chlYa~cxFj+`#<>7upW@A%{h}x*6gyomzWLk~*Ev9*mP>|T1rk<F}U&0HTYHwfHaspDU zr<0n-oeo)F6d+dPc~Mow3Db-!@4NtbZSJuO#ET+zTz_!39+o6oh-{hegXP|;6Pcg3 z3#LmtTB}8DXX-I~Lt7jC;^&lk`}U=|HH|Rp5HIU8Jzt;+UNsHumf!rPP7239__k6I ziHyqjI%1+qKk~m30o5DB`7`&L0!vVJxu~)5q5vBjH3d$Fsrx6xCJqg(ToW+M=xR2) znx#@s!+&Mr@b4fcdoCM|1+{tKk_!BgX`EFf9G8Im*Ell-GZXlSw6u~xZJg3KISX4$e#QaTWJ^a{oPYQqaW8+Tf+GQ$8{KhMah!YOp&$FUTO8Md0 zAIvzzbBsRFeRvau*@b8?zRdm@!ypmNi!t{wHWi{4eBYX2>rQfyCSt$St0SDzhCj!@ zW`FS`&Ejb;Qs%CCdHDJ?53F>%O*ihB`$sBsJO7vc7l(LCdEvSkHYuYBON|ziWzS@o zs&CT-G^Ozv>Lw+EbB#1!FNUYNZhqo;KxIX_YwVGSkK!+j$S4no5AYn(+fz$@tt;s? z_XmS4Lqv{C>P0<-nG1usHYL!S-1y}8L4Vhg7vk0u0|HeFOKZpMm@QgLZ0)zE%;)hr zOz+394~PD$Cc&#RU;q9^#BhGs2#BYs7^9Tt7iDb2?|5rOUZv)BT)i`8vB28_pI(5@ z#uA1(n-)yO$rV^KWh!c91Y=&Dv&9lo*pPdJ3Dy+uD;levp5BpQ_LKbWil^ZNQ*25by8-|WIvCF z!{OP$oLv;-MJ0d09|}dD4d4AKqYzVIsY>2cx6e+#K78>4mb~F<{snrB&duZTyLd_u zI_QMQ#T>HkSyhflbuznjG@C@Sq?v*T#Rh4PsO3qJYMVI$p_HeGrk#v%;^InZ z_h7%Ip@_n9HGlo@|0A%8PKt3A%_}FwkR+o-5`qPDrp=xE9bAM(uj_Wup zrhcVfDyo^rQ-~bdt{{s>I=QnW+}dz~YK%wht%UQ%lTkrP7`u~^!lWdgt&m`{@- zoaZ3%(_X~;Attp|6>J=$xAa~=ohp*>B}8T|qN!UzZL2pItQ>yN0!@2V?ILMBW+6qoIox zzmE9Vu3vPsdjm3`mhl9G@*y=YxRkD+g3H*|t7gfOIXF4?R2Gfg>VHM-2QQae^e4e? zMmR{znl{U90J0a(uP_<^(Pni&>6Q zn8ousDHipVxxS3+D6Jy;OS;UzNK#i8u_KtLhtRKa1Yd0k0XCxZbVR>2rpNv`W;z6M zXQ3irmjsurE{lQ=@qdv?%CbO^Rj-#xHXqet!sZG<63*FZE|WQ6IO80eu|~59Wa9lZ z(v(!pFMU28c-qo$bQ6l2hs$u8nh032Sd4=3ACS&I;T%va&DCgMUVvG-Max7g7<>SmV*OsDt8 z);2WJ|% zLm*|NF#c3cmVf>Yw6M(Z89#lveGE6LE)$SZF~=cM8jo#dELSJm8U<;g!KnXDo-#@# zY+~^F{SUS?!FT*4&8PULZEL*1xRL(BMxyF6wyfKrJ`B%O(&;uDf**);w&S}T>Ds2( zWt>+CY-}6kakN>E;eoL2%R@wI@~igDavbM&TJ z`xi){5r0!X5(X&Tca0yXe3CXDY1c8Y+@o~K$oH;LvGU%J7G=sYPJe&vec|5qckT;`hI)F>sbWyZSBrD| z3lFrEEu+46u_U=lUMp*V5r!_Y3rQX$KCrYyKDO2$eejJba0oM#nyU2F6e94~U=1#GD)-2>96&brKprLwso)5`&(^SW=Mk#i3Gc z6n|htreGor2ThpYnYe;fZ*dk+CbSph>^Vw0``m)hgE8RV(>2xq0Emh594(MLlgDbyzI8Fz$TU@S&J9@E+P+LY#&h$HrB&lJ7+6X}0-$B#1%D}# zYQtP>ETDrT7;V(1{;aNL)=!)RBuUGhMA_LC!j{~zE$zG=jp0OSO*l{5nm;Y#vQA1} zA?G)Z@>e!#odVFVgVv4++eou#3&ZZEfF80QTie1_2FUiB8@Ml1cl&s$30(whS@BN| z@G~h>*5?Z|Orv2JDUbwdoJE&uQh&zf`0{4$_Vwi5wy%`T`hJ|>SoXg;1B{?&zbfdh zz*JBJQz!9kpwVJj=mn61&e6-_8qpy}9H|5U)Skqtol+0Yv9c5W*$9_RgZgTovF zU=TdbB^=1vgJ=e&Hl5BHPqwOK#PhSwoWyB%v*sFTCr7iM;ZxYSx_AdFyMOj!&KX_p zvtp8Da==>7`gPjTo3S-el#**tE-nzw4UGE2Y{vL-uLRdL>O;i#<3Mw?s%gC$TTSC( z;>e>cSfE+%)P;=Gu}*-bP_YWa1oJ<^$t=8-;7BqM-Gn3J7Dq7 zl*L^A+W;^`_y3xlpwUp;`m+32!OVvA&}5DW<5Xt%~H3Fe@!il9@U zLWrR?dcGLHOWZZ9i8MH5L@_qjZecqcTKIboV1bBGbGQj`KvHU#W?=D5#x1#G;xun! zA)Sw73a`QIe7%Y7%!VdOBvW&-AcGyB98A+UnI`lGAZMy9&Iv53n1475dZw`qsc3Uq zl(B+QV=6H-FUYP6 zehBIfva+P+*jp|5dw*=D$F9Mm*rj(GW}6cYe$$G%#;{+GKBcFF#uc=Qd=XB0X=#J{ zJh2vOy+$inmw?t%>@tZ%O+HI}D0o2guHb9I!Qd~8D9tCy`}IzS?tJ7bwK$KiK|f2f zQGmTVL^{?~s2gw>A1N!J1T0`5Uh#MwdG}g$1tq=qZuP@!Wq)?M3-eLzO$JS&eJNvitSXq5s_RR#fe2XxDn~ zEXf-@ckD6M2*TmTUezaAN`P*^fd!(DZQi!-Y_3^(k$dfj0#sxw6XcPGtZVgK+N^a8 zp~dF{l{q*l8*c}T>~}A?1UzxhA|JM`CeiOM4Qu9H)~dLw ziZKZwO7AOvU=sW@zJkg!cy*z82x%M}nBFfL35KgT&VRC;`oxW{6F|lIW|ZHxZGw8Q zLQ{ zVNHm*09h%26fPr@jVV>$!4c^JDiAJ<+oVn_rFA}@C`m>l+D81Xv;dqi0R zZ>egx6I&^UqH55FR$AYUYS4-}1p9soB&WrJOn>6)^1O)433DW~L7wpwyXGwZ(Q6+} zlkty+d{5=yveM3m9#Ui1oN+HAhMfW;KxH3PH3gXDV}IBDx1T?J^k6hA%rDK)AJRXt zBYytyrG)K<(||r;sQ{pCCj{Qdvsz+jvR~|)V5Fvd37dZepg@q29$QP7sihZl7A&&x zCx6nz=$ng-vbzLivxeA#SX*RG;s&paaghz!Ha3gvGJQV?+^xz*2H#~+jK>qTumJ;2 z+na;T?d(`-W%V%iwLeV7dKjHf6 z&6$VaJUjRUgLceQXNz>k&v0RI_yaMXM|B~tt#*NEL@I0)K}@g=t58B~seAmHhjR4% z0oWwlVNNZRagxG!lUFUNY1qJ7#uNvbB9k)YQ|zm1FJ*(M5capnUYSkFSh&QNHH#Ea(*wf%tH09wp<=)>Tt)hT#6A3R_M}{SgbaRM_ur%9EJTFdX!qjwiGR}=iLtKOgi+Xb^a7$UmG!&yr zaz#LWM*j$M)Xt#B2#Ke80gbS!>VL$)Xx+{D0#NJl#z2}^q?3o!qD>j3p&cUQt-kl6 z56w_k$gX+Y;g+`CXN{aKBsviysY;yy?|4gT_U6n5D0DAT_`=*LkB~-7 zWYMHxhr(dtSs*)CH*0@Y%W|RaFY#}zct4@GAXQHjl|gfu#v%f>ll-@==6|l#EOyd& z4vDT6X&PNkb~>y-;2q~fy6nOcFKe>%EbPce_gSM+%{lTN64$J$k;SXU|HXsQ=m`DH zyn&xA&Lj|`;;#8Ol0fe`QVUyJ#CwJ9TBHzIuPd&E(elDrrE42MPqQp8TkGAvGB&Q= z&&qboI`*CkP2J1p6$E*^41dmg&Z|9s;~M;|Y+{hV`Es=Q9pApS{-X1{;$>xVnXOgM ztJhm`*5q{#^B{nGq=&!bijxTNH<6acA&J)PgXSLf7ZX_Nx>uQ+!Zxkc%SVPcwWyI6 zgkN6DMq=Jt>)WQa_!$WwX3cnVx;aDOrbUNYMOfD_+HT)gw`tSEynobs?~~Mk(BKhB z&5Kz&t~RZsm75P1fQI#>w|K?ok%-@=0@(R|eAnw<%Dn55srl_c`i@K6`0iy4^h-)+ z^tEToR^7-;hk*CVb5-TKkQ<_VwP{6uMw%&_fxyF6&P{kdZd$r#qSLZzT9tw=!_lUN z`x#Ne3;mlG&`BJhsDB!9QNdqS-Ap&Erj?uS78?8TCvRD^zR8!C=dhj=wdkGJG@tw; zEUwuD&NFIeCFz#i*S&6woD>f0&xlkMOP<1>_C4e30C zc(Q3vdrRTox}S~rv-ggITh<*lJP}w;%f(I~ae_#G$mhkn*`$ zW%^#DTrVjKme`f_j;8{{#;PJ)VGQdvyd#%C%=UL1u%%reoEa1|v00sA&hC22Rf5yF z#ZN0Nq|iuU3X}`-uBHefMqb(rR212YMlK6!U4&VAynmv7q0x4e`dk(T*jX!Vhg_uk z+-j35{7m}FCZ%v+EqPMoXj`?N8`T84P|r8^LvKxDDBGkOm!)O0?Wo{7Ip3skPEN;R za&D33a$)pVlBMV6stwwx$YtRNSFo7m$Ci%Gk|2GEhD{2wBx*}rt!~u)c|G|-9YLGA zHuAg4iht=^HTkLa+D4)FyFNXNcruIUYnAEJ`X$O&ClcmlTv@9`KQ+JllAMq4Ep=1I zo7V=-gom9-9fO8zjb5N+WzXVw31K7nRY{hL^lH@uMO(G92&-d5BDGQ*KT&JV5lz+y zEjY4%Y_!_QX}>48x89h&Ff?|B|_boB^y(EkZC=VdV|vSR8atB`zR&5E1Z zNPl4TErT|O5}UR?ISx>R1VHln3OS)sVJoLdzx-MJbqJTh{;E#u(VQMI;STi%xx>2M zPpvx3WLDHkC&px*O2h17t^Aw6UtPX9y-RJBE3AYZ$L47Ux+!N@_3E6L=@p`yaHk>V}G+tfb)!cOYjvJ^kYlzu%jN7u}S6qMTB!0 zw!;n`AIy*ds+vP--bKq-fYo`uW}l?eTVwG3Zauy zzZ>~3mAjD&+#Hg8n&x*^if**V0xt}%wrTV4XjyZi5i=BdbgVmWUG+9gp@AbdDu4Ob zTGkHHc;`xc3JX`a`$?NXP3rNYW6XU+?cMw9^0($zezN8PjyB(< z!oK_T_7_MqEkCzeg;-8(afIEi74359Mbw}wle0Vi)1B+#ymUk}V3-^ns&@<%BkR6* zPAahR&VbYP7lmbP3s-`LR_ZF~+JEAkRiIgd;)PyLH?rl7+n`)OTgT(uR%O#Qo*Hmt z->k+)&Y(l~)d4*TR|LkoXqH6d%c7`~&8lkUWt?0#H-I+MM-w+^%SYa?qbuzg(jceB ziKvP+s0QZCz?P*6mnMg)4Nq@}CG#{t)6?W3T zrYtRvFlv*DG)1Ulk2FDm`BMYR2W~!VnYr_}LuO~-X>Pc7L;JUyn1Wylx>FRrTl06<`kEz#^X6(IreJa~ zcgg#GJ=dywWs&@3u!(GwJZDk8D4|RjEI_M36!4q3YIKwJ** z+L|Thg&R;BrglvGoFEMkK{Gk@^&JP9v`3rh;VHO6BbU`Ug=%+c+4{x0465ICBG_Hj zxjnHW`t`RqXvCUj+w>^%fLNwmP=XE66)3U;T|ws@e)JVT;N$}rX}L++t&CRfDf4XL7Y8}fOvec z_w41ta5nJ*^BHpwA&-{)EYYWsq8TWSJ=BQ=V@VXU-Uwu*K6vX19Cz~mU5O0Z9vZo_ zz?u|N0u&d$zWjrhhkW4aJRpB^uQS%KTWDvE?K0e;(|`P3#J>M5U8CwVpbJpTB zK+~z?`xN>a=6HN~h~R7-9Lzg`aiBEg1c1$i;}PVKhJXjbe^M5*M|i^9VT*|d?1Crn z^6k_7@z8uj!D*%o41qxLIobf2W#T$M%|98M6MqDj=c1%+FHFX#LqKuo2y9Q|!u&tK zHJ?5B#mZ1S!OB@P^Z317ke z@lC>r9&QsKDN#?bhkG_KPk2wf4$S=XMtlxFh+Nl^ZpJ2McSgB5TNUNv7pv;%i%oH6={}oLDNy1!6gF^0vHjsC&Q^t&*tm*z z)QGcXQ6tu_WSuw=a>n^lA8ZH!$-h=zeQ_MlR>yHzG07_;FxZ=}E9^ou$^!5mYjmbR zUcy;dyo5%$gb`}>rKnXsY{x%1>yCe5Ie#6Q;h&?{tS-DasKMEKK@C>d&>NeeRRg80 zdg2hQwG=u74WOQrW#I!*biSCKC*`XPI&|nhA&1wiI14K1B)sPX*b?0<`>tO5n&*i4 zD?7_x&P?wFBA+sgVyYQ1bgn$h*Nb#&jt@sCN8L2>D=JtLXw?!@2Rzg##~__v=YI@e zLMZJ{LTI+OhgoF(GWW(D z&t;1g059Nn_GOYk+9u(PR1sB8(X!nm-Y3GOWKIHB*B%b2*uno=lx^bIL3Bwuk_&3LXzcdYN?U-*rQG^-c&Xe-dt2I*vK8kDLaPgNpSbuwf2e1G>ey90gd9q3J)&1>jvcd0&76j}Yypd&2oz<&XXf=Jh1 zmplLZA+FUyQpiYemJyFqSPWr)z}okP-8l?nRqZS;o5j6ux(Kd89!f{>MVVBW#1h9Z z_uKwpxT|Bee(dlV}&hv`1OXXA9A-rFAb#_lD?Eq_0DuZ`L}Jk9S} z1IvF5mfLK+N$wHT`^-6;=kzQ+Q52o#Xv41Q&U~6rob7d2qLEc$I5Jh2rFkHFAVMQ8 zxU{;&vl63APPud^;&3W2VqyOgUPHdM_zJ$b!A}%Y%(~6{=b7(V-+1P`4;2Y5BA=3) z0YMJ6;7M|o%1y_P%YVB~!`JI1o}GgG1v_fjJRCk4J~+*pVJz7-dvov}N00E4hVnEQ zC~4~jrS=WhZfPuFl0x=aFr?R)3DHZ(fd&YMIgmM* zb(E!7B#or+5{yW!9Az+$*m=23FY0g#c$g?Iq=e3pXcY*_h=1KN<>ygg$ttk9AYuLW zFaK+g!@~Kr>vpz(_t(GtZ%IbXL)_|#S>(z4ImKqlZqRA8Aw!(Ai{zSOX`=_%N%GDw z;aNH{*9k}VKqN02LEB?Q$_pw?$CtXYnylnx_70UgF$J}vz{NbXTGn?-@($5GmHvz3 z3c(yXkU(zi5`SvyGL5GRl?~`4#@AdFSyo&}i@6LRbh$YQ(QK$_Ftpe^59C}h&81~k z@1pKyFM9fY4J{(2Q?rL3q}pTC4(&y>KtgdX=BVHe?|&XZ9FTO`S%ZwrKacA=DRcL@ z0i(Awgc1N<0U{@LGB*!#1YKaUdQ&0MuKXzMh^not=6~@6{P`OW!!BV@F#l8DP`O>Q-uCNp!n9^>` zlWPfRLe+eofUV)Ov5TZ15Gu2D46}RTHYZcba)UX{2gl~-TOQZ?Fc_&vy9`BUdCgbE zi?tA4U4N<)qIHJ;@kIb#z|HF=6IKl}aE<#J!~Og1p2i{N*4Bj9pY?uoqJGRMxYCqW&bh z*l1c!S{3kFn^15qJqmvpjNs#4M@TCxhPRN6-G4eNdTX=SwS&2h)7&1|{xXiUs(>am ziA%anXHD(C4m=I=YwVM>G6_X&h_md5Ff|v8jB2F;4@#GU^CZTKk;BA~xq>+eu2UIlJNOCK&Ngu)DFK zVSoP#H#qEN?v$eOx3*d^qU(Ki%}Xquf$|e8PzT&Aj)o70GVs`^Nj9N%S|@s{`UYA4 zus9bbhWp0QXZLrPMNSfW_T1nLSqLRFdEdzgfgK*ak1_bWGMdUjrDI}MWF*;A=$X?z zOGwCPm795D;%Tw<_`ziRbN)#baOR20i+}4ae3e1OL*tsRX*O}PB9;%3^Q68`lH6>$ zf`>ybigNOrfFD<2j5Sa2%U1Ah8)D(J_y)hBxZ+|G-)yxi-5wZk7Enh~V(m!gxEc={ zbwNzEGJZII!7KRxn&Au9><5luLmKj_c5H6opxnlGe_;=AJb&6M zb5-%o-BUQ$_?GItEmGigavaO>CuRVWcPQav3(l2LJot3i>}PRRsf=$$3$FY$CxnHF zvUo2o6&1*+MnSofiFYvDJqBHjUt5_}i;Pd(ot+ch>bpBTCO$70b4V5NRwUy*#AAkU zm3WlnMCUxu%3|(inIx;TP`CM-?tiL`RIc)GdgzEErqT-2iyHYr;}r-&@wEnFo0oW{ zsl>+l_Wdc6(L*t_q5>a++)mu!B2QXqpvKihvQF<^v$OLQcdTDeH7|i96I0l1k<}?K zbaz1ptKwI?28FS>RHo$l&ac1I9QMJkU#z&A-LTA2%)?$VB8j1`EJ22phL! zM&r_7d5_h!sur{%%0*5~S${i=lB*GJ zNA_uqhfiFaS&X;+gs_}q-jRTY{6a>M%%oG)#a$4V9?o#Q%&j)VZswzBENp*dg$=v5&9YWNL443o*Oxqo52WM1Ism&6~D zPIDqk_THNmAF(Lq8Aq5>Yh2<;zBtS+TEP>(36+ivN8uJczgc~7_}i%;LDoPYw)P4t zf0ZXul|Y9`_I7AQ`IzP5dNlM$CQe~L!^>Qu1oFxyTilNc_5Z29a;>h5wT|a}udxK5 z#rbp*#g;%H#PSeDkqQ1U zK6-O(n0I=Sd=Kjg?p~}m%TntOG|m{ThVHz+l-w%7EuJ7Ve}5)TrQUPa)YP%Ug1q0! zLBm2NjzC zz*R!UpJ*|+ntzN>0VJ1OCYhK#c@LpHp@aL-O72O}M>$mJCUlx)U)V(MV-gMRbzwrA zHT4u)9w-=salz?_{NTC9SgLJG)dEhtbYZdt8iVRGos&YM63iAEFy7NfhFLnz7l}6_ z$k@2RC5BQ_2qsf*B{}p%>SY4od#bagf^RpdRcnTG!hd*3!2FiRqC+pi@Q;6Au-1*P z-g1V6A$bo$bVxY;r#Mm!&J<5Ww)y#wVdxg1q)Y$4n9-i(mdFv0HhdzTY2ws_Yr1^gdC`HH!`9)&zK011Rqbaw8HjZinqt%K19Exh_hCK9^N6 z@D|X3BGxXdfw=;p#G6{Xl+jO^Wv-GzYm~Zu|LAh3D-d%AJEVippfnA#$nOd9#>{V2 zYJy}36sR-ob>TdhI;~zxhy%3v8{*2oq1ICGHzWnBuM>nO5$~UYD36&u)ANn6kKzvg9hs0w0)| z^nmRuCIv|=Y~7=#E32nN6*{@o!y@^rr+ub#L~gb=+NS{N2ndlii|g^F2*z54Ab(6l zH4}9uoh0x(!2f!$p(Z4}bx?JgdALCTRm6WsdYt$NXlM}KdbWV?|YrCcgkDerE z5syVjYCJWZUb!SPdYUkeWyQ|~*vxUHrgSJ-HK9&p*Cu4l1*1sTmGl@J-G6FdI zR(85Dxy=xf>d>x0i5=d2)2;Sd@|Lzb}NpF0SbjOhG_e*B@^b+||??o`-2tOaX(oRxiHOowV40J5qT*#16Hy zUPzUu&>i0Gp0vB#+iEET#j4BVn(hgJd~JBjCQ9h(BF*$zqth6tG#|33`OeOXFO$f| z^r~`BN;^9i*P|LhLVv)SYq;bP(AZ84Pp8aeOaDU)G_=Hz7iF2`H7~*^q=my`*n0Hf z(I?S^N6~|aYM7Ul2l=F(?y;9{4&!jKsCtTg*paleOs#v7(>B=xl-n2!2EZTvfPgQa zggwJNw^RMr>y(zbDNrE5qi_+)`x;l*zMV{3vgV1ozt7dlbbsGJ&9?`4=vg?zeO>bg z_ixg-BdO2pTmX3RjT8iYXqFLs$cLSs4j*<+&Kttl#jYc<)J3RuAR#cz6y6L98NSs` znhQ>J2F-)0z3my?v59;*i$F%GMO(nO{N}-AyA5s$k`dBnO{mKkl9$Tqn|rC}F2ENW z_hth(0b+3htAC&^2o6SaKyz9h{bk0aDnO(o2U=)k{e=lKZ*2wHx6MfZv11-Scp$|cL-3>Q^eBd0d0TibQ zOkoVpjekYaAYyx}CTI0DV!&Gqf)~8>tohYh15Wc70IOdVz|YgWO9@#ls^8`+vMh!P zHlv^yZ4`4T%D3`Ygz}?|ZM3sI<>&@w5}*eB*~#M}5CBR0&}#l0%XyG(EWcCxAOs_L zl6WQHeZ{ZK^F?jqbNx=@0B(>b>g`!550phwvwzQz0wJA>GI%piCR7){&+Ox^VczvN zK-c4qg!c}Fc`MO6kaLO?E<-P)#`_Kkwo=uI){Pus zfqx1oB2Vte*IoLH!|fUX57pT14APxS&JZ6rAV=1}vknuEN{t6}nLwtltcEh2x?k@S zUjy6wd|gEjn#-8*574BMLhwZITiHE+4*nbWdbrWL04u&eC`@TliqQOA73l;m<}5JR zSyYW9djaUn*N;_~#Uh)SOF$ZOY4_%ULVxPnbzG_HoSLoA7rDP&yK_17S&J&KAj;w6 z^JuN*qQ$%DME2r*Z$N|?XXGLJzJj)jHKL&f;g-A>=a$1p=(W5%o{$q(8oV{X@O#n2 z<{WY}hD42xKV1{{%&qzP9|nK;!ynA8`K9~UAO7$Q<0X6QC-d6%fKpiqUlU^44}axz zwYv(u{x^GUzA4}U7t&I8(%LN>5=)0i909>yfyGHHT_>8%lzy-MQS!#fyu^<5SB#IN zJ1&YkqD#?Jit~w&JCGL_7#WmprurLPcWTma-gWC;a4W25ffkq`7VKB(f$QGn>7N#S zr$RUqdYH-zC3FvUNhYL?kN=&NdVhp|W7M0&8}tDmIt=u(=SjKCYD$J7C)czK{k>#?m*{)fTtY68F7g; zucQo+@FM?*F!^B$KJ&nty0YwtT>>KV4a8?ZM0-K8IYg-A5h0u*r)R-}%zvOsJgfA2 zVs9Q6h`=h{d~7_{{4H=zV=-ETo-}8YBw#;kxPpB$w0ExBF4b=U3kx~%6yqlo>8w^1TM@a0i|y;nBF=Ud9E!7`$IwX= zwl|-bMLfRbd8sy2O48h@L4TZe_lkG5)|kgbzGQ@&0`EA2c{Y{%G_dL!mV;=3gIi1( zLUb9Ib8>2Dk;-lRPlw*ymASY4r)zp40~J1aTci4D7c}dNG?Gyb@kctcf}LrAli=PD zN0kWxpk*;Hv5v(nHyq@(MB6@xC?zGZH@q*mJR17qed8RWGh0B!IDZUbkC79c?bVA4 z5!36-8=5qoR()U1()YqLsqzrdn7;Liq%HjsqEOsAK1mHsHge|5R2 zX<;}YnA9EXcAg&ZLXot>O3U-)@P-ygKu3p~N!>ez?R_0nrGr47uDUPzM?+K1Gjepm zz2~DI+iM&HOH4$aI)C5ZNe@hmstXRspQ!>!>*d&coRX#J-uWN=OX7q1@COMt_wm|DJ{1_m7@ijpHJ(3cYj4jVX)A zoL%l0**fzwnWc*vvCz0jRbx0m-8D~F;}3LnXGvT!^(~!Z>VGb^WIZhNgj>_*DO+4snLJhUKfxias5PT8mICqv7>=P%MMsR%1WK_vKI4Bnnl9Q1oK><0s( zz&9vjh~`Qm>FlN8nc66>MUhV}Ho=~wzJcs9gA4(R=o+XPl4wQLaY>n4k+L`^1ES|l zaCamUD@(+z7k_Bo=mzC2)qEbsIX{r3iyml7Jq*@VVOfV-rz0ShmUp0piY<;iMZN}2 z<&``Z1cA{Bsw3$b*AIIf_;Rr?4p;FFMjaCoK;3jI8MfN#T(AtP+LvHGmxHd++=!%T z$+@@&X6!>;7RUo63K_4~^<7ve?-D15j_eI@2G5HNw}1O&LdyqWF!6-#B4+atKIGk^ z=R)l<4q28V0P9HH{5XVcA@6&Opsh@*d6Bc9ObFQj_%0CK`Nrt3!_(%x6>h@8p2!q1 zbJ;4oHrKZ$Ty2ah!@*o!2$hu1(JHbwI-~5-)X&le2h<5MbX9Obn}tkiP`5h%Gj10R z2{_oeg@5|W>SI`I8XZDOLkG{xeTZLZOuC#Wofj65o@RXNF|G})pP5I!CPbFtWyTxC zpYgvN`C4xnhJR*iHeMy<%+xqf$gv}f>1BwN$$L1wi?P+|@}&TB5hO>rNKuxtZ?|rg zjxEBH4!>fDeWY-oF&mr+og%I>tVw>dKnB8&PJiH=OYGd_b#Y^25h_DIH%~9&v$(}- zMsN7@D~=lSSzN&;tsA2aG4*_5cx>1!G{i?O^Hud}vXsh=RRE65gynmM&*oljbOMP- z;yV0pfKEEiY?C@J^mpbOh_9tKe_EttVpJ@Zf`uhNOI;G*FtOXApV@cEpWCxiDaT|n z_kZ)dF$hdJ0q)H2wuCQ@;iR57Dh=fGV!VLZN26yKi5`an&;A91es}p#OZ3Ug zdnyv2x||5YDu&T(!bbvF0$aW1$u1Tn8lV2~F@(V5S@ek6xW!~DD9LTmzFhS-rKKW9 zD(!81oI+_{TqRm~1_6AsljU;ggd-gCEq_(bVb*mPx+?<`jYY;@G);U*$Y#eStmd*4 z)gId^Es9T91fe=GVg&qSH_L*fCqn{XRtkh!otR?!HJU%l0 znKO2jXr63@-*r@FuBF4FZJf>T>?%ZrwJuJ#(dxT4E*zBM&>x15CMr?O2CbA6=6}}w zdy(emU7AmxTr9GzSWtuxZGMqAVT=Mm_6KEL#92~}lP&vkU>*z~Y!904vI+g~oYpHE z9}ji!Kk;gEgf#dw0N@3AmN4e&CT?&Ks#Z|N^bcFr8xiL9t-?E?#e?$$)OUJzY=Bkl z7^@b|mah^2Cmg2@SpxwFwddx>sDDp@*zEh#6WcCh6xL+(Yw`gTLB)n7epG?*l~LS7 zqS&hLz~*=2NHzL$3->sKijpireB4O~#hxwTCneakwS@F~6}knf+H-M6CYsfVwtVjL zHfc|&bpc~a2m4lte`}HT31-o8^^r)G&M1OOUjHYj>?0DDUc$cDLI~5~(|`1agcetq z5XvN9L^H-ui?o5|{WYvYY9T?+07Vs&0P@CMK>=tXX{`0A7Gt-ALCP#^u{GUi$Ox;s|gC({%v7OMx^ zfJx74fLn?kiYiD)OM|K3rn4Q^Gjjk8ZJk^!GDgJEid(=wkY1!7%YXkS+;|PnTf{hD z#f&F013XeZ;una?slCmQr`iDxW$}^;?U)h90aENn>gBYHV7$OF9~|70-JN1E7OB{U zMN}+m2mb&G9nqG03i6LmlgC|YlH`2=x0}_!snV^ua9TZQtzNFV3alv?SV-u0j9peJ zy|299JOg$gwV$u^`F}_ZeV?i_r+dc8wlVheSE9f(+?Zq0&%`S%ypB)PzjXE?!U z8?otybeR9Rym!m(HFq~LlWY@N)a$y|FGmkVn}n!mu%!gui2K zB;q#3mu2B~VJs%${V97&jmQA2hzW`pvc?FG@Zy5vT7+h%(0`~tzHykvO*ca8*o8%G zG%$VyvC-UswamiJkTBFUY^O3+e;=SYh~FqM_pVEo*G7z!#mT?&mono0^)LSm)<5z= zVsp0;v8MUdGua|&&$T@eq~*e?&m<;T2Q&~%ZN=@@QDyDq4Qj4t$SwiE>MPif6;@dI zvVT@L&Cp^^)_-tbx&UD*g!$3FxtvkilG5GPrW~9>4TQ_b!O8rS+LNv4)$&+h4<8vQ zmwACPWX|Id4tKN*_*EkjB8B<+__`8usxU&>!$+F1<&CMgQe1jq8BX)mVdR7mp7JrmvlqlX*l+I@ z0bHBLW99Zg5HIfEIL5M=Ex(e{w_KX|ytpDo%XtEp0QQLT4oMi zyiT|Lk7?ai`A$~HCbS;E`t<)&0-bf@mi=oy*MA9ZwrWTlGUC4mbyi`%bGmLV zI*Z>y3TksV`p(X?WQ+?r%#JG8E#QRwMvz~Is3hTl?jwj+y>Uf3`?m!3<^nE=Srk_+ zhJQ&e*1TZyj7F%lW`H$lie_<6xgp`Qf*4`3c>b)F-{Syxrp*9@=JB(gvO>K>C;Ja< z)KrV?x^_nq=hm<~9?@GApxB0f#JByt4&FWL4J`OTHW`w9$jr3~fn&x=iKSQb3*d

ar3qKKi1(zqDFlS5E8)nxQfQI)5dzo?(&+CZ%Sx3NWAufq)^9CxKh;Km+Fx zI)q!^83C|=L9%K+grNi1Q4*$WA~djva

9IWT8spF&pcZqa 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%0D@LZt& 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

GjvxE@s;o#g> zM>%CenRGaXtr4e_O-@5ruOherOf(1{zSdm2uUnsj*MDfqU|4xv?A}pCrNV-f{;9sn z5aM8d&a3I_d^$zGHsq;S&juL`=F8S0i7_m}b8dimfmli+qaaQv6|$U`l7i#`$`GVD zd|sL6dC+q9@7@g$|7YIMvZ-bsXaIqirg$rBZ>Il}JYxqlBH-mBa19$@HWYT@X>q($@{{W^Viy#M56{{Yab zlb5aqzhDVr4Uvj}2xU5Sr{j<`!# z%APv)k~FGPQJf9XZbexjLS4IF>d7R$h`*tl&a)&QLPF2xNetVDkOEE%2cWyk^>7gp ze1DrRHjU8;F~#u8xz6cT5gA{&(&Ds1#vlGVj|(C0jYcNXgjAqaTM_UNi}$+<`UJg4 z4~G$jq&OlJofmU)arKA#4bkaSXKxDl>~;7EjEKE-FEJ@k4|}BS5PS2|7?f5XcxNx+rkahgl1F zAtxIY7H;p3rGwfY}phvB?;r^pXHR}(^6zixhGex`;25?M^Vt?${ z+~v3S)QP*r>*y?uZuNJY9!@uwFVY8Kv~Q00-1`^Q*8XqNgs-;63I<bslFSYL$W}0^4TP72BIFwx+a&5<1OQ&COeI z$;!ZHB$tu>NuIjEB^VFSqKg=yF24`!w~N_FktE88B)PkkQ`us&A8~~MV7CVgjtJxc z15tZ1ATfLsm|^~`8IQBv>#eu?ckCHxd-)>$QWwBWq|Ft_KKCH7Xc2AVxqt1oXPTX#wjn!2ODqsVz~)6B zSfB%1w2pVciJ}S^tyQu_HG>bZK03jhEBWq5RQVRJ5O zb8l|cz1wme$F(+izn>z1$od7qUEMs0vJFvmfFLB{7b(&JDA^leu(P`o-L+9&)vl}p z2$_!1)!a_RjIZWu9%G(IFEFn#@vXJ;P}S8SK#|^>9kDH4=dO4TWkH}Ka|>- zmPKKvby?Ys9d+^_N-6aZ`d_6s3cWBJJ8I)BE6Sx!=FKEIZ){y|4BQjTs$80?&J2F- zey7w%s%yRHMn1k;(lFn(ek)HMl}$CJujh5Wv^%5GGS^cxFZ0w?L!)io*n2~I?eH=y z((=*{3saB2ZGR^5P+4kgs7Z+bwi{RcBNC`0B^9I=4$bH3w-tAyeo{Zqkh%RacF1a~Zs2 z=-uV=ps?9&Ufaj?$A=#C&{*2=4>53iA3o5?FY>ZJnt$rLHr1~l=Ub!egBp>|@0C?$a$RR-@$P}?zpws7Ua@grl$W_lXXcqw-Ck}Q}o1(@~K2bD7<$k2%ADtGb#nE(b(k3^lsIbajihfAnm^YcNtD?cy z=YLC6(DOWAJ+I1UHdoU!H3Mav>0D{6USxS*UaHOUi-V`b13Wn1!d{OTx?bjGooACF z{eC>aRHtQemQ@Rt)!6FF=v21j^PxI4)3Qp{MB8kt7N*va89Qz@Wwp@tKuxY{LvtLc z%Pg(u12s3;-~p{B3sp#g8$Kxe^cv_rQ<$@?G&n7Bc(3ZT= z^<2Jraq!fAN`!!4(~Dl?H|i^TcJp*&s+W42)mKSfnIau7i`nVM79P&d=<MPd@xg-MPW*Gpo#ESzqY@sQt|*4KPL@qazPRPJm1 z2(D##0DrZ zI?s31Kiqz~b6i$gQE$3Wx9D=<^Ox2raPkYCo1!NE%8DsnJr)XiHmP(a_uevl66TrN zmTXW@N}^;4l#3M!r6D|f#D9{z!K`HCk3>Dord4Unvsyhhx+(_hgj8Wju-%`U%BZ8m zeYHC?Mg3~ispL7H94_21htqN~GDXtZk;YF(wlayvPevr(wgyU1r^Z^7s(W|teUaRG zkleY4HB6g@DQc@o2~VvdtVuA-Bnv~odx1et)4>mfyAmVH%7XcCT3!};$>Pq76Q|p(S+i4`L}wyK z@Bvn7oi3KpxbI$|{{c-TK0+I7LWQoIO6N(gi&+Di4b^CPTC8Y{&Parm8ZC5nj?D>A zv26iifrmyft*Pv2Qh%Ac9@%O-I;+n|Vx@v$&NKeFHj8DhYh$C8R%V(ljdhRDo5{#4 z!J~Jmxok=f`c>pq_9n@S)Vx`*6@Q%-&zF`6`#h_|u_-?d<%Uu;6z=WuJhRcqeBYI zT&VH2dp9PYwFE(%6l4%q_MLm^YiOB#mewne<4IPG^m3VBCFV_CX*;y@v1471;#5{# zm;!6U7jMJoZ`F&YT9($Rx2MJ1BuVK1@yPi4(;Ta}>iZSb0edLs2GsSg!I2eR$}gLG z*}!n%cdk$YUVn2y$5WoY<7C`#Sp)As3Cz!Lr!aOalXr7CtIrdjR$}X`+{i4B<{D;& z(BHApA3vz*K^om)TE)~P6FogA23F`|n(3UiX{V?ybfIU4j=r?l*2V;8uT4l?cj}ss65w$6%HWd$}(hPf6R#(cFoujwlsfwnp z%EBniS4Lzr&jNEhIHQ+@tIG^nJOyrT8Jo(yVt?VGJo$mDp$Wi>gS;%{WBz59XZ4k* z-?GB@WJh$Fc#n2>=oyUc1{1!fa?TSr^zEJ}8QiP<(w zY@UItBJ0DTZEG|L+!?r~@T(QZhTFVW#pqDGvr}ql7oJy<86pZ@ zF@IaRAtf~H3uEhS#xk;_01DySp*o%$_`i6bo2P^ZKgFmBUO1pLUf=eO&!fbJf8*JesC1BFVm!8Dv(3ENXbXEC~Jtf zy3&QPKwN-X7GUQ5Wnd6f z7IzT8G;5M;b6usTU{_kAUNm;j6RJxl2l)494cPb@4lt---l$&UH}ZJ1v|!DPi1&qG zsHVt`W#zlErc&n3GS8-2onI-s8-GlLa0bG4SksKiW!feiFQsTklS&uU`MUWMQ{+cz zIKHo~=f276Z<|R_J_a#0&rQBG6>S$-8GJB7_l%YnkzTYh@Fky{f)wBJEUSg$pxz`+ zm5&E%nnO^&Jba2{oSQsX7rG)hxp?$(N6d6yf+U1;m9Azi4QO7$Sa$4_b$@g^Pg7aa z>)0N3)7gBndu+F8?6b0(WNB&&KW%pR4cvYYl&#Ck48T+HaaoZY1tZXb1@3uZ4464UfQO^y$tEtzPM{W{W66qzMS+z8k%`EhUh-V7ZZYthG$#v!);gV|cnD8X!0w*5~mo zF=Z|dbZ(f~bJMej0bMh|6ItcyC~^Z6qaq)?c>_ll>3FdwTQ$W{9ko>?Q`FVfvdoH_ zufOPv;3#U`-NW%fjk{Zg&koHpzd9~Ek77>aZ%k_hJAWRkT}*@wWELs5rWjjR&&!4k zGw6DLZzymVNwJnZAQqmT#kVRv>4%`uCei5j_K*H1>}+obY3q;J@1UMS8zU*aG!^gN zF&W!@JbrW--u~C5F_H$qx_OxTvNCYNxuI4r{<^_dc0C>}5{lrcH$JzZntoI1<$R#V z=~bZ@*?;t)xG2x@t4d$0OEa05C4_2OMZ3HE;=ro^0!5)}NiHS-*JR z`i@F80OQM`Sc^v*0a2!FkP&-i23S09p|1M~02jG6Bu7nX$0}2U;j%8Lb8tpnX#ZR2 zHOy)c&gAGLxJQQ?!&1a2?Pjz}otafoVKrM2(0?j=C`K3Q2>ROU@spZSKrDmr2l}bu zYN$ni##@GoE|$5eIqo0LseMnpQYPvoPnQC6H0R7hCmmovn|fYWkQ0OU?qX{7+*Fqc zj5dXBNaa3j@_~XwMc@SXe1rqUOHJx^?$nUH1W|#t=Kg@?xcmSv&gE|+rqMlDx%5XQ z(tp8xUywzZ;c|)s@lJ0Jx&U`7WHm z8ROT9pK(HO8;feC?7X~$ke||{d(faZx5o6wfB~Y9{ebRT`B>uJVMn@>u10f>wg-1R zRr3t?8^yWY#^_Yd%cEo8D|ggRAOF@qKfL7gp(t@UE*_Ao1K4S!v= zWS=g3ht=W!(Xoqwbj}Z?2j>=IPVr1(Iga6J((HtxW2gOs zzeUcN{ku=_=KVLzysS(`yE%+j=b=;$rKZSRNiACv2D6K;QROs;{gn z^Av|&m`nINJS!24*3f1E*+dl9;x@8O{wkqip;o6^@IgES@4_X|vnjho=~+jNmA*`f z3du9tLuWCKzyanN118cGWI~H)sWJ}h$WfHuqi44gl#DQasE)vgRce_nO@E#hCSHbU zBkQg;8&M?l!VWV6P*vrn9nc?Ie0F4<@M^7E0LoU+brGG!&_yDuS^^h=w8)LIN?h2O zvl4E{q;WS>E)Ddhk}jtXXGuKHuhj9mVdt$~S|zjuh8Q0o?tXu?yLWu>{QINV|G9to z{Pp4UACExIdRCN#m`n{Es(%x5cjV>eib#qWe01y2vI5aUFBjniH7$Y>HV%@Bg#x%Z z<2k^cJspruLebQ9q`(44LpAlQWjhGi&7>+Xee`%m+>GmTnUKs+>S(X{l<*xpfheNU zexNdS1Ft(>&a5^S9OpH8xW;}zUmxxtzdZbY|H-(I-7{yVnVx~^Ie%&+?ghW{Sq8OE zT)hz7dU{SVgD{hXkk7)S0j`8Z?BHtE?&?msP@RA~UCdkHsB9}^TMWl7ic&3`YC6{z zkqo*^UE0D8NvjgTNsL0cS*+$AyuD|y$e8e2AFDcKAUG+q)D=0OaSvI;UGPmeU>q+7j+B-;xt#>H9ZfwjG;(1^uW~_lcYk{)Lv^Sx)mfA02`Or# z#F-jS4bi*mswo0`zIBgxR|5E?=&_cRR#~1W2#4|p5juTLp0C6dRfbZ6aQ<|N1X4_YeQ}`f&f~<^iPOgJb#AA-RG60>LjzOY?kZ4uCJD@ zA9Iv|`Kp)sLYwEAlJaTF!$?#8ZS95>kJj^9m(>M2GxDFyp!wSr8dGfd&%1lks!2s)`%cXM}> zN%WuPTGVr~N5$^}ybU?g!{6C#1|ceve;_(zn;uJ3C}F_DT;~P|Ua&|#GxFi2NoOYh z6qHh4B4mChlMxmge_4g!@sUH*pez&)9zgnGhf-CQFmAk0#CG{7wwkaGxzR-g`eY6` zM>vblJAec+QC4oRV2-2)V*@|2Xq&!5$ZFB#b+#lUp0yYFV6&2<7v-{H*3nfx2Ep$T z>_X@pkv$r_AL$&*%I&>lR|4|uZh{i4!8Q{HNRWh@WO+{Re=wv51tcReM8_JAThYP@ zBWvdrMwnHaTpNboX<=2Dmqk!t-Na;6!3Vl!eA`SI^ARXLxy(|tIvu$bl8QFPHC>o0 zDKCLvY`%0{YcH3 znIhYY3D-7fe`nb=GsRSNHTFQa=N&Cd@}ayfOK+1Pj8~Mif()YI+VK||0*F)&Sv_$c zp+7on_v8v}mOY*f4dmPub&-{vNlB*qb<4HUz-l4 z&&p?`zm8u549R7-WJv~h|9V= zsYqPO{3NlHMKF>uMX))3`4DC>!oIPv9gu!Te@5`YM}ldOXmyW<>akFJq@Fn0AHW^0 z!>`M5_77>85s2iGV|#?XWS*sqkm>voN5XgEk&i|9SfMX>k4M6$l3+YU(U2o%M9c_S za8)L482%_5G>BkRK%&?HQS@j|QQhtj<#xDye~v*qIG;Sd>S)qGL0-BCgVlDr@v+$k#FqQr0xn?eXXI{?zXLI&5k0lDXt#xl z+Al25Kd{b~je~+JnpB^$XP;iS}A;>VOC|Scrm=R>r%VkyS={($u&xh(Se+2T{ zdwSqOj@MoW#)L8Uiw}oX-Yza|?7_ZFMnW(S@fA?lt4nMVx_{+ZnKw1(wi1C0un*** zb68WIH(W=W-Z8sE0k}3+)<{6G=(1er7+G1rN)kfqV7d=0Gt0{2kvK>lV$L&+rZ)0Q zhL9mu1pZo4jh$HEdwM{G_O<-1e=>9I$A$Z`;~Iq636hc5SP9L`y>ptku*ChNV}kkl znAk<8S9XwIzE>8OV3L{(RA>z~H)owVyX zZuia{wfS`5EE7{-8hM?Z&UIIWZgp$z0Gt-JezWcxydbBI8Yhzbr2fmouY_?}lGDb? zt0RvPLynyg8YhVe+HhQNe}Fr3S1?gOV%Pk)h=&*iv)C79!G(cRF*!WlxuEXZYazf^ z_YQTsaq?>T51hyj{%4@FbSF#ydAc#)qBrdl(=LpK!qPV%UXwfcgtpzJox@(mgb18H z4hT2~P7W>zLpaYAZ!l$Bd3+5god}P1axlx%|Q--e}$+|H@*&!F(76~ zFbX^BA%?)rAE`vqb2y)2YH{Al6T7b4mAK#$(aeu@310 z_&8*?WiGRtGcsr{NFim57cvFGW|N;KbE9F&vRcws8~Q-jf#zJ?ZjDAiF>`&9m6fOE zxh_&<(SWm&iz8=z)F+>)KMX}+M3MPEGNtksQBD^>4&IeFe-`X|gAwgcA4F`rrM|{? zS7dDMKKZK~VugdkM;J*nH=OrLdjpF=Nz*cK78Fm`wMxt4GuZP0vl7G3_;nY6REtH1 znZ*2*v`%>-@eASPvzt-n6j4K&GVdfK&F~6VN|Cn~$0itq>f9vqa$yCH z`%0GytJ$KFe~oC;@%AvDY_Zfe4BHqoh z^_U{vbjkaIjY7CB-;pU&0z%t>J{!A0$3vmcM?ED3e=qKi@J5bwFyvu$aWDRiv&bWe z+%-lIwwhF3M-H&KDS0at$@0$MDD1ZqMQmAT3qtf`=R1ZsJJ~APFiy@dl%BFH z9@Dt2O7f5*cSbiUJb;W1>)Tp#1uk=4n6RTmwa5FXULGDuax_XtxO9S*wc>~e>T;e< zDPM|+e`cX`h-ptu$Q7f^CBA(C3BdHZ!FhOi4ExNopIip%ytHc#<(`DOh=aue*vK!Z z#@(Wq;|K#x7Kg5NUd~oymFq*GZl^dvMX^w_6CLWody=G_gTO1a!z6l(XC-tvX4YeewM0 zSpBb~=ilQJuiV50XZ5J>VAVLC$YiD#P-!TiybF?1gHlVBtiypeWECpp)sdSGnP06s zN#Q0@(Tqq=uHhdaE{dv`885HR0so9DfM59^Bxib3Wz$;@DF?M~tQFiex$#=?XfiOO zf7DN=e%4&l1dtIjnTV}K>Ez+Mu;q!{}X8}jcVe22a^={O#W2u&BgGakwEBIq6I0Zyz?wZ%saRX%Uj zQH?x+Dt*2GdHVX|frFH_)_ZACz_!EUf7k7n$+MY@f1uot6mSfcF2Xu_qTapdvo4(! zNV78>^5jZh#v3k06@uRl*tj2_QSC$lYl%G{-n1v46--b9;=w4OKv6(uM)l76)+ii+ zhC*#TTCP-`=`PKyG!eb5 zZx$CE6&kxF*d(WV5T|l033G@8e^*%nLfw7x*AdU7dl4A?+Oy5#@^fhkj(h(QF0XB> zGacA=h~?w_cKQzX9cRkkjKgQ%)3>9>-|Qc&QOkcm`bYfdLHf^;8^?}1yFPNKZ%6-d z|NQ63o;UW-dYL7nU4M1&&b`l*JD(?a@ADL1l$WL=7uAmQ;?ZzN=Z#8^e_AhB597%s zS^7vNPggyv@VG`dQjU@c$JNzX!*X~}xTedK?{?Ifp4)d$W;^`G)JNw?Rv)P`{_z?G zg~q`(do3Xf3AviJzgj#mv2zp@7%fV8QbzhGR%=ExQz!Z-`nNrASiI_=mNvQjVEABo z=UpSGWetT0Vw%-1w^QOce-`D5{@1(U?QmvlI&OJgQ<;QEde{57&JHP?M)=lt)<{~Q_i`c&h8u?(Z17x$~paYY4Z0W|he|7A~%51z64~zt- z4GE*|0wTa(Tw+igQ_pxm791pyzSdl)Dt=jnn`UFnNsZoVjoKf*zPS7P9zJKlb#TG7 zK=J~hTo_FrUy&maDvqPF+j8Pcj*{1kWUzqe#V(8B^U%=IYku$2MuCzP*D8rJ$$ZE#C7M44x}gweYVjef_!;pfme}&4~@5uGp0x&nqOrVMg z2yHNALQck)WfO!nrYlfgn*k`!wc2*`TncK5s=KxdRzSa`#x4(cu&rgI8dzID!6ge%fkxZTI@$OY$81w#;CA}>7lQS6$R zfWg~VP$$IlAffY%m7*wI{<&UR*Q_EsFUl3)^w8L_G9p?Zw} zL$Qfs7KN-V58WwFz#IH0+2U~LNxqRv%?ac_caLKtf9?7zu7cxwjfsl}zDK!WQ>3k` zl=l6`A^H1$Kkci_{GN+x*FOHu))stMvA}C94PINw^tP3X!(aim>&RejML}P!iR(g` zSd|=*|J9{F*oQ zpHDZof4A{NegbzkE!6>+Godf#+Jw@sJ&Sx%WyrdQ$VSy2s)z>Ycx{%%(aQ>UqqOIU zdrSyMA&wS^D}ZHg8;V6KK{1TnwmNrgZ~qWiOW)oO#SKDH4rv6luG(q0bi{v{A9h?W8cyqg{va!=CNFr;( zC?qZanOvJFW-fZOY&sX$*xvqzl1n1ke;jCM4*jKS3ese~6T5@d^v4S|E7b22Eo!Cm z@bkydgEGbmTQ1MIVu*(K2dtbu@jN~(;_SpuXyV9-Km`Q)Jc-h}JYX@SWux~6oD`f2 zL)Mm*$T-WWo^mi`R^ER2cz2KJT)y!q=@NKA>6|0L>6_zkv)LR+1R*OKG526wWfSzLK%OFJ(zpe5NRy^Hep+6R39fUC zDbTBWr{VaPh>4z-8m>NG=aR)0yGfY2%0zS$EJ-?C&PyE3gc`%q#9D$$Lfu3uQVu(= z$kSzkt)o7sOw~+uL|8D;hj1cF)h0Fe=KluoS~qV zD?l9n4s%a4_zqa^o^FsVzVhPxbi>PHsvF?60jFDlJSHV|ed|>Qn59z3DPo`wBgmjo zofX_OExB%`Qa9Dd@q835l;`iOjxJe@d0gzA&zSQyE73mW0V`s@?_Qf4Cq~ya@8rLw*E*Waq{|&ZfwKcE$+7E@Cb)_SUfk;9yYd zf?8%oC2FDelJi~;jQ9&Mv~iJE^s15zmYPbgo3E>g`v+B__X@L{Pp9n0xI07vO*ujC zU$prgSw}|Q|Kfo=+byW__wXnxdbKHLGn^isK0V9Ik^EZdx7JUO;ETFwHFD{&EB zZU#p#gqMdXQd2IVkre1c<8LL+Yr*B>%CWmPz(|gysk6G zj#DkbW-sRkuIO7-e|w{zUO+nG8s+`1WDm{e|+s!4Hl_9QU9i)~jP?n9f_kf^|SuWjR00N<#M%oQ5=~yE7 zsNFJ@gHFMw@%%1AZv1E_BYBMCq2#+8-)4kescT5YKuLDHe<2OLJDw0K+`SH#O)A$a zyX`6Ocht-v!sw7<&wxu`>`F*()kRFYbZ!WN1;;*+s2EwfFg5uf^X!}roJW9*11DRp z?;69X5e$gRjNh9#^^V%SyS3h1z-miV06G$DMe31o)kmtW4Z(>Z>IEU|Tm6uHwTsPr zTWU8=1CQR`e)aRqLYC?Z8w9>ERGas=+;92gPKKy& zLM8nr9SvOKatuG3-xQNe#2@f}BRKw$koxd`W0ZU-C{n?j`@T-#I%$>(GvZ%8)~ZAK zH|mDH-jjN*6ZRUJwZ;Yej>b;(>uX!Star!~q!RH&e=gh2S!Wwn^G`nUjjLP~XU7Zss5PYH_}*aM%`Z`6aOKhM?XGMW-bP!~4vK`5yTp*X z(tmrKe&c4|wrX5U8)k))m(c;aui2Dn3n=eL>Q55J-bvpU8b-W1Kw?qcH^@fSs`l*R ztD#VVe`}rBQk!W1B#VFwcb8{U_`hAVhqN3QPIvhNadqp};^e(mw_U3qDp2pdgYd$H zE`^pR;cAloX3KQ{H`nMUg}GCro79WKWTe=>t4=pgC0Uw^e9Ej7djKb@yC@l_RnL16 zO8Ag==N$HYs<%~FLB9|Nw<`CI+lI;wC@1Zbe<9<*EA_ABMn&N$i*mKt_nHl22Md1m zuJYi0MYr2^!1sDLi#+J$XhgF0xw)?Lx8oahCu7DTeCv_`I4(ms+NA4>g0qve&DMSO zZu@1c=C&`J`@u?iOLh6{O_EO(Md_eTidwbTf6thZNSSlyqlijr1W)xrtorttQk&d3 zf2&v9=PkDEH_SW4?z??IiMCeQ$!d=qm=;~X8OsUh+=(34Q4l2tAozh+>G!>cdMU|U zT=(0jPS)iTl^<&D^T+sO?%aZOKuV(M>k;81Ze-AO2vSO@)>+ZOnwpjc;#N^HWoank zbBHwe@u+*;Y*Y=Tgqb8v&+ptvD1v)wMa5<1Z6F4StZ$ExUxZF(wPUwVlKI64qSX_4UOhUJe~Ym> z->Lw6{cB(d_;T)4P#Z}QQkO}t>RF{{&b`V^v&+D}q25+#V+I7K**A+A%`Q<#7Kwdo`4j*;qB^fw6vb$oP-w9x%7h1*Y^8x zI&D^D+yxDH($ml%+>qf%o3;BI7!_LkiIlZ}|(=;x(f6nNDR$_f5 z75n-8@U-}Y)3e{*#)s;u5$>~PZFpTIs=?s;J_X|9SORv@^{n*x!=I?WCV#V{4}Z?6zu_DV9YS`96Cu%d?LCBbXFj(lH`MbWydUxEn5#V zsmcaz6Xzvi1R1U=2zc~*f2O)+=s5kRAF;{*B{X51mzPe%C9=dwRD-W=VYZD*FD%{? zQS~?Fa)4ZVCHLPVFf+GhU)5g7h-&wMTBo@J&M9q(-l4^F0xT=4k<}5xdTrM`>C0=> zd`3pJA`UIuU7=WBx!V)+BgRQ|9*4P>2fW{o+=!!GvoCJ>Jv(zle|Gggdv#E7;C6~4 z`U7dQ-4os+CjuoZo@YzkL1d9rF_;M|!O@mKX#nE^clHEttfY{ID_QNamDDkXu9 z4&M3xgI>O+j!95`gS>1Qw}}z)oM^)cpA6L#Dg`ZtDSBW9%c}e@GlfQYZVdW}ki*<* z!yxt@vk&ZvL8wm4>Fhe`=FQ+VYAGC#UJ@w5jwI zAV=W%#hb=^@b^Z;MB{{mDx1M_siE;u?MpK;yDSUzQ7SIV9EnWPJQ(IL zcvn|RuG3q#6F2bMjHiOE5DXMU;m8F+6~O3-x!X4DJx+PpcO6XVL~+ucY!_lvJb#Qw z_zmhD=3XAMf7YVZVOA1Rk(IgJ_BQ1NdFHphy@Tcxt|SbXS742K5S5C}q`ll!=Tju- z!90RKx-^xP1|gucrl8pNw(HL>DH8mWmxoUW9$7;r!MHN3yqgCN)rEZbUHGHFe!lne zNZlRYp~p`*+~>PTd+LijUxW{Y2EVTK!jO-^wd39Qe+fXQ$}ar0j^+f>Wks~fHP?Ti zWmC>;VcnT)sY;4W(ZC@tE?n$^fVjwm0XM1676bZ%bCL8FBA+3nj1FQv9-kK9m$lhp zA1T1^3qpV)`w+EH%R-%KYnufznpZ=$%V*B$R$s9Fq+JG=S;VWMyy3KPg*V6(PKi+R zrh&WRe=ZX|yv+5lA-o(ogr3$z^;A#LnuENX5G1k^?5#lSOo|@y^9ZcoX2i6*)^C) zm}+uPq>V*=sEH}2bI3DkTIJIs13DU~6zT%{e-wjOJL0y<1FzK{MOmiQZ8uR8|B9>c za2RHaDp-q2$z2#YK2|oCc!61J$_Yd(k>A}N+`Iqz;K3Jv82<53W6G;U=5L~Nz=`}= zt{4{;?0`w)irWB1Cmp6!GtE%9njpe#-4jRVRK?AEBpA5eupOv7+}%Xjo1{A$OP34K zf2JIeB;Vf~3;1sIZ1k9GNxuOsjq>~oYUIIO8k~KgIEEcT1#Uz_GaO!QoJbE%v`!5d% z%GA^0mOHu^rb35AQclTd0;XZt9^|KTe}X$|eD}fd{-s_Z2F64k8=p)N7DHI@0lE25i3`z zC8#=*4EfB|NV0t^_pHXDVb*UI<@ba?e~{Iy&EIXc{`_>SWsFDJlRbZ5`xoYOa!{Ma zEA>|W?yrNt{`If%KYl+-;(z~jfB4r=*)~bkV{|{P%UVkrFxyP{FG|bxuF4jw8hPHL z7A?t^qFc){liU|b*hDtfg4{wFZp-&VJku8?qx2nB@Qa(G@0%za+Gpzclc)Pccd2YF z_hZMks0_7QW8AbK6pqphgTO-j5&wX{e8p08^>TNn{sMo!Mf3!tuoe?!vbk+GK9`LTlHv?!<+`>f6d^(HueMW>ENaGWC zMcDO4B#Rth@n#Fe&)s_e|CC#OO}`L$fqcIT(hO*(q%jX9VNh|$^kove@ky45m{4+{dstu zD7CKngXaEA1J|2m;JcL!La&N-0>rnBz?w9l>5aNVxSo)d(a7Dv_}8v)hoh^|>LKd? zK&3+3O`>Eo_SQBg;r$?ZCpn!$O9)eF4B9P(-)@M~$`o5^WaP_iMYQGiS)W18;aW=I zV&q%{KLfvsTK*uhe_U!s^meG=s%q5KwB6LiV+Dfa&+THjRhQJf2$OVw8e7E)u=MYJZXspxea#kg0tG<-p*XgHOM%EM?5Q^4bbpg7ANMejIPRbGjTLAi)Fv!}&Lq-{(pqsiGTLy;0c zaKz#0O8k-R{Rs|sH}n&D22kJnP zqC76xcwsagbV>BhjygfQ>gbtCvj$^a%F7;;;m1uc{4msv@fDW>^4^Rcb%I)JY_Eoo z)k3F+o+YV1)63SAj;*sn&Dbo;wq^^`yHQ`Q5S>%`i5qHEZxJf{n!Jci$?k>+;RGAK z0%dv=f74Uu$y4Mrl2NpyPQG?({^(_}30{TQmS^gBCwhU~`ATh`1mpG9r(37Rg;gh! zwMh2!E1CwL%*vEbhiPnw&XnrRP(c6zAVq%878P`^4VyeVqcrUwzx^9q@`UI7@!Q>F zdXGyoQzy?|s`Lm%*;J(Ej}Td>yZ7p}V4~bne<$BVfO%ZSNJ&z#8mWWg0=Jr&$Vd=h zUfisnR8K(*=h|-NvycliPP3<50w@&$tf3QZ`b}XOvn45aKhCd^&sRIHtu|NgA~}6C zd%i_*jqUAk%S#^CGr3LSH6X6odWCYeMSzU$ZFl*$x7DV0D{ z+jc+x6=}_~WSppj4zd%^h0ub}($5WPo<#NxI-?~&Yjp3}fg7^t|oEIp_WYs3IwhHb@iUZ+8(H+U3^peQ) zbVCXP#`{EkTboKszba-g`*E7^kwv4_}~GDz^83DhXeaE8uGp-1Nt8HJxWvc#ob#Wz4+P zDSpefSqADQ;g4df9H6QAQ>M*nCtb*_Ql>dPwg8ol+ zB;Dk_$?3e9orU@&GsgRI_{o)~Bn92?6e&X0OcyAlb%P^vjhsTMe@jY{Ez9MO-!qk> z;x1>ugrX020O#BkZ{Qwk6pZ#W)+kzIARTves>2*jM4Cv^o>N8~Z;{izP-_srg{ID2 zVy!fy&MdF+ts{|OvBeHWXOF>obhRXs@-z}c3*ErNn$Oq`*+*6CEkoe_x}qi$A`@KY zUbkHEX;VOeM76$gea3U>W9=_ z<`wbk7-tfD)|?jQ8XQqnkeo8Q&g|J$AnfR-aN}@9$l=hLl{&ZB5~=?Wb-WI5Cca1< zW$*AC99cQd+#PUhp=%xA#86cVL1gxD(ehXMShQYW@hsZG^-G4RA-{{#NsU% ztYuah=c>XIe_zH|xI$pua*LU%E>bc`5SuOjIf6@3H&D`SPx`oR~rU zfK!!g&=dH&4wQVTQ(QH5oviVPf7{tZca`Xjh|0iAWvTGFS9YE) z2Xy1vS59bb=S7zqV;6?{H?j$W?Vwj8E6C2voY*+@ZJeQ8rjcACya8S=EiK#qD4e(! zznDu)%jLaBXojUiEu%sTd?zU_uiy(Oo6lCRb&X%t{ij-eJGg9H``!xmBJa zGxx;<*VSd`sjvRt)vN-h4enoCQ#s4kqv)IfA0Yr#K&!v)4G$euJg&W%NH}*%-EYr2 zO?@?V{C}uNMXOM1YX;ne5qbzQuENxU8721cLhB8VKA zt54Ne?ML7-q@Ql9y8;axf8C?>sjuKe7mz^E6L}1Jj8lJDafAB-yM7!NC2$aUkAkC=g)E($<=nbaOCKkbwOr=_Q^xTaV| z)Hp~&u#tC=ov1)lyE{#d;=)ZF1oGZ}ageaZM-d*po=JZ7odRF?U2QpVM3DuYP(@t2 zLt|B23kYFI`NUm{fTcjPZwQ4_Bu<*&0Dn$IH@1pK6fg<*A%NmcYF|G}jPwR>6H2L8 zlsNgtoljc?f<==1a=jfR=T15mhWwFQnZBi=>QbsI{johRhb^hPf6LwkQW&EN4B##O z&JXgZ?jRA@qM13uAuTE<6go0fiB0HJ>T)}-nE8_1NX49O1w(+ohaAD zWAR#5FX=Ta?Am)SBAb>IB_&{E?srE)G_xk?t9C~iS*o%w z4M<{ef-kYgZVW(#(dNlR+;;jS-JT^NEwZUl5x86mc?cqdF@hYFk9^K9j=SpDVb%Gx zI3dugD#f`)yV>uS8MXWxqZ_yYMtyejsK=rlU1NHUt~FPDlpK%Ztf)z}kAJ%}gqlO5 zk!lc*RkV5-R0CfrNJNM5ftCmyL}oK{amF_`B36i*jF?J&5Iv@EZ);0~n$zOsFD(tp zndhvU6DH;ir|g_Ia{Idq9nmZ;vd(JBnWCFXy=~EuGyBPmpbjxRW@~ChCRS&Ux!!UOVPEp8e|HovtaEP@>tAJ-P*DUK5ojt4?smpjNYe_u1`JnvT7vw}m;}ISfq(!R^=IRO(0e4geM?N)Q-)$%8|P1 z6!B!CVg5Ln(7!t^bDHZWHOVq>W?3 z;GEQP;s8?X2$JvM=m&zc(Wj21Mb*2Zf7AO;i*}a~R?YTzG5)i?U6kOEAe(C|?=Tz` zr;ftqxZbgO-5Gg6&qth-%YO35D3wF^nG{K|zI=9RoJet0>jIkT+7H7XAhQY%-it`%GM(;kOpfx_7Sm%{j^x=9Qz zV(u40OyZ9t07=^whu?sCfjyoU%yM0kaF(pS+u>ivgw`^toF#=Pf(CqAP_ZPSzLxl* zFp&=vd4%n>8h?7kR=y*^NXu_uo!}W|74#I{opo&ziczbXA8@F4(Su$ZqVQfjfsQ-Y zGKL2|fs4JvZ%zwwVR!(xnrEhh8$&XJTRx8q7B|C~cfd)~Vm(T2P~JN@)hqug_*j%v z?)ceWZ?^barqxaxhvA{rN8wgVeH4DB)W_pkov}YG&woSJ;)r9LX} zQtG2}FQq;v|5ECsaxkUdi-$!O7uK=^0))nMZ#ffq!Vy5D%@G1Jqs0^241n-JU=WOB z#?A>-(1kkL59s;bS!MVwoBO+4p~1_$ijh$LibSU+yR<#%WJHC&M>#^e#Vo-k8KqRr zBGHx6{D132HZ%z^{zSWpY+=qP0dwTif#Rt?+xz#=)sLU}emY^!!&qEUy0;+Y!P!m@ zj($+`7Pc=Pi09+1A+r}r{K1wuwdgu5sRSgb2_K%&{ZF{4L1s&i4%~cNabRLZRbEDm zCa*J2$Qp$%q9eQ=HrOYD|0K+O92|8kzzaBa)_?6YhfsKSgdF8sU#Ur{NKxvAP3)R< zoGmLXig@E34vv2K%(Zx9)}QG`0A3sS~5LoZ3+k=_9XO zpn)WF-O=Ix?vrQxXq+)z>(~;91C?UygSSQ80PSwtvrA2l;$VEg--Vv@ejV?XhP_Xz zTz|q@?f*}4bBHsX{Alt#@pFs4s7}GUIdNZNEKlJk9SQy#^Gh7GWqK73-MwOKpiU~2 zb9os+3Vz*dc_<>3k&L#*8*<_ubKggoFW8^t#W#rzM@cR;a-xg@H z_ud3(DOGQ?-L7|mEKj&7O_=fJ<>ipw9)H8KnvDX(+q%WGj90d!t@S`be;*>CplcN> z-PqT`1mFG&cp#O^rJUgFQGr~F7r~-yP=SP6Nq`E9VSNKxhd?QVv(paTPOut!D*#{z zLUbG0-?!_)iW+SluEu`(_9~2iI#O5Idgk*g#qXPk(e@ zMiKw6a{5l(UV!tgM1y*l0@I3tdQ^DldW>EO8pLS5fL>dV)w>-e&+TpxERVe20enX) zRdt=o_g=uf4rXBBQ8@uk4i9sb<$6ox-8&I>?4M?QT?wE7OMgU)7nx9wyHNHesZ6|^HySipm)&8(#KX4;AIvJf zP;5vzjgL1Y3{0i5i92&LzEvl#jVf~v4oBTwfQzn)dYl&v);tqeMtqB!hQtQq5Wb;~ z#mL}zsDaeKgs$5C2Y09?mi@AWh-?2g`o%r@!B8EQ9NuE26;~E3;o@l-+kYGwqo{C9 zPfby0ImPmw-^N450F1l}@UNX7@Yv4wwmNDi2y|;`VzI}^CCtmXH`(DjsvIoaE%nMq zJa)okyA4m4Rf)g1T#f3MqhP85hZCfuWa)H3YXUd>&yHuRy{xX^>I1EahE2k-eo<#- z6=CQ=Wqh(+7^@FmM{Wt9zJI#nJ8R(9sR@o^PlYN zI&{~x1D%ZKAfDkQv;>D&9$A=DKkUiT#r>}-7=F6(!KbMb+52(=7$Ilee)Zta9UsPj zr-Y$p^s#^6%SZgXp;oFNtt|*x^}|Oe@dv+#vg{UlNp=sPDPEzlRy~_lT>at}cwZNt z@7B|Ct-lF1%MfK?^nWy!9sJ>0B2WgWIFfkHP2FPTau3Mw83Sxj3nZIIZ8O0M4h0<3 z?chPX7W#HL#9$S=fpcT5w$MB7TN0rws3wckYlu)o%B?>inIu71`FwZK);3WGaHqNL zC07cveQ$x67C;ZxsAvmj!pBccUSc}b^FAwPF8fMWfK%q2-G9v!DKYx12#K;;pS&Bl zEzL-vA37wmhnaT7EUipv-Miv%Jxlk?q)qn=s+$pvCKo&Ep#hk@K(f=hNWK>IH-;^t z3V=J~Gehu55aAv(t`0Rge|k^RsS`ASXubB~c2+KNNpTjY&H_-U7uTGDY?YnBE)c!RY+k;7J52IW?wKIqQR-~ z8tlBSIEzErMgWg>a#sL>v)#m%6>TcYV(Cr1<&5Ih{C_rTM70juia4xKi6LjzN?MFR zNtvneNF>FRGtkxEXJ)?s1r9bVeJp->#+9dBy{W7osuwz|c$H*n+#vo7jtQ$%8Y6VK zrIqxDWPD@>$O4We1!Hr`ruh~z0=%3VvO1B7Lto_gL(`3<@8E@7t`u>Y|3TWSn8A_#L+%9j|Im?)A~Oe#4iS-Yyu?F~9AHXCLWZh-sl)(QSUi2GwnU z)$@&iJ^2QH^~ zU4IP}GWO(=`z?&fteSfP#Tfpmc@p;LKS@rXzw#>z@03-&MchunAr7EZx6|Hi?{?ixJ?Nvd+v^FgCnIMNv&VkZ z-4)bxnVRK59h<7s2;Xh_T1YWwJGk)3Hzx?3RkU`1X;bE^%K=*t%<+DH5Hvp(RRi#n zUJ9S!#a`#}S-szTly?UkzP+vHD4oJ48-E)vD0>5A05l~X5Ws2tOwncl<_@+lz{e$@ zmBv4F78lAI@eB?ef;@^m;YL9Y&_3qK0;<@W0{_zL1n{_o{hMaBmF6u#2IqFvSR;77 zG;t%aEPM~q619hP-609`Lk&1G+umQ+!Z}#iMdrsj(x@`&O1!#V^?tmF4{dMzntyFn zW$^kGP%4bYjHjR5IGZ(GZq*@Pr$dRt0v>py%c;+;kK^6?PST~5Heqt_knV$D_zZ&Y zR}gBHmCA-PY)t552xBgnE<)kTnCz8yQCjunu|tDU<3{(;01&81CH7R zw>a_fyn?2VI1yqLloIb6bM`QA6fd4e#T4Tx6lqAUn7Dj#>wTV=myrJicz;TQ{h82k zfM>Yc)($NkdtvFuLu|$gJw9#+tgh6t#Tl?kB*~b}NKU>)cDH0e(n1m>hNyr|ny6Zuo zU+zS@y}jECCz7VuUA;V!ntwX(ABz%?h=`-yAO$bn%)KUoURRA**@>`^{aL>$c-PZu0Zpr~gSqiGCa6&uXf1sE6;Ssr&yKfBnZqZ_{v1i`-ny2qFp8R_R z#L+1vea%bYjiPtNHGfw~;6*N>mELgNexd)$u6a@Ce&UtFBBU&M%!^tti0<&s$9^2~ zjBCdR+q`CI!Ft8>jUu2eBv>?E9@gG)+<3075mB|JLWq1fy~u1?-TYWJ|A2{9Mo}_K z|7k)CG!^BqAN}PiAq6Jr$J#%>^-m}E?|C8`6uqvkD)@1nZhsTKBfzjw6^6X2GSHW< zH3s70!07;LO(`?T?w(g!LERQ9L4}(PxMYJ%2*(Kf0xrgkjfy`Z$R*AL?)Fon^&oPj zU3J(NNKky8QFzTUJ}Adg8vxS5k4ar6XR-qagFDm0pv0o-B&)D4;FE@SbA2}Og#(Dj zm-E85?j~z3eShxyf2SXwfvrQQD8|0L8vst@YPZCZk}^WPjaUOeX*sEXy+#&Sh#PIW zSm=sp+eYB;$j`e|7){_|YuB&39bWV9Rf_w5fEOpX;#cd4p_eYI21>@m*kYQe*?bv|C z$)86(aDS=)m9TO(?oE8H#{3kQzwuUq$Gp zQJ(XX3pids)Jz@=KkQ;u-!Z@n8Y&t@xaQmU!Uk|bs@}Zcx4$l$z*`@C{olTq2b9KH z^(oC| z+qzyM^Ny)_6LWKAH=PN0t>M@G6(xGaYVUOhd-um3<4vrn+u3gIF(uRx`Uycno|+Uj z6!GoD|B)nWG*ZXOy*oSV@c5bf`Y^eBXMcEiApf|hlH?H!(oQ}m$~P3~OC(p-NjT1; zbl&}wqr-i*3rYK#1-KCo5bVUElz?wHhRI*tf@%AM*`K` zf@Xo7Q8E~*=vp>)6Ze(qcpPA@3X{tUT|r0wuJ!io-pJ*zkp7bS9zwWZ)IJCzlUO~#GG$SNqJ1Hw3+)TPCm_nN~gAZSqi?(A<5$+ zDWeF0D#fZwA>!5Bv-V(qu^5d!q$K6p5hmV>>s)(MSVC;M0tT8{K_G zj~~9Ps)z?^QjKkD{mMHYZL)GTy=b$e{*6Rs?o0N?Q(&LF2q`TmB}5y_zkl(l7KOqo zEswe&QAZnw`$;K4S3!_c;`u4>SR;fRUs3{dXT`Z!vwg1_CP^?4coK7+Lgx;5`oDve z$K&z5UgW36!}))OB?iXG{67ow0O9D^l!+()}#OuDr>%MI! zcK=On3ZOSekE`<1nnNLF6pW;QpyJ+YUdX5SzFrFqanrj7!Gr0Z7Q9JO!@qqJq@7}| zUQS9Q!ai}^{fSf}E)tQUE9t9kDM?1|Z$MP?%3?X`)_kp`w61$8Cz>$pV&6I>CD)Lw zxS4M%(LidYgFQ%)ihp9JB{Az2xy3V*T@}IgqcP`k>@&?~27?F0%HLPG1E;0CXd6|l zbX7yZ@gqORn`K5un>duDOMN^#d^v@=)OoiDq^~#Zyd*Tb3*xq7S1p~IBeNo_)`xa2 z*W;zkL)e=wM6UrUILxbGd!}Hrv$08Ya?@>PiKOD{P zd5Q3XI15XGXDH^O?*H=h|M{nZx_9T^7rin_3ab8O)XkABiv>)hYeimcH)OKi&J(|J#W|Cj$A4_Mn#rgWg*mbw3{U4}T1!ij$@_*obyU zcCHiLbemV^_}@J9)9T1)D)SYuiQ{~jp4yyBf%dJ3qklZ}hN# zw?^LaU*x`Q%pG2o^=;S>joLT`(njHIS zVyjkVXJn{4E0yYaUYN+1<#xZsdUsZphcK)tK~QV-xdCj=R4qxq(-!63NQkTd(H&6= zp0vRdafxYgUXHtbo#iH!agIwlw+c6}bBKDUS$|Z7RjCbxGv4E8(@yRKYO_mM2vskgbaFA|+b@0%MuI;Y3HA?rPsL6W4*a+9_q|mq z|6J>d{R;6|swE~x1j7OXF&%l9qU$&qpD(Yh>Q=%N3?{w}wk-P?_hli^!@pp>t%Vq%4>x*z`# zp#dC6R&Wb-B*pl=8%_agrbutNoM$=jeE2a^Hu{b(6lS8f3`W}w8QbAVD3hBqLVrWX z3AcxWIv3ZRB@KrB@*>B{#D$-z#c4^X^%S~wCC=h{)@$k#x2Xp0ON=^cmArMY41>Me z91d?B`Nny2TZ2|9@LNj2E)%<*AiVz9Yvf_y{XZ?18t&L@rRBXyGWIf&)**%-Da0JO z#Iln{EXd&5`5<+HujjwS3Mt(sF@HKiClcUYI2*#vh%i9jJp_}ZsLDL2$vlGBQda^` zd*qXZ)T1`+>zAMZ<@3$>A~DDArUi%vLh>wLePDaH3eLUH>Rox}uu8e0*3{q?xImOc zhv2j=o1o>P6ffO#P}Af>t$=CZd=JXGKlI8snXgGc#bOJ-~;mVet8B|Zt$ z5qU?_kO?9>7WneVIgqupi_)~RDmog$+Hy!MkQI~B4wv1wCP#rGeCuu@>2&CoU1t}r zlt>tKpmh3Q$eScIA%Mc0VNKZggW2k{n=6} z=byIpdd81l@fCNrYI`K6zt~&u+7>S>xT}|_A$pN%N(4Q4B9zL#Q{B--NA_>q&$yo- z-Tihsj2gERE_9kepA0=6y_uhmJ16yt+&;^)y)$6+?DE` z5U!zE`pNcoOzl+MsDG@G=v?L>&d_3!#g{!{&D`aKhIw-NyPm_gWvtVZCe3%Jw@R7g zW9~*L>cnkPF(a*>g9QKX#Rc;>~-y_fWgC$Pn`f-K2 z>s08AK2T>NpMPW~g&Ro2L6s+$|mz&{X*9ueTq&{=eJVkJtZtjs19?U+6}5vlMi_CRRC4VW%{~@k2dyTKmE&r@+eBjpbZ-xU71hObPGlVye(XvQ<`nF~^KO(#>5S^W z1oex5WPO;tD_0ru;557s!6TTY+$TLa1*(Av@yGcU z_eP>hkbe|zYFDbOOZeBAJYQT>$T}-7O2}K6)d+@6T!-Q?R0HG^@j6CLElfQxQwJtI zD+yIV{il5sE^3Ce%qhVv%>cTnB+(>7Lxw(18cK|&0#*ro1k1vfc}9&8`fYbd7jEiH zeMRyBLj2?sH939VM3^Oe-~Rfe3>R*MZN|r2K!0T{N<_E>U?yZ+*Vw++>f17*TQ!Q; zO^QpnR=zXM36<$ockc}D+`03S%qZ3m&<{l{&8_ZUyL%=NILow6bCP2w^zfi_dZ@@Q zKks@%`aE;JaikA=l3<-7FP6RfzU*3O!B~*{2<>tac^pKSC$6u9UbkHzGP$%=mZN4A zcYp8|lc}U$6gpRFrm02)A$N!BZ)Nit`Y;-?kf7-E)_Ou?h2N+t_9DOHbVWC^uHzy_ z3xH&?x&PyOF}1ScZdxC9;{k_nZ9o0t;u!wr!(}nsa_$Q8j@ zdfa_G-%AF0i}l%|+Q;=i>3_WAgIz^zgp8TUJHln`tkxx+5i)^2Vp0Kn zxinge=V*X|XqTM5u_SK1E z*M={fG;B*m{-8)MchBnMZe;Asl#;EHYy9_aE!*29&@y1}`Id5~HSN!5pd4E(PJjQU zh5DXU6H=C-KJ;x3Fc`K}slfs8wdMk48~~RebI|SDWc>HtnpT$JvceggWYVhu`6(UVMZcetv2E(H5mp6p)RKp5?8Q`k0oBj>C~aEhW|zbtm$-wdUGGae%RV zmB`$9Q{U3zv|C)YLXplKt<*AG8h-?oLmm*R0qzET965fYSpRiuX%zEk%NDpE+O+L$ z*CMP7XYighwF&nMZvQB{`CG1rmpBJI7kHEvi{~{0VB{U<_s$kGsX$+EQ zI^?M<+fYUdIvX+u*bBVRtU77!g!4qYp#Fz;qxQW_!T?rcChQ+ub$V$r&3{&$#%gk< zmeSG(*8mRU&1sIDsx9)7Q81)huv!Z0U-dP@jY3HCWSVPhVWicsH zw6AZ*-4tCYG>2BL3D-5aW1 zjx6?1__n5i1m1O(4?h@+6tAg(VAo(})1@i{Z+YC~)C}E`0 zLRJ_nIVD`_aB8W*YU?UJ(#hN(a{oQ4p2zp1bzN`M?dR9uQo_CPN+?0I^^_0y!1Mc? zJf#7FZ+eORGaFp$BaSb9$qAgCE`Y*-$kBvDlA<=uil}=`$izdx2Y+h5*lqSiT*}wE zk`d5m3;XU7|N_wSA{(i;#3xgb79%=6{K%+tWGKA9AO}fI{a@ zxr82Z*5qfIM}!n9*Vd;4(F z=73Z9D2MRN&;OD#)@+<`=Msh@WL28Lz`o+h7K|R+-M?}1a$-=^b8JV&L`bs1*bgUc z=ml$*uyrlwM}O3pwZ^kArm(yBL~Xh&;K}ca)Mj({W!?8`b9e8FP;y~rWz7stvJ}7; zT$MMF?P{AAsWtBLrIKM!yXkooE4K4!tZ01hS8lYC6= zF-eyJH9M+PTE+IW>r{Nwz8w@8N3leZIVd_z42@$9vVUeiu;uMukVHXw&@LVO-V<(l zBW{p*1@y%)KmW^?tPkXu`pQ!88FH9_!|I$$>^aEMC+hp?9J%%$6T$Pyy~3Q|Z*-{T zCrWo#sS|gqJiM}VV?LZ(Xmlcz3*KQD@vx{3!*7p>%(KxpPvmfPoHa|+^};w1(+8b9 zT~c&_Y=66OLV!oIllBBqfkSo`{cR1lLy0A%3B^PF^7Fr1m8m*)2}&ZU&6cp= z60UlS<|z87fCEGUp!Q zs^l$`TAV~D>(AnvX?)#*N*E>bTo%9ZE@GbeA?t6Mt^wkGoD=enx=>wmklD(yfojm1paFEhk?3( zhc%8bxLC+g9dX{k_V$r6uKmIGHrPCzJ)N>4b?Fkg1m>}4KQP9t^`ZDmdmK`a8$rOECg{FG1$ zC%u9e{$y&9*UG4d!`m?Sy)~~OfMln;^+wY&Z@GgtPNj@3hZs;=9DfSekl`UcDFGaaRe1FTa8*i}iHVnE24*vAY z0=fdm2;~#(wbe&38M)<9n7xhhMsq|PKC1JAqu2OMlXOKz-{UeOK>`ppC(t``>9~4j zG@O$pBMb_A+q{?}n#dbnofRuk-fx%jj|HC$NRVWlrJ`&EKKX4r9H}C2OAYbRgqU*< zl8JS$kxu$$QGbm8z+{)m2x5OQ84w0rqpr*8j+TR#THs`T=`PUbKv&WIIE(*yYcv~2P%OVQl=HRLO05ND#xg&5OJIG3<}!8Ky@b*Tw`T1|AGWa4^p7cX0lijt$~ z$vHq|Xn*sTO%3fv#3zXpCpuB2k$=Q^yhRDi4$TBDpDaLep(I9e)SNRAmKv>*)^iYs z9$LRcY*k{F9UA#%&N&T4~k`J(x@)P<$oB6&%U&ioq?-Ryu931K#ajyNkXDX z6*trK5%7tv>(#-@rMcSXQ*9)bi&C;+JFpT%Kzk|nvM-`>cvvYqwM$uaeASBF%*Ke| zb|tOKA0R2FLaH4pNb#)zH8Ds?SYCco7U#g1gp`dAzZC!?%bn`GVBgRq-N<^bSAou{cVL`S6?P$gsd(I)V4U zoaW~V8-$macV;yRG`u^oBMa;nNsvdg3rPhSntwV7umipP^Lj5nCeyr1vshn|`}!vl zW?n)gp52?MB~^{s(8yTbSP1^|ewqt)%{D(a*b9%7t1*ODew7$!ReresYt7b5#)Y(;& zxmKSIyY~8f>C(Dqvpvkz`?{+AIR(FNO)R)sSHTu&tWf-YSq&a2NZ{EK_OK$pXN4s?X^Xr_y-Q*?UwjOUXZwPZrpWnQ1 z7Vz3qQI5{$Rh~~+`KPaH|0O4vjDIeMsm}Ga)`#9`%Ntj+8>v5fotA@IrSGEKHz`clQ}C~T za}GdHlb#sExLyi+-t_uWPDWZ+nBAgG!!>?hAWDb|stBmfg@y4AOR1oqNtg&Kkjh+c z`TYVmr{=63ej!DL4tEb;$HR!~v3#JhxRNghfhmaaPGI%2Nj$s@sDD@=jJ2pUAJovo z!Oi$-YnHC6y*Ww}sxf~Sq zEC42N7esw}SaOLr_CSEnARbl%WABHcV^H@&Nz|9cq{xaP%+)~;Ni9dpJ27;W{)O+sw{4lpf5XApW3fKT8i^f-({ zrhYtb0!0eeh~0=hv8gNuH))r7g{h0Y|aEQoToPR9r+Igzi>5(FyF_= zCobUN;?u*_p?|hJGrp}Dy0sB2KBAn_6&!M;_634E|L9TcY5Y;n?CkKHZHcp^=QHVV z%f7JIA|tn&9NiN6AaH0l@u$}8`Qtgz7-WQAXQah_z>Y>>=>VZ1N4y+^@X}hsN$CPK zCCa7o6e|RS5)>R}gZux3-OjsU*MMlCvl7 z#fpHa$z)O%NpD1sqFWL3nzzS|Wxne)GY_FLGLBnB#;e6bkIH!20f-m~eZy76D7?t# zQpz>xq3E1UKx+ekt-G@N?lzkzmwo7q#fxNIox)2)iBU%j?k+i6fIxG!P`f&g7KF9a z@nv=-34b?q4m~jljYy<}KuQV)3I{|sjcHyL9Na3a6ogC6VHrW)L4PpVo0;YnYJZeE zOI?_gM+GFzGTITMpV3lB&Rr*&H8C+s{Pg05)EaO@CMnDdV&TrWqS%EK#E`cmb?IWh zZ($Y~15aWWc3wQ&ef9)iXJK`hymEv56&o!>!G9hSS5iuT1D#$0Xby2BELt;nwgkBW z*X@YlTs$!;Ropq^<>sZJrC6S2QNXA{0>(}vdSdI+aTj!&5Rb)y@{-kYk|E?AN&-Ca z4wQ7J&wkoNB88;Z28-QwmF21e(RVIt!xA2@|Mjg^W#Zo%e^8+uDY0LepS{* zatNb7Dbaq0J4xtA4+wdEECPmWK{D#Yq-gzQh`8pN)~6*g(^B`RJ>iT*L6_YpJ{J=C zCX;A;qQo_TR}L&R3x%@JPTP_P&kv?KV+$pd27+P(hcFXWs!Q6q%gbA9>$XTckbhyy zRO-=B0nbC2oRi7&vR_A|cK0O+u1-Fm#$DedKB`L&;M{EoS_m)V>Ag-%N3Mp;e_3CpHEZz7XR^-#{32VJ`UMmz@v+|JSc6_X?o;;B-D zCmyFIEHCenuKpKY7V2dQijaPfYP)n)(@YOFh_@RrrL)ioO58=u9#v9vX?C~;LkLmi z4UA8)k=!w1q01TYW`(lk0)G_)b2=Cnr)E;>GkiP@O9Wudr^)dB5$X}|6bUho*#rm_ z9m7@)r0k<|70y3;6X-PIA@9Uev*$8&J|G8-#|70YXSRVr057)1*rs$`AJxyXt;Q6X z0PWEgYvSzD2SIJtOVHo}Hz;PM8_+SB;tJ_1EYXW9>lN-5i=OaVV1Ih$F}0;vir^wv%k9}P}ntlt?0~ zYcd8rhlNZ0P-~_%6@L@U#b?)HE0>r55*gVzGsNvZN}7<}YbHq7oO9D5^YqxdVmWr` zN@xBtB`tIQ02#HD40X0AqYFdVKA9K9Q;*|GI%1jR{em-k**r*qm2BRx%YB55D=qWW zYov}u)oCb6M$EinNVppY_&1{&vl=(2p$Fo*;csBb(}X6$1_2fH9QR8KKSv}G{*dQd^pcqezoTyWx7>cZ*?2@=1 zkPU?D0frrsC!vQi_~1SbDa)HCxl{QPT%zu z$k;xULJw`~jei{EPRzFD?yO~KFe6GYlBbos zJu@9#+5Q`b?Y8C&Yp$ofj*i+(bAk=v+7;9B394lbRHb{P+=M#6AQS>9yPi+z5< z?splw)`Z1kA3MMUkj{9c!OIP)E3F#(ozGRkWf6xk|Drr!NVcU(ixk={CjQ{VwYGb zLYR$ z@_)rZ4U3|W0%}=bEk1ny}bE?!qb=f`7 zMRuiK!1HsAc3>{`=wo)rJ&ocE@=6OZhafgjQz;2RIG~f16RMhgxikZ~(>}BZ4X{j> zdo($1X-iy$lC?-yWM+sCrnhytn>6x%^M7@EOU~Olp$Rwk-d?MnIqut9=F~O)w_#Pi z%L6bP9Js_S;+Ul&fHuP#t_}V(E>jbk6FwamE`XC^9Z2D_or(FeK3aHmF+M?o>fyG< z;4PlRZ@>KN-L=p_ec)6|iK$KXP6&3^l|aWm&oJ5!Kb0#Vi!5y|A_0(8;4cZIZhvs! z1wmy)#umAVWF>L-vatg)WKB~VrxgI#NYvoKAy__hLnJ`JCKVHo>@38V1Ad8|SOMjq zu_k?Fdyx$y75}{x%!odP+N=7mgV@iAf1L5Lk1rTU4 z`z*Qe#PCKdv6FmmBqa#7dPhm#hq^$xMb2*ade05mdPV9r7C4#QDbhaFLN>MFk9#dD z?Vai{1f7=r`1p9N%W;zSk8(_y;ONxL2OQ~rP$gxxcu47uL zGY|K9o?Tq_Zt%A6r)dB?`+vKKe!DzOvh4f$@1lG9{#il49NNr-m$dpc3MLC1B8UMY zGX48*w~LK!2Nuu4kIQ{OcUTQ?VpQ-dXS&jBi--2(_eM=-eWA@X ztNymLze}??;P;|sa8FUM@`UeteO}jd8u%tjGa)BF)@V7GVs_wm7JruyJbtQq;2W0> zyrBUeIQ?*qfm0==M|!}@AF3L3KN}2sy{mdEyM}J_>_EZVNHoP67m}myF zs9jB+=H;GYS6tk{=xksO9a#P+`>$|o5{ijs4ssAG!$QWExLdO^Ek3 zGNRZT?5g#?-kY-xp8bFS=bn?CeN%8RU$Av-`^2_wn*;6&Mt9tfK@9x!W8Enbc`*(&f!J8a5n_#ADd65^JLE9n$kMiqm6GeE+ z(Bk-ixRKEORsqWGweRTMvwNJqF`P?9@b6qw3#e7Kh+F~~2C&l>VARW*Z$k9tor9(6 ztydVBtD7&FsNIm7O?A?vWYH^X|LCzBxqyO?L4YkvY5GD=5%{QyYzDt;UoRT8NaKptz6B|FiCUD2uX}h%@_R zcNec*#l8lxtiZ2_f|?FIn4k<>DvI*x;KZHK=}H=wSIZZ1*Os9hsP&D`RMe=uBg!9K zahOh(q)MePKiNf)kcZ|PxS_gnC*a*g29dczV{*sBrq(_rS<4=z9{jLwfwp4ID)_L} zvWli~ZJPuKp6bE%8oMbH~{7Lu}`11VzM z=g!NH(_3Zfpnmr0-)?&bRFH=ZMG$rCZxjel>E6mR7vkW_`zEN2dfnjBLEXL&U!KiJ zR+czG+Y3sm?P2V5SBD@<*>{Y}uWz)aSm49C7b$N_JZVQW(V3?gl89tMHgAh^rf@oGsi2fl z8LW=YFJ<@lMTF7heH#hX2U+Vw=Xah`OY|K)?F@oyP_TL^H6st?%w4?)?Up3tB!4b| z@bwFh1lv3FZxWoMY!HbEXnI5kvs|#d0rj91R&GCPVaH|-5fL1%K=4iY=)4Y-z=JmC zzthjcPUM4U9+Yw}-|05=(N&1D1^Li@n;Xu)O$Aoox3p>;OGq)rzG>C6p$5*{jw12- z1R!Odscu9G&G7dM3Wqx&0X4$hd5}@S04L@YD;JHDOLUyqS>^@1LlR2HkV8yKCD(TF z33ss2LyDQ;`FvFzw;$ZD(1a;$3zKRspW8!8t)z)+?lsIJ8R?iZ zcR#r7;!!Jt$mR(QLDl4(aBAW)WXSv|Qr>iR@vmSwecH(KQ9)Bo0?R&8f*VHwu2Fj9 z-?c4b;pK$ttk;x$DnD0+UQ{dY*bTY!SeUDtTyUx6(?NSA*6`KMi_8l48E{nvQWuu) zqk+ux0VR@cGFl#jAZM=Q*^u_TpoOdW#+fD*O9n%{u(PEJ(MEV)?R*(-o{!%HvI4($ zb#_h4k7Y$@CiuQPNlVg0Ny?D`g?t&%jx_AyG>yb#J|=!Mu&lMmCS_rJ>kVKpGlgKm z8DU;T^hkriqVa01nZfezfoyhW1%Ks)ywU?6TNKGN@kpR|Dl6SKZh+b~NT3zKs?FYE zT!8Xnk=CiBJN^ktvYAlvKQcz!*g2;gFESC~cl7WwYMclX5TDJ6e=1W0^d-Bzk3}9! z_(Lx%hLYRS1ZQ`?9?N3rhwyzgQtb^E3Lxn@YJGO??W$a}g8j_r`P29Z1cwJ!Ie#Nm zfK+l0QG1wQs`VdTh!;Yo=bB}uB?lCanwnczj5R?*1HCQ@2nN|fSt30x6)~$4lV5oKBgU4nTf0zN z6dYwaf^vkkz;u9j0+rP{QY)UUq(L^CaM9m;;r!FLpggQbLnGn{;5&(O0>HeA{B-2e z{T33CHi#~ES(mciXpSokb){AqwRzF`y==AIVJ`WF!d#rdl&Gl3$XBkaJ0^}~ii~VjMO-DI>GODV~2DmAV5nEeUobF|FdSvDE)xiq|e69os zsF!Xw6y=Y)ZC+6MTMVw2w&(%&jkTSf^^xdWrQXg=Qx~pp@OH_5?`AnKeT7MSntBM^ z)bd~0UVq2*)SX`(^)sZuYT56(0^$zJTMe+MNC~FAo|mQOT|J)04Y*TZr!q$!V=<@3 z8`C+8jpCmow#FPJi!{Rr8*++f8ENF>t)^{Rc#oP_*q)NSzcTVmW3K?OwW&IZMyBt8 zZ-S=o_U>QhHG9d<7l$DRT6~T6;w~#1QBt$2DNEY&K4)YJ_IoP}QfUWWiYbhLZ}IX^ z<5(#M&n-bRcLg+b2TiwtMdMmb!RooNC`7KO%c59u54TpYf^|xf!?h0paF6()+V@`F;nJ9^cGN`b z&EC?~PBaX z!1C3$x$#cx`KqR@WPLrWD$4ooek=LsFl+hZs{c*mg44Rn-895h(p2$S|L-Q7Qj`OM!Q)bP*ux z?t3Dr+-pR3$j@~mL4fKu&PE3wNH0(tfKspBN1&~x&6!73L%#z6*r#&=4q>@Dn4~<# zJWk#D@z*6?cFwmM;tF?6KOW=PdW?H6LDJBHFSfFGV^BmDfQUeL5l}eISr7NTF$)56 z4~Xc-W2aowT(8H)7C9CgzR3A{VYqDei2X?}Y;{_F)DD@;J)H z#~x}GaBrm!vv-97+t}oV5!b9Gx`osrJk-vdE!xOj65iw%$;RVI|8QZL%Dp8tKl6Iq z+l&m-6%?=^6y<-MnHgk0y{91rkI4=w0^Z{LC7OXCQQ;=nR@o*Fw>l<_t>4e=ZEbBk zgm@IfLI`>6fTTkyiIYrSHZ+nTVuL~bVjE=GM4gmukd)sSXFgk=EhOt4I{fJ5K;vmU0C<}s zEdCG~ALTK(o<*r|yx~>W2|){xw48C4%247`K!B2l0c`6A_GiX zaT`n_k*kOtvNZ`|NizkEc=T+CP0@LHS3%)&8yg9gO&66-gtW1<9sbcc^_s8r@A4eN zzyjIOxvHq~l)VU7?k3w7w45LR+dQ-+{9!VI(kyuGoUN(qn!j1L9d=4Ygey8gvZrq` zK|3n$+T&Df9hI#$*m&3o)+}(}dfQtmv$nDVQ@-yu9nC`!U+o%hbn!2n_?v_CC+E4D z_q{XxxpJiQIAU12pLxgG-G~s4E4&7ohNN#VffHfZLX>7V7#}|}Hq;3pfE&>?-`#_* zWIwNHe{X%2)?|Whvzd_Ha@7M1y{K27zvOUyoF zbhE#K@O@XaYAKt}Tu7=N!axPHw_Dhrx0XJ7>iDO>1hB01Tt5Z4SiaYmmiQ`FjgD#( ztm5#PXtq!8S5Ca3S8E>HtlS}mL?7KVxRAK{&u!0sRx8FVXkEc9Pu;7Y&1r@bU-8o3 zR3kR zdQ<9l7?WRk_P_!m?waeTQH#DnKTz;R`ve;r2G{{zhrf%1d<5%ExPuH+}jAy6O-h9X$=_hA?t`{?b+V@%WxI z7(_!H%?8YvJEB~+cm|S8Pr=%yaR%*RK&D#|c46sr<+KT2=RCPfmRHDv1;_4j>(bTJ z)Yax;Eq*-o+VtF|d)b>_^t`f$l4B(dQgkEJhIV5gFog;J$L3~9*LAy_hiyylO4}RO zf)US!pezUQn)+4Aoi)W4V3rC*;MB?xe*dIg4(XojInP{0f0Pr9vp&4^#bovO;goMx zA`o=ZUgVcD%_wtBz0+i$O}E6l1|gA5-0wd43g8kQF3HA^Ziv^FzDSS@Eiq-lv|c^0+C_ETwqGffAOK?zGdSVw|kDR+y2?o)W? zUOLLJFP?Ea^-c9{?nT7sIQ$PBFq*Fy)8FNwU)n%~1c<;If37lnGSOCtkdpPvNrv5V z=@ueZPOO?1%7rocA2Qx^FyC}lRGG*vOD4XlwRbFJtZkR*{Ol#Egg)7ssE-ldDIjY3 zC|)`M_=kKU9Qr7bp07>2dtKXd!d<^I9u>EoEOq(}ZAa@`?ac=*2DNIW>L(E;na^{T zJ$?Dx>4(_235J&1EiGoxer?VyxQ5kH#orxemA>nH#iAZ2#?#0zMC!gOt!;OFj}lNS zY_IeDPFWqTma0*BWOaA2?iO(1gH=d4)pC3TkV%|A`iW7K%PI}MH=pvpW@fuO%vWyq z_zybe={u)SP2koYCNrywgtnLFo<%XM)~t@v8I{{ila|}`IA@;;=qB%d=%^A8c@_hC zCfkI7bisFR^0bZ5XHL#rq% zWN4W~rj9JSy&H#*bZdwI4<=w&J4`o73kF>&j|h7R+>HB%J6Yw*>d88uy0!Z7rP-%C zRot%qu%|xGi7o zQ!rH|6tHj6`r~Y?{lm^lydy)g&HZv(vZL4mD$s>)yN362`u~k0dcXW zRN%8v{^94^&-aa!;tk>B;m587zbUw9Tz5+TGm1BXzOe3}+kgTDy0!?fdlj~kKORtF zuv`7Cp9$#9b|6-Oa-24LA6cGk>6{3!&pEQ}ztfRHq7)$gfG%C$DQjBi9`9Ln`!@lJ z$D^x=VyhBt=S>Bf*<52i7bT|UDP+Nh5KfvJ65nQ*mh3RkR_+%>^4juVeHfA-4#thc zF$xE#1d1vhMezVV1)O6mD3S-i4e~5Cg#TDZ1D_`_~6#%g>%LChhu>f$)$>AkU!BR z=dgj=Mdq5+mhF7(9|d)i$^t4ihuCvi{SfH;0uwbI!(g3 zMpO|pf%LhjAm2z)50}oXi-9B`90#rFimX`rem8~2?eElk<8w4dw@cCDWoLfN$4zRa zW2nga{Sp8yO?DhQ>JaeptpB~A3^hm6GTlUZBaGNbB*dE@($hV$KGScVc=M-=&6-mh zJn_}GMd(+{+JLzdxqH#$B)b%6NefZ5DZ?e{JekX>c7pibo_*w3%X;o4>NIa1CeSTw zv4MVssHcs|2fK+YSJ+W4>HNIAQnA>&-3=)GCnezff@R$BFGk3A_F3V?;tvF=>0L0V z$a_P2OqL=czY^~DU(27xGvgb4sZ3JUheyK6CdHU=`}iZcu}4NL+Fkqz^F^BB7o5UV z)ze?!I&dn68CimHQl9NaclrGhVg9^vMixpKt>xTjH@<7m(fc`ReK-XxkWpoA7U>0xLNgJ^m$#JHN3dLp{wYCF79A&!fX02V z!JIj7BdRP-FU%i^R=F;6e7SR>>jm(Q1?cn1IaIxi7m1Tm3^gis5s%x|-x;KS=F4(V zBuw~vldTRZysX-&nwT%W1n8H?;a9NMgtyn#sYi~Oi}@ADYAbpfz#SA?(QmLUZm3iJfipkCdi&*%URNedjLP18>7@$_eI5W#NbW4AD>%;v^ zWvkN2WK~rp7ojusoy=>eEGD*=BYn&(il@apYM(yM4%t4Xwe0BC-+X3$%nv}fXa47x zWgp%gA+&gkzK@>OQeqM$EC^7anpN9d*GfA<@iwe!ZZaZ&q&GQ?A!Exd_FkLQ*b~5< zpKg$aPk>qCPo1aYiXUZT8~wdb7FnOcyDjCI*P$a#$L6=VLTYNx&&tZ8YC&6wp@@pp ziv zR)e|`)_ud_BmoMe8-di?3zvO zJQu=it#xLkRo1BVDV*_fKUQH`PI?Lzyr}dkN(a--~ zIqp1`nb;_edXm|z<{r@9*Fhe6cx1%w&YJdzS!!6emV-{Fai86o6{=-|*Q@{|18n=b z$5Y!eP`W}>#}rOgQ&xf5T3k$V)Hj%W**L!H=3;HbMSIOgX8q)Yp;4Y&LB3at^7)$m zy~KLvX|jU|E*vGE+)btE{jz~c)2vBT>r7+zHt5Sfop=P5R|$Xs?z7Gi@zq$;XB;r^ zkZ<3=(AvwTnv#Pa`lid;w4^vbzWw3u&C@7XCLPmvXSF^)K5>omxAj&PR7UKzdX8z~{x)zB(YtsYHfXuRDb}LSxM^e5%Fn>p zbZwUw--luhOB1plb`gin{0o5EzNsyP-C4wG4JfNqcn0DdHWDMD z(Df{oY>rPLK2eoh(qm^^%-nQrWM;KVQ`ycUnR_&Rs|-MI{x=buhoSC53cF?G?u~S3 z0;V&=NDUbIsD+t&YF%|USWEMiUEtJI2+xn>;=KOTL*Yuk=0eXEEI*q>|JjPRz0x|! ztP>iW${V zUo{VrS{xwT2-`3r)3nL$U!(W!%MO`0ftj_s0)mbuSy~~p43achQ%Og(8i!d;%4+e+ zp@6W)XZUhqN|7}qu`;;TEPR~&o0PNJO%0Ld{A-c-CIxBgZ85NMx>?LgXI$Me zPiX=*OMn1N)v4y8*s>C#2O8B%8>eH*S8sx2lFq0W6xN%^4Qm?V;e&6N6?UhgwE)O^ z%+?a=VRX0KKZVpLmKkV=WF(HU^kJAc7Ab=lm#BzDr=sc9TSy{Y9526ZF zv>@9$9yc!R+SpJ7)!Xg+&@P*M_ybDdvy<_aY-Bxd1PTgTHsPOA(#g8N3^(f)EMJ8w zZ06@7mela=vm=?e_PwxWg&=bD{43!0m=5%r&O;A-afaS|c|6`Xzs72%gyGIPGv_$9 zMOUD}z~9ANpwq1&JvY-eN8gBg5NMj0GnyY(it*Q*IpD6>_jqwpBBEHymjJ{>2oVxH z!TBZs+8B{eT>@Z%Wljt=|M^#s>sd5votINYVUX6>BTv?nPoU-G#2UI5+spA8-RCv% z-&ksLH-FU@s>>xzpk&Kgt2Oey%+vV%!zL>imb>q!mkY8*u291mN}c+urJbrkzBPV= zQso|B2@h2cMa&TanyBB)3;-C8l~G!3JZB!8yRCv}537z}EgCTU1tlJ!Uuk5?LW0Vf zRJBX)Sc(6df>04^deL(ZOMY{EV;w($Ov)~8n$p6Q$11g~d9F>(Tb-?Tb~@ep#8fuH zIY9R7&l0R_UYD!p_5rUj>t*hh-(QcI_^6LM(T$&uiHYHh;2qnR-KGb1~U+F@V#neCobiLGePJI zlBQz&eCh1pbAQKS8neyK*Qc62@5vCyDQ4U~(-b^QU_wxj>4)Ri6_1RJr1GvVyLao> zo&gRs5|f5Q$x3R!lL0@~Em=AnVW7H^l;r{1vY`P@Evfy2z&-Z1y8O&ED=Wq(9$=5Xrxxc}rvph>771hWE% z#;J9^v#ObKTpQ2xPn_11td?gT4gPkkfj4QPb*q?Nq+kSZp9ZX8#U3TmQxusP$s<1z zNzc&z&J2J(tye--Tg)trbyrN!5o*A>E8LIBD{z5yx|NMm)8E$rdKtYkMb>mp9KA?i}&Ima<{RqOBjrdzB{0BW>?d+pvE9soJH0JwjNn}A-CU_!25cA zt-ut(?ews_xf#0p8s9vg_F3^h$TlMSFx$O}QTx;h1OPfj#Ius$K4$w?hmU2pUB8~- zhtgcpKf`?*9w>g;QDgYPGtQV>EXqPA(oS_;=yHlFzI_^ZJTTU^!7-)0T$B2*i5~6T zI=DSszo`?+NshJ^w;A)7MuXyynWTw5#li>kui$v-oFi9pTNZBresmQ2ydSC)f7j*Q z)nONMp94INb+Db(KITek`4-Pojpl!lmU84%Oay(b*CnRr1atJ&1dWqZqnJzGLRt7z zmE}z%Gx1xpzk0xgKK?r=JetJxWQ`nMargskYGmfae|7Y}5R~jyODiemPj`oY z6_enO-Di^-BryGfEqm}g6god2(wGJ z7$&7{h{4=;S`;8*s6L0o(S4MB>QH9C{U_wFx(B3sF&h#Zq=d3X_%Ub3j>_xK-ql#DP@-hqmy6}vnJTv7h4L! zE(M`O5QBHcQGf_>wlnYtVJV+0j{6_({ly}YPDbl7*X*k9KwB^*uRS;jYI6AHAoj0& znu6J2a4rF^$ZqZT_KUCkt(KdI+!_YnLN*`|;udF;&leB_$Mq%4iD@o#T2Fde#jy8I zD8;h*OjK*}jI32>j}r=GkaOpr4ti`Cr$c`btY@K_(RoF~LOo^?Ym^oXuP9clT(l3Z z1C1sy=^kkPxKiz&d{iP%7Y`qs++>`jAXjcpqw&d`mZ}J>Pn5#Tp5zSjHxgz07argR zfbsm(CZ&Vvk~MDSf_?!9#V_k=PPUuE<}PamZ)DN`9p0DA)c;SLPN|@=DGhvP-Fyp! z#?%clTwjKX-FlKzdg(lReV-nV3hHCm7XbarB_l1x+?7h9Rz9Rv`2erZ9$E7BkG&Xg z&TGfSzhgFoO4}!I&n&h4cL-G2#tER`o}A|8(=cS8nq$pJGwOg3nkB$Pw$>+4LV=rv#%??xF9 z-9~9~fUe2~8J0-lzAo~wQA37LfF=KPh1P%b#GKG0qfIOkmyI2M{x@JjznPaWudA-8&QmTw<%dL;f z@e1OiTqHJ-3fZJ}qj%EMXTk`Grf@P-hx2l|V|rICIj?MXh;fmNi(-XXx)Ot!R8-CX7fB)_XD<%9Vy?17!=X)sybP#6ABao)%r6e=oh9qpT|ytp|@26 zF39tEE@inCbU-m9-e4`*sFPeto&?^50^wm+N5UVz!~PNToE|r?n~%kakQjj5-QH`3 z_cLW0#ED!3UuB{$}@HeOhlSRrJe6uQ2*-)QU0jV{wPvoKwrWUz;03-g}O=VGpcN+0Xi1oPXNhVC^#@ zsk8S-*EFHS>^W$;smRi9(XMQZnSP>MfP$5F%{6+{!OOQSxCk(OYwt-XIosID`6?y% zB2@s9<`d8g8o0klo-bl3UouJidbV86I?I;c({J3R#=${SYHeGzwB@xP=Ut%dS#T-d zJ5CsEUD`ms8=6fxXNqJm2?dGPM;>P=b+{K==>hYo$9rhtW{vd%_5`OkI1ynO9q&Uh z!S$;b!%Tm_5e+aH_COgDsIopYG-bf-Ssn&FNp-qVc+pEM_Y)(AC{ zDN9c7^|aacH1+j`2pOZ_x#j)x67pHXGi~zfvUXkknGE1_(|yk~mM_tDz5JD<(ulM_+f_s-~(*efdH) zxX^%G2JI3YFD)&AMV5Z}OI2R|cR)Rs2zOB|>U+8QA3mJXcn_FizqN*|KE!;Zm4dH8 zP*9v`j{Au@(&QiF4J24TeEOat3r3s$RGuKjL*cZ^Ms4w3Tm*= ztOtOx(Gd44fFEP>$a2*_w)(9Sd<((XgV|f;f%gAOSV6Z3RgPEvt&0zib1)j$+}XKJ zi8^z^q#me*E0J=ct_nR;0hFMj|3}gw8ReEnmk5O&Bp->u=&xov;y2+gO4Adhlu0Wn zmc5&qJ;#NSEVV^XfnEe#j@4KD11g2%l0D!OMWETzdBaPcfF-0j_HQT?D`aq+U`cZILVdr^KNt#w0vY|>nDqeE5%&VE?= zm|7y9bUhz7c~Djl~m1B`fr0>*1^gRO>>~*vS=57ncg| z2Ryn{Z+R1yoFb(_qv}&0f=d%`y!*98`%BG9Kl3;W=P!3yNZcJ&#c{H}qKbr~9OL*G zJUbb-O4AGpk|YNaZ$7r>LcMH|uk-_UQ_n;xN)R%De)ND3fCrfRm2cu^>;aK1R0lK7 z!x~4+p1Ak2ij8KBD_3W#s6N6gU=D*SZ2hwmB5uEq$tOd4KJP4RWaGd=9kUglM~G1b zguI-S%M{OMb#zz6c49RokeDRY{CHi^_H;bEB;+B#_|!P4hDcG_Z-FfvdHX= zt9j~K*{dPnP)#@gm{ZcXq7#ADAOXS zXbO-xD9VyBa$jGZ2+!;LUJJ8k(U{YVJNC*`O)OV3q?rv0rtAq(a5WXaw?b1`$Tw=y zuV0eFwcPFNoanu=F2?R|>nHsCFb92bq(@mN+F|EB1G zZw947V>|8wy*!L<)VL@Vpz1_cu`eVc8T z6!~4kFl4C&_aQ`Kj=O{yi$OQ7(yn~;3sc+dI)d&e|HKJ_9vM1^V=YNt1%G%FnEw0qm0_4^&10Lp6!}NSU6iQb@^yIGtONogQC>Kp7o3%E3 z+@K{6T@ScDp?B<)IbDK^(wl!Uw8hv$Kl`a_bFK!M^rDO;=*JIF$Gp&jxrGXY%m@XV zQkb2E5#ZOd@Hwq0BJ@0!F|HQx7hy5>DItnF-UaK#Pzc{=f{Fcv@+5n^#W!_iJ%lw} zxdF-G#<4ixOdEb-k_U2&@NndB4%k?Zf1(V)d;5iFQEq+%x`z4%VYnwJ&e7P2Ep$qe z;#4SiHW8W6-Yqo?SPJh&G}4{OqGO8b4+wG=o#c_YU8w! z3P;a@SQGOMQ9$c1XIgd?9>%|bDJVGkzpnNZaAzJG_-18z&5iY>C&BcbPQM>0cO;b# z7*@-uW$1y(ssA9ce=wTF+n3HQx_zP9a6de0kXi|^9)^Zm2wBCg& z4pEZb0Q=Jx_5t5llwY~xVTvTxp7RRuwy3!rCXDP3q_7eo-i8U*Wdkzwxj61!7FLdj zf$P@GPc5)INe9clu8V3TU+HT^Ze{z`1Sx-7MQ@bjNWvL4o?LmFlCytmh?A5cCxBKN zatO8ueJ1`0)h83~o#DVo_oC-iQi+UDgI@*9Vb-3K=9Zuo@B+nR+tE>EcU+gNIW^n4 zk}pw9Nu}oQjB1P3>k)9U%(4rmc=SX$xzHGd@(*Ibty`g$8*}c4<;BUxTvZUSzdH?S zc}6XaBwjfZ8Ku&ja~VUZE-54<{Q-Sgv+hs}dx6W?t=Gm5DMnN%E43n*w;ss0zs|`h z9}9m+5PV>D(ZMLlL9Y?QZ@s0Ox7#bYy)lX4bE)*Oju!(#5F&<(6}CuGJj&Wd9Ehi! zw+uCk21lOS(Q_~%!eZ;9(V10o#S5MDH#7muhvKk;nStKT-)-lPTcqyfOB?~%^J zQmEFCe>{XPt9m<;{23sRwcNNg+8Awn-IbZKo5V||{~($99_*hP3i~r@iGe^ga|j?> z3n5(3YZn#;EUH%-IQjKcbNrzKK(jk**Rm=_Wx zWB1Yr*1ugdo5pyFs+amM-2lwVHT{XhdHGoz)+8`CqDAlv9!VfiNQNbaQHBfi%Xshu z8-+v&uZopPE)f=5*4q2f131Tu&(Q+r7OSu=#}GXIRPdq8i5mh9fv4H z4*sg&214B<%jdAaBOT7YZY&g?pIpu`4>*OPUplXKJ504h1;mtLnWUwk+DU4Ct-W36 zC99J(E6hkp5cWwQ&n}Lz%ae;%+Z7GjX9gzHJpu&-XM9nbfD^PJ&!*@YXwkahYxk#P za0aYl)1DBm0oz13vj9R@!H}dhmswmE()!sP?NGM0MlHZ(je@R3Slrv?=t}t@F-pjn z7O*SPGIX0z2MYh*Brc1>II6@K_vsjPP2ah|5?@kXmr!y^W5WtwaM{Ps+<;6dNBlLe z*;f+TLXyGJraaqsnrVn!+fo4bD{@SoIN5>Hzb;irXpH#msRd|yA`SSA@_Q(MK8@En z;LkDh%KbzdG$*B#0dV{@`W^=Mg!{Lq4?J&emy-e*T55MjMaE4Ua+lB@~ zYKif#Yxfu+LLoa8a<2G24IA8!$Qu2Gvju4yVH(n`P*_eOyp$do7LEb?4kQw=i{Lk{ z?LT0{5Mr*GlUd>M&&+5xdnTWwLrIb637Z8y-g#z2;w|b2stqB^Pce>RAVPDW<-0TEz6JL-;2Hr~Up(W$Y}fPAb$xm} zz+k3Xs0rC)1OC7kISGGN2)aCtK(Th-O+#pZ*=9(Ma8oRen`7)cKoKHZUM9J`^rC<9 zlyn@L7@*)t#XMMmR{**W{(1jAZ3=4nDqiV`#ou`CK`|SA2<6osV$}t*mhTsSpbY<+ zjI;n74{TQjv@K*v1I7@31J+V`w&r8`3wr|W9M4&h$oFT{p|f#z zAe`OQSDt%wSKk$aRUXnFD;I3SuET=0cz0Jo3YesyNz>F*ODuz)Ro|Go=(NwboQSpJ z6bzF#QPPeGSyu}2--(}~%!RwN)5a8J3wq23f^7v-vz3){Z~|SCrS#<`nH7*>LI#i^ z1=l8^4~{`cU*O6b8VA2BRrk#p5M~CYu`7-V;c74**~gP0$uYW|bI6^DC6A|7U(IQ( z0Z)AJ@6U4h`KNYS{b=2? zPq0v1M6XjwV?w=-R66_!f5P&qpht(w^tp!qdKyGiBD%J-8)eBjmtjbN=jw(NH%x*` zifI|P4wf(=Xq`cSJsXyM9t`<$Dz~mjdmJE*ueeKl3WqX0)Qc0HJOa&189*|k0~)2* zRJnplJWzss@)PmV$cG7IXTXicPX+CU2Y}bKjvo0scP$MKLL%o+HSlnGl}yh`1sZMw zToLy5Yo>uoB}@346}iop8|`h=rpY(V)>D1nt-QnDScyk1d`VP*)DbxhX?)jBv9I~J z1zvsvpwmh&y(wbOyFfrWNI6zBV3#12?~Qr+-0%6}k_#`=?`JQ%B?9W4qZ?Umi{ zkUCn8U$5wHp}x|FTKI6Y0!~Lo)G?panRPlFYAD9Kl1?7`#OPs^VK_W4Ls=j}+{i1B z7(E0nn@AC&b6>D@bq4kl9)MSOvJ)8-;~d0Nm>r9@eO}qvf4Q?qJ&~qE0p2n3`pA!E z%xJIpQd2$F>0Qj8+X6i@()j%ap&`XgOgcb1N}J?knU%ClV@B06S*l<`uq1NU>ph%) z4SPZIvr*}br~RVb6fag6I=iF3t?7k4<6c!M0U(j z&|ZB<`QLe5vW_IwPjTC`6!6r~97>=+h{ScByDZ`n(-6xg#o0>E9$=XtU9eLVy2fA& zn(;dUGX*PT5aw2g-R*XWra|;~ExH9m$zK)g+ah)%6}o`mpmOxaFz1*FHOVOHUR(?qdbDxRh)$|kc@F*Ujr z3rtPCn>nno7hp9+$k?u=n(B0w_vjBYtAH!o7LGm>IwtQNET>RBl z5Pl@eHhbg9P5PnLvN|x=qJ&GE1kAi+Rx$iWWiBg9B~FU&3m`JX?5bp(F+Q2g#;!La zR2ty9lDvH!IAC*%i;g8LT*R#D1T*Z?&Kwwu)pj8vqJ~vW?8}V($LQ#d>d$iMA`Fb~ zOXx^*>CZS58 z(Out-nll{RjtZC9ALg~47D6y+@W-xC-5d_*4qdr-sKD*8Li#saGh1Jl(SSI ze^k-70hb`u;$n+WDd-ztkt%0w+#M|YYcX4;>WNF$#~^5-sw&{_J!QVus^s230U>L*pQ6On}!0gWbKwDaN}&0N!!y0(7`p z5n$i6Cxvubzr{=}(JYs@tc*rxecGkETDg@G062HEXDpSkdg^@nq{uBDph$?LedR*2 zq4<(>U=4&0o}5?*#SomWc}K6upaz!N(%tGRBC5|-4@M;N@r<|p{x*l{b{MhP4e-0& zrv1wKUtXyZ4MquKq~VTnW@w2f*C|qGL57$~D1=F(lhYz(JA)kkjIre#F5(j`T(s0d z09W$zk#i$n`o(cwMLBiDKhMn75H&gFwm#5zX4eKKc-^^82 zzjB>bT>DOV9mgWVN#Vq!fZid_I@6B=7hzUObE4T$#K8?Y#rTJz3)P|``K4Lnb2#_J zl1m_PHTJ_KVI=;^{0>NK230L2v8BwV0KDw&3BraOdn*Jf2Ha6)-Z{@7y4rcuN+$cs zNn}G^av?xOy=UbNFOquHGm4nh1;>`A#Da_pnUNL$zPp2u`#9zER!Q7KC;rnn+%}_C zjr$v~-QPZTBOVfIFVM^VW=;CfMyo2YGo`vmBO7#qybM9Qc7?3yP&Wd>YaITcLckQN zOMoh@XfgWOx%RH1CuvI6%NtF#{JCj1e=F(;>U^?ZO0wbjUr|+$hZcPwv42c{m46@* zib44+35_C>%pW9`P%b)w$DN+HFhH^owosix&(Wu-;=eR*A4LbYPFu0$ElK_ex$#oL z>2@Zb>}&v4-+is|(kAUwnlX#s$HF}SYW|Jr;!jRPvH=x;kLiHlbcy}B^FJ#)74 z3T>UXyJkRF_aWP4|9tkfU%M;nOdYi9hFoK9X}2H65(0_do0YpHoxts#RQ|LCsjCkt z0cKW*vXCygRwLbl{4BMlsnPC?QPn6TQ>^(I%S76ao&O#OqZ1AM(@{z=_3~vwxg_yQ0aF`F`#qlE)MqzG1_CxpT?LC;fV`qoAN}=%g#mQd`K@C zOD`Iae_Xr^RLu2-K~P})Ma07<^M#`A(x~)|^mq<3_-VGZn7_amTWVFWP+jvL{9oaf zqft+ooEj4~pg{}|T3LEQ9I%>_SM*9Y-ZBfn$H2Q~jT8*W7fT|vcX6PW%6&PyrK(+F zaYS1cw7r@0865*!7kHgJ&>jW?wAWt+R<%v1vc+w!x` zBNwpG$!VQdh|RI%lmC-4I0ywBK&-4P9{)tcc z+=Us9Po}_G-r_@3%F+4l0^?+u$_n0%#tbPX3>DtHHAgmvdE~KaI1jk#Dq)yxENd;UnBUCR&zzBi zxG3a%4}D8>IC=T=Z6yY7a?oDmlT3~C1XnsFaSj2*5A27312FPY~Y!71Jx$|{aKm1S(dZd{`O1a!Su1i*@_ZwG(T)6ccG`cY=n#4nCoEL0`z+4 zaNBy6hT%Z+V|_ItU6Tqo!2r)a1ZDf<3C;)oY>pobC*gn=6kRI`u{HWRoySe>L=%?WiIfq)w zeyC?I`v^Z|fxK<@b>*;eP?87&5?0SlXy4Fv47!EE%PID#^siK&(v_&9Hy*dCCEi_% zq6W1rIVw##ijQC%342m+a6B}P%Lf}eUJFdON^^@ED8N+j57SuMo!#b97p!)H)$RWP zS3s!0(AIY2C^*aKCyeHGot3J}VhX&MQBjC`w!#o0*@}>q+qOD7%)0m+3gf4?fuTFD zV=-(d&9p@QNr+hF9vVA~Czgb82$M7;VF(*Zk0(V*!4y$($21S}1x4Tu?W|tjcRDkH zsuGqXUCaPPbZXmw2R~r%xt1G zi;1SK?u?1vDQo5#XSR{@&++#*ZToqMonnh3UW&7`(?3grKxi&$fUG_YX5*1gt(`E) ztF`r9WAp?P8NYf2qBwZUJ zb=6CXovI@-#2MlQnWsGJoUnUw%2;&pTBOp${Z}o)>=qlSt|;YwHfRagyu`AJ{WIt* zxOG47n(%&3s*2+TDG@}r^CQYvfjvLMLuMp@ac}}e945V9Ic1MNCvN#Aend+I>sMa5 zddb#Ajo1^5oiX;y*yX#r)V8jom0TQbh!qQ+lJrry#PafUiZjN>vQcHB1Im)n2AoCC zDHpRzdkd~55=3W!Lgt(oO53WXKp9KBp`!$~!R?8N%_=9B91F;4FI!8W# z$8q2W&~H+HCy*^a8r5Gh98ribD5UnrECkW-suhb?!_}UanAlly9`ekX#*c-~lfl+T z@Yv`X_NVv%;KQH@fHxgSw;*L4=!`))YaQ8j*%cUChqw|nFqxLU5%!Wrlu(P_V!QNl zM9CQ-$q$boDUl1IshaZU_@xgDBsn90;=)-HpwG;OsBwWHF&pND>qmfFCO|D%Ci-cw znvWn_ca;5+qT(s#)m|h>aW%6V6Rg~_j#rJA|#Q&HaG;+iH zr@Ias#D?_LBLs+-)wx{2D`h(-eP}A4zD|Ia{Y!2*=s~K9L6VF9qacNTTHNrX-w!jq za*ISozJr7`TlG6jPFhqX4w6^!VkvcVK`)wn7`$n=GT!Dn3Dzx&akaYq{`VweQMg(w&zj(=#LwKrZLyLN&V)HAc~hZ&NieIJzO+6}`mE!Xw|15l@F zd0JB8Sm$7WJ`yq={90qssl$ar3mj8MrSe^9Jq4roy(`A>T?||JG-GAx0_6{0}PwyNgEZ3)|c-DK%|HXNwLO zXdYA&n(u*3qkbe{By>H1Y!lSY=9x>0*yU#CfR=FvbT4EL8QNAfo$`7P!qIzRA5H1&qL#u z+@N%SYw#$-(?~LLpr=?<7k5J5RNYW=i!Qv&tzi8!9f;99hH$6kY_3_j152&FDg|JK zlV5DqkH2kQ#b0X8LY7E%Fl#21GS6Vqax8-*Zj;XA;lzAe$-z7bpb$T@p=yW=j)(6ca*AeO&4NQ_zh+Eo*^rmT#Uv ze03m*x$NBz4>Ow~iRT1>Lj2C6m|iJTOQ3}N>J=#;2Lf#);ZL@CI=eNr-WEk%2Mobg zd5Uil)4os&)MR_{3e|mc9*)^^u3;4ckC##}pk9lA zvx>szmzSUW&FsQ}xK1SzUvejDd7!HWY+cxzJk3Rd!ZPX(FWGYm;ljd_9e)YT1g2h*gqo!vghrE&d6YlWLmz=#ncs~8~Ph2@C`EX zCBH^0KP&t;07U)vzyIGsrgexKp%!a@h%-y1)IWUj#0RVVI8E{jYl3D%A(pMLi|N3E zOLA(}hO3M_DGV7Y$eh5z5C)0T&NeP_i+0Wg6^*8OgXuS;1R*N8`@#SWNw?xHdcs}V zDiR_sfE{VXU~r7**g7l3InQ+da2ELws*<$SA;dE_K~Rm@u#&7VGfGQwqa${IIT$+s zI;^;otg*Fa+tg#*_V$UKwn*%`+Xf$g8+2^UvKXt2L3AZHRBX0zVm|!BT{$pXpZNUJU@h{0bd%9)D$K(q@} z^$~T)p@puH4H=VC6Go3D>ZGWDs!Zp)clt*gVAR(dvkAova8?nyAR?s`@(d&;l%J5S zupb}?RFvuKS9LNh9o&k~ymOQ<{7)7H_3thB@o(;vQUn;f&{Yc#62+|ai=J7@k`wx0 zdv%ixQnG}daeu+Lq|^fJfA8`>g0ysAp^4Ab)8qu@oq{bRhJFNyVvSvYQ9OXjNGUtS zfq0AmY;dcCGK5$bI72MgGMr@&6Ao5}{5W`7{lf# z7yabw8-+-}Ef<-t2~16rk_1pQE<+R?9J$%KP_nJk7dko?8wy_swgo<~OLQ=b2{?<~ zGj1-%ai1Q!5|J)Ask*9vk-QYYAT7XET~h3Z;mV74c)<@;e?I8UgV%7LDr28Dmn-b3 z{igYrSIm?~C}8L6G%t`U4}XoRU?pHW(3Br=n1TRKP^K*TP6Yyof|Up)O>E~pMLFfhjlp!(Ut%UVCKsjX7?z`9uQqP1 z-+uWuD~4p$qbaSS!)TdyDAF884gyg1IQf&&h4C*E=I)$-CLY956>DAfkfI4^C`;IN z9w7&^;W6q|@BAc48y4aF;B=QZPM#EZOkw7_UOM+<;cP>{At z-R5Lci;VueA3C;$m+%F&^^br#=e@NjTkB{+wF!De-T+FvJn7M9fGo3xit|eSo%`eL zLfau;YAHK^IMc#?VjX+N0guzQ&h@TYg9TwBomgKC?FM8cql7^KMZk6r+M=#iaB}v` zieHgrzAWwO+#v54sn=rIcPqNiuxa5=qJtl85k?T1dwVhWrRvEJSvqcTk&XQuOC6Sh zIWvxq3t0o2uXkUQwulek?7rtpP>^x}BoNakHz%J4j26%3EuR6}zeH z3l6xxts`9(YM|knr6G-z2>|dLcXQ|H$X0PCRf4Ly@BFkA944@ZJ#GR8-DRJL)$Vrt z>SzJXCC182fu2A2RJctiRoW?d+z#<5e@UU$yL}b?*Hv%izjnj_?0-jjZFDz$+l{u? zw+uahf65C^{4)G~?I_=urHp^;s*U(3I>YkQtAqCIo%YUO+8e(5o<;T`475V_irZ0; z7?8cEOGZIy+#sfd!0q_p2u>Ys!WM7&ejsFkKcgI-#qEGao-#q0F_#Gpix&L7R@T_E zVtO=W15~f87!xny1L~dHB)Hf!Dz^~V>EJAXcNQfrizIHev%mZPxUw*0&%)ZdR=>*u zlz9nP{jYz6(xkJmsBnaR84Ues;ScKZ8^Ulv1&_bgn(yElssbVFzB^C}&5|=Ij}NmLa?^I%+4&L_QX&U)%_M z6^#)L3}2JGEajFL^3mqXqS@&C_()EY84_k!aO zG%PBX!Sf=p0U8}@)Y!*yXbA$cGwig~ajzVQ1v#)={`F{op&ZhT zgMvbk_OR?TR0*ER8n~(bjqjN?$I_x3VrEJ&_6W!b7mm#8uLdhi@^M(IC#;i1Jl-AI zV7Jj`Gg6G`Xd#)Tueo*-w?PGzR==PEO7e&=)zdU#dB`ce^q`%w{Kx_+mn2#{THsni zM++!fpi9^VsVdOlk8;oDIU%iox%5=va(depv;=JvyXTqN?>a;?jYY!>@R^#_@yjkMua!etprMs6L8YgEt`rq=v8`th z_g_g6aoHvt#RYxW5nx2Np3!|_k}5Tb0fpok!A+&GMkcu~riQGWd7sXrU2~vu=xksG zO2HYNxouuK%NbouJg=a>7nz1E_q0QIXuU6KUS|&rfG68p_l(4#kmLX)Tb|w`vr?<& zsz>s}QmEgPYMPY5r6nAHY8*)MdXT3pq?I4UZr)GN(!LF8l4p7e0*eDk#L(I$VZ8*N zbg9gOi!*|PCFMLo%U;}EmH7h}gaFqpIh+j-3ha2S`;Z7SHWhI+NR*})M?RC_=XM^+ zh8tV1>Ch5Hy1gf>1YnWS9d3tns=<|{*^HLX!hXD?!;A?2#jB%#Gv|W9Yp<`6zTTtL zLQyrBX`x@%G|;avQ$gpc0Fc1j9NHY(Shyg&@F$o3&RYjn5GvGW2|n=x znCXf00@TlqjIvhrq|11#+?_9_#7kU8_VBVu`mmH5AhLRY@O_D8q|j)lLv8GeD#~?4 zR*Zf80ZtYh;sp#S&DGj(zx>C#Ize4Ba8cCyCYriQ#k#rjyxw*94I1hUKTB?kFCV`R0mrUw!nl|j|?m2ThZL+t! z-`z^Dt=6sSbekJ+>Zo4E|Iginq^~lIB55VtqNF4# zxwA+w5fK3fkwgHI0D=@f)bg)h-G6WS74D1aN$%R;a0URuL82sA)mq&tGcX*S@f-HH z_g>39&;W9Atd6Gcd9H)X8Rl$fI`!SJze&j&N9bs)qYArwtES2d6wRF^D7=GXjC?LB zSGY-kM{65%t##Uq#}aGhx|^D5-8nI@9{#h*`#Yy+6Z#=k!c8Ygv>q7f{H4==Fk@*@ywU3uCCq#&^?-e z(XK)APH+c{_FdKKOy}jB)rV15SJ61h?>DXzv2MN+s{;biR+hT?u|l@k{ju`nHrS(y z)s&~NeVO;^A8Rr`=O(PQnzE9oLpRv2Ay$F=2VdFR4}SUPFguX}tDNezH_ns0l|4LP zlPy|MqRK@N&Z>SJ9&m6cNJZkL40yj-YM{5#oD2}xNo=gN*E~eCEaN0-a$g<9RE%4M0&=&D_ z=D$^B$ryX!kCB>J8ZHrzNivl=Q66HGs2JwmufL%fohn7t$D}k0!`t?rtqq7=(Bp5p5}sM6jkf( zz1LP7Ofey`VHtvqoP0sPRV_w$`&AqY5c|^sL0eu&3sqSJUWS&9pn#gtyL?qovS#=k zl&8{gQiOq^J^-z8WWg#H)RhT2ThJe|xYekUjLorGI=U*nt}Y&+KLp=pR_Kas*& zX3CM0FcRoYh9K8h=gV2yRIVVD++~3dqqRR5J*2mYq6DxZ+PMf?VJ28)2uWa5;8hEQ zW8y!r`1!O%>D!8P!Ft($!!gb(I$q_^cmO;0sjCjAkEH$l60}p#jDZTC4`R}BkdNNj zecC#*F%M)KFqc-tX~fUKU0_(f(^Do+5)~BJjZz8@Ya^_Tr=27cDz*+IjbYoE($9=O zqtl1T^Q&!yDJEdX1B&=#3l++N>VYHAdJtdB+l8bBniF)EVE z-z~CajS@c?4gB$8->lPBrY_dZUUO+;3d0THg4ns!glJ=IOZMV3NtYwwco`~0j)ISQ zVtP?Y!0*6JFfV#S-x$yPLc5YWfA6`-zl301TvP{qa6x4H&=Pcz#+MTkZ|yOrijktv_8y7gtKX$eijH$YmY0((V%iy$@l`=12Cnb@|$VBe1OkQDK^%0&VtDC}gUOu+9 zD+udkur=uYvV1%5GmG;!VH35lUa~kDmZ0ikAF)?|J;sXnB>wnM_cstNz$uBuUe7cT zMzY_3-`aDj^+$HSbsgV>HM7oqyBHYerkkW=;18w0Y6A{!#!k^Up)~jk76LsPJ>1+InVx27r zzdmhJoY`l|d0iL$ulsbTkdk&>F6a$h|2;rjulAOFpqEEURQXy2mrq*s28}LYonU-_ zz%ZT1Wn<^_D+e&MY|yo%gDHpMUwla{CDfngj)D>znSxw~cF8mBoW>P<-@RJytkh`pyj}C_D*#JhUjwk@AD=t2-MH#N1h)`m!vFHg4yG$ku~cxeDHv67 zL>*fucMwb@RjPGAPld*0^W& zsd~4A>EXBt=DK`ST2nE@3=mEI$$R+c{-)3EVelNc{Yu8ER%iIf&GIrPpv4K((c-}Z zx_a?FYg0P=aE=$iF!F!?%iQhH`{=v&+lY*PHWHmLzLXuQyH2=ir`WZy*7%m+Y8sp8Z1=_uxSAEko>*Z9f@EGVEHL< z)%O&h-fJ2i_w^TzhF#AJ5lX=wxA7o0s8n4xd%Gt{Wp`ucYq1hJKMAsWA}h35X9ODt zwT@RmqZo=OWXZqY@t;b0w=Rf(H9x*2`2&vHR8vkskI73R=rtP`ijWshGkaFm@t6v; zy+mL&&C=Qt<%Z);L}ivRC%Xt{(IcyB>diQ3micp&-663}MufEY@9R7vrM~ETr@cJz zcjJIucJy+{g)F<}*_C@j#PfE>)Q+9ns`tZVaAxz4(II4 zHS-dAsetjfC1C6&63F)Oc&6sVZJL~2Nb2iYcC$|H+ttl$<9JqLJ@)34aJ~EWw+p=j0sU(U{|r=GJFa>6>u-*$s}&?|c~Vc|0bbH;e$mxj8jxmBTeGXdK|GIL z!7Iu_A5u-0XiPOEro7sJEWtzU%}J$SQm9p&K8c5?FOxDYM&`k){Cz(uC+2YB<-LCd zfwvS@ij>D;?@EZuMTQ-FDs>H9vIncQze@g8+Fdz`EwPF5D6Z*{!SnmSZ-lQz(+#e+ z3$AE`F{Bv;&TV%kqrcY|bj{bnU-yVJcFlZo@9W;`>gr*>p69cFIMZ20cYN`%_Xt0E z!N;#x|6op%SqW+5;aUd|SFmOTbHY+5|ABi8@lCB767`?f9|*F~++Y2}WfcfLGfv41 zhO>U0C2v#lt2Ntz_W^Dzg;VoA*I>qr>v;*KL30}a$;jjr$bv7gQ#FwdPi7av`vlCe zVc81Upj8qBg`+ut!U9Z8;Cz}(-Cm%`pkvBJLM?828M!7%6c7YrdR!I=hbRLAmJF`( z%Nvc$Il}R7(+Vz;aVbOtZGpr9dZkm|o;Try`CMG=OcsuVLe8JA3dFhRLr^l#0eITc zy|{blvAWpeJ0xMCrZF`h zm%jZl->cF1@x>acW^@vPUq`dsGT@IdM&7Uh3)6d7MyZ$ZIW5^Q_2bljPE` zz>oiN|Ir`JAVClY(-JRx28GD3EjygM1b7%!ML96lG(828c=rxH5BxC5=&+($??C(h z`OBsiGuc49L~DGVQPuVeimG<|he-5A5vk-HE>P)zw@-7CP7-3`MUfHq(*0r+)ky9N zfDdOG6FD9(Y{qGJ;UfgcV-N?>VBP)caDnI+aF84>to>w5jSd%HmdSqnmVf9SE*#Ht zmNLU{d$Y;m!Y{wv^6<|N7JT|{3ewYTj2lkRdiIK9cI%4NGsj!aXFWaT7xds7l*3S9dS zSm8~*^hi9+QZAir^KvY?)h32}Uu?QE1Mk0lWt~Oe@I-B~!b_ zRc4XVwtuF@cTB5eiPCTafJn}mqm1V8gH_OfLKpd{x{CyDisX-``O*=@(pyS(#lYpn6&4)PD2|fAWg$K^nJe1>Guew>tT2JWV4hJ9~V8_5P!1^~-405A_d< z(FL|RDLRu6w_Ko76=@45{r=@TN$)Oy6b|woKY1l_Ev(Bgts6H;i*jMj+*`Fj`FVAs zy2J0saR$58m|xt6*l@W}QxmR(cfbC&y!^Lxd;(&v<>j4Zl+GsjcTt+<IG1@8vO_u?KXcAa|8(~@$SzuA% zHL>HG4=&^wnvLJ_H*wIB?CjS&tZ6{j1Uyo4H7+HFqH@8@Xf7R8lOPE9?zbLBFZZ~B z^1@#IsQqgC)YjEK<4hy9mk7ZCu1a>SVS#c7S+50q4a_Hx*jt=V>gs3ftWc&Fr|soi zh-%ZaJDXIk0QNlN@@tQOmYsKcVfD$#zV>Ps$-+7y(xh7w$q{)|(#)8EG+R<$a6BEM zl%<8y$?tQX_00`Q;^)%Q&9OCAiIw|?!VaIAtLqB7=vM5tJN#-1wt~yPgad17xV#_k zBmNo^XUQ-39wKTRGVJm%-?IJEpzbxnk4o+(EYHKZN;nq^WVA(pB7PYX#>kQ-FC7Q) z{nbc+=PBg{C|c*9%O{46Q9drouhga3gzoqaJ}$>TMZsBq&{~saHp!;uPpUsFaoFe3 z8449?B^tZDyj@i@-d8B{DWziMuli9?Sv;&6igHzoc=6ci&0!3I?!9`FF2>9Gh#4AWcNZ@j;eTaEp?$V(+RJ`B!~JaWOg^m!XfQz4S*0;ph(nG<75n+v&6Xq zpJT+LK;!H+GBFWKaiGf7EpS%M}0z?=Qu;6WE1t+RBN_Z+~$roi-~HXUM{ zR}!ZotBfe>z@07MmyFbF`#adWX$3wcKAmW|J^6RfQ0M<4vj#Jm(YxrCq zD{l!peIuFb%VXi3#Hp~Y34WYFFhp%ISH^|!Vjc%lZ1XyZLFy_F)K(9&7M;`iX(zZ_ zaWbCyQH200g||HpzQ_ig{c@5r86&JKtf=wmpO^{3rwdPFcHzcU<~R>6p3FxEk@=x# zM`fI5-`JC_!Kg@aGJo${jHer>;3$q%R{#T6w*1TF!U4v{Ikyi8{jiG`YVeQ0GCx7KO-cc#NMH^@PVv$RTa z@{7ojg3RI}$ITX#9LxojP~r~_NoXx~rH5CdsXBsJ#fbo0+<$C6Et;Ot{qs>y7T@Hr z**3ZfUu|P*W@A>>1xf(z*PF$ijSv0$DHAs72hX8iXkHz%FmTJ2_Q47x@&cqV|A6$& zN)ZnjMQj!qP0n%+6b?*h!ih#Q9y{k)~ zF97qg_A1!K8+b_;{`K$6is31Ylt$jSx+M3??sX&PXG^YaD=|~gVEPr$x28zs!Q37a6lG7xG^)yPW zQ!0*;K!+vju`L-~$o7m*>v{naJn(K9;lUG-($J@N)-a1xncPKXoZBM&H9JXAMUhsM zzRR}COIpYg3NwLdAMfCO=V-lkMvUH`JE>T#Lu z{r#DscCfV(6CNhXfvr!}alL-iks2A7N%gO6MV~Ajdn=+tiO%E4TR7*E0@*4y)&-oP zi_c~7E<-7_Cc@PyAs^i5xK8w6mvtM(#u;ZulYflz4jLSj{u9$gGfUU$LnND4;%T~K zyXb6Uy`GB1W#^9R&c#O<&dJ3kBk2ZGMruj44QzxEn^IhP{r2wH-~177jitX|>cMRH z53j#N>u-?7BP!U_zHamrI)>-gQrjZE0+Ibx}*A6cJ0}Y z(tjI?iqt7oz@9SU1*ZD6Km_TDI{O=9TQAMo5a;$NU4iZEARJzfYp@SOY3c+6Q_`<-SjIh1cioLzh z(2jZ8+6c!6w{bV2^1jzQLeugI8d%aRZ7v_ z9_;-t(6`)_kCB#hPwv1VeLN%py_0d|6@Ox`2+ihoo#Y&~gCXZ-e$h^wRLOBIG` zlwsW1!fZ^Rl>tB3p}G9&`tNgyyQ)vl+$D>-L(a1LsCt(4-dmJ8q33<>c+O$I@INe( zchCOwC;KmB2)nwlW)>{{V6`$ThSf?I59t4kRv$$YAx`sgG`1oC{$#Y^o@vYiD1QuY z=SkqLO!68Jy8|UwkI9SkAMRc;p6D6UQhMO+fsH%g(A!qV1p*kVW_3@>&j zozIlVw#xp%Dm_V_WOx#%H?SYhlPrrMc$(tFlhKMd;t?|7S%%rUqOXZ0$bUz#Sz=5J zeb_-GgU7>nBNO=YWy`;g>xk!tu8xS{8HjD>s3Yd6!1ss(3}-I1#v!sHN*VFrr+G1u z$v!Iu{Rd=Eby8%E@xoN(zmMWNroSX_F{kQxzy3z)*fJ51=`8Vva;Ch!P9dXFxr^_D}UHphZA;b9G_-@%`b#mED0hbk4aDTMumgWHWmJ|Oo)%A zN`;~r%}miWs$P4Sll0x*2jp5r1F1!gw=E-qupX zfT9*yM0>D^%vXQnEBO&@A5~^?{l`8IF?WXb%=(XgX&p1~FsBudhlw);QAK{#Y8TP| z2YPSG5K#`E^KIIGb5GcK;!#B0I3cGrc6KR;Et6?cVZ~gSMa3Eq`$V+g)@G8xk)sos z*);&S=C|9_>>fYv-WsQ(38Bv42OtI`x)AdVP}+V74*s)%k-X;-*vpO$J@pbqsh?Nx zpvt4+q%t?3XC)l-+0>kmQb(Du#iH33GIf|s@{_yu9>GKjs5PEqv$w) zuPBphTI7`!N4xExEAhCd8bM5d(CN6bfx9(x@crjBTIPUaoy1>z@6yfjX~D(UK#$L+ z*q>;Z(OYDrt7v&$X0^%?5!cgzQlZ{BS!-BRC_5t3S!v`N6`EzLj8ksY^-LJv4QmW{ z?4LCDvmzS1PzXS5^(}E&;$v}o;gnjCq;38T2c0_ zpsYIIAk4@9;1c$^s4CPPkOyaR2qUse2T5fP_#?anfL*bhTIGV~_MB0DMp&vxiv+p~ z@K10e6z%LYTEIFD0$N3;aj{CUmd)XUz*HA3-Ci*@gSh1P-0z!j(@dZ+ZDl`KP3?J; zC}3bW)SJbE-lri^q_-^gT!xf?m&pT5lc1B)XB?Fd(ZVWagIZp8P|Cft2j*L+zm1Re zK+5`X;y%RIJt*Fq9OtLgZhz=AF$g^bdVhJD_g|iJR(W?C=Sc>qU3k8oaD+1=0jl>V zA_0~xkiN(*vjg@xh-1*DMB`;3cDKAtGq*tXAMT*^&=G_D#WRzYe-u1_Xzv7ejC+FI zGMr5HIw)%ZrZ`Me93qRfFzmYMnWP@}Y4iS4AmQyAerkW0T?}WQZm*+IbQ(CjkNnRnKqrHhFu~YWkS&?f|G0A3%oUJ}G;?Kb&sHUIiB_8)O z9w+7ItiCWncEb883$F7si(cxJ`ZX!-BOmc2ZTIVl5F|2<-D8so>>z)tFSCVeYA|9{ zw%1y{(Wp9mtL$7~u1<$F1AaI$Zg-*OW!hi91{U9v`SGE}GoANXsAQkXeo0%lR~1e> zVlO~Fb(#rK0BZmw!-Le;wc4qcC1*+IiJVc=I~|_@L|-6W0yEwH(fOzDZ}80Q@g`Vj z;f!5BMn67!_v?S&TLnGc=Zv_2h$&khG@Syzk>(DGZvJA{=|^nbWZ(D}2%qJ^;@aIv z9_W22_A3dMlC6R&dPYSkWC2_}aCN<#ljQ6$1@}Zx=nj(^?Hm<9o~@>!=86LU%;I6= ztITU4(PMcslS=I$RO-}82>~PD5*f-ml{e-L2-;=%V8Wip8 z^o%3bhm5D>_nnvwBSDPj^wpE=?J*S9-ll%Y03j(Qj++P}m-cDQmLWcqFzy+Dm?pU& zC3SXx7?iAB08%Y(RbY}=&?mW(>!RoT0&6!O)?4IAnaAee77rKngpY8l|C{sz<}6b@ z$eADhuymMz;rH}5G#L&T-pc<)9si&HAM<7Q4-Z?@w!8eZ`5wM#BlwWUckv}W)CPm8 z#DM7}d5XA# ztqzbdDF+DEHS2{oQ_X)da$NX?ccP1_TM8ZT>Ok^#>TUKex8nAjHbl=@MEUbr!wD@Q$Z)SM>tw{V8gpE@ST(Hb^MRJ35f^bg2YGN)GM z^S(cc>+NG)%@v}e6X14#QlK6|_9JaX%o38%r|DEjOdR5}m`wFk{ys|+^tp}ABP2(8 zB&sUxw)VF3CLBRgqQRW-rb_CUXGf^4EcpVC(@TQDEf}#LAhnAL5 zJIue2)7spBC}hf^GfSon^1@?xnIo-v%TYt|6WYebFVmEN!B)ag5;9K2nWsn-S7OXJ9Rmd8gmK;72-l4E$ zpPZB~^U3NV$lfkP!-hN6YOz&xzuPKuQyPn%C;e^MM=*nbTsLs!4|WhK0=V+j1!L}T z5TPi|_U2*!g?xsXC{VZ}3g6H!3Rb+B5j%~ywO)Ty^Qh63%MB&&MPGiwW07^8%!dT| z7%XzeF^6Uh+FMC1o=pL-fy&#khx*Vm4Cw)vA@r}-1nE}Ub?1)5ZW5B;ao5s`8|qlf zDQu22EFd|5iIb}BJaK>bd>JvOr}0x|EgP?K)U6?ZBsl|c9e0^_*r@02ePZjmU4@`5 zup2;M=Qzl5p4-(q1z~*0R!%W3^7siuguMpg1-TrrV?7}}4&l#xtE+!%o-^JiFp0S; zzY&VU-4uD1Z=%BpmL#Y&gMgA()s4tdRTrqTBpE_~B3foE8_#R+Y6@6kJuP{a#mvxI zguNkXFw8SF#VjJTsb(9RfvhnV5Y9`^KD72lfad7V&URhta32;=ILl|14IELxSI{3e zfh4xb+)x%7UG#~>Fq^n)bA~**P?vYmcNrWT?T@1DuK;Bc7(Qf zCy)@6!15RZZ@H7&@;!f_Kg%s?F&B^Dg4y9~9_mRv3SF4tjT<$JaTx>m-l!`i7I~TIT)xES&dT7)>*F{n@{J^Lk%D(S7WV zY}?zP@(quH6M}5W+uT;eZwO6#)~n*xVW-RAit~<>mx{=V`HxRO+yVhAm(jC(HJ``i zmW*N{%&IP`I+-w3lq@wpysb72M~?pE9;?Ij4Sx+5Vy}N`P2a7|&ND%{s~rN2B+0H& zCJTT+>ax5Ro5U&ZbQlkw)fFVv{ElxKFU~&k0*IUt6Kzqotm_#WO)f#~t+P4FT_%9+ z+6g!+*4h$$w2?&oHiKR*a3L63f;LKo zlW`rZ=<$Da2rWbH{&{w`s~x(s?xksUvk1afcM-6msa%LK?KCL?bZ}Vf7Oa}nrVNUV zU6`}YfJLk=p<9AeqdqE zkQ~9`0(u5fU=|@DT>ud(z^}t%1f>+HzIlI?MtkVZ72(rQM$lBTcM$N2Z`sa|3)ogv z&WitGO@hM(Z!_j=q&4_W=I@S7-*w#~y!Lr5#2qR9){=avW`lce+1z`V3O_VnzH&CX zryn4nV9XCBjc}O%5(X8k)0q{YJ#zc7RR0CMsCAWO$B4M&9p2BxS<9l(eXFx|G_QX{ zj+my^R+cteKryBafe*-5xejMeED9G4KcB=US$&Wh(^?LS5lom38`^KS>9orPO{&TQV!g?Z3_DpcWdf}(mqwU}m9uY*~8ScD<8K)TtGHh!n z5HoCiA=K54S?R)ZFtTz+pGi?bhJ*&y!$M$Sc*-pDcpNeN(TOab(-Vjl=Q`m#lxcNp zkFjkv;H1uKmX0U~{4)~abz*)tJ4s9@^UqoX`SW4^bHx9r|Lgq=zcxPc{|RCylKEM+ z=-Q^#&#?X)Bi*zV$-0_gXG+ZOi*3{K!gv4o|1@9u0&Eme+Vm#p&*r(p#3hv9^{~IR z9u-!d=@k3fY)Q278wEXbe~V_)kjbta2y_+jZ6Csa~!VT#=a zS;aP`C_12k#GZFqLbn=h9d9-6{YqUzWenz!mf5uOgAfDmwbPngytmD z*o#L@!D^O@zhM+Lv|f=Lu*Ksv=#4;+SMwV|rPj8nEY$4O$%cP&$u<`z1lCMC`o&Wg5iif{;uJ9#wv^>-Xi+*xUkh{A zr8d&9HN0}oP%r;gp0Fw6SmH*7-9`|cuwC|$l&b%8>{PM}>46gGryYzOY2?hs2($#-1xzh{e+MM1GEr&n_78sOrz5Aj$B|$?0>RoM1TcO$%~>*z zmfwb(L5UuA%p>lYN49^YDQ+CZVC^i^xAe6?gCuU67$~F~{g0oGWdHQf8+xZTr#Ud< z8P$P39sDu)&*m@G0>2M`#@r$Gx9A?dxvI_2<{wFAe&+Qh&^!{UXy5)Pv+JFDQWxt# zvnO-g3C_IPykEUJdtiQ+>TZ2oSGg&_(H@|FBuIM13`M*yil=|mi0Tnr#<#v9pm$`; zgv?#LQ6bJgj;EDE{%Ca4ijFl>G)Yn_hjYi5H?LtRyB!b3Om_pX3^CNVr1m(vvjHjTTue_s9D0l=854;N|dBf)8Dm5Z* zrG)_C5q%h(A!~mo3BXP|)>f!ZQ5k)nBve!>drxD15X%Tl{WM7><`ThvA~$`G1^(rl z*$WB6=1{_PA*HE;UM~0Pi$uJ3f_dL$mXSyW=Og8a1fLj20I3D!Oi&SyXq0;-hKXjJ ziOv50GqdP((=5SWZ@veN&oipgG%?M_G(StKI%RWdKGA=KeveAHR&8-l27RMf#|6z~ zaX_jB!b@Ky$CJ1Wzpq>5lr=b62tOG>m%WMHh+4w5G}nBY<;3nn?E z!am~1BXS9W!3k9d2eKyE7_FPUgw>9IC$RQV2$RG%RSpv27Ba%;^}uWfSe<)^$RY9$s3^(5i6k+F?3333Y#CcDw2n=*&QQ)trKb-(Tn1{`&GN zgkZ4CHUNRPnxVP4C=v&8b)2|N4gpq2`KK(W!v%N$;er{&qp^n$z+&T7t4DC)2t42= z2>ughY?Kv1d9o!z;Rp1WFap@^?ihGy+Udznv~U!8Op8%E#1&#|_=W(C{|Lm&#|4nQ zwt|10rjNA}{FcCyi^vJ_>L=tS95gH~4;Nj7j!=DOC+pc|cMsMK^XA!5!I+CLLo<8Z zawQUFU6W1Eu_by;E|!T;DzE6HntXeH{m)riP(oEA=!|5eGF{(U@hIZD%x9#!JL!If zhL`He=o`6R#iR)GHA?I}O3sLQrm9hSGNyljV?$<{MC5<{{v!Lh#S183Cw`-+t9+8g zqp~O_CV88ZmaCLo2Hgi9@nocPOL~x$fQK=ekDzoT_mk^p;R!mP0-w*!W8NiINR8&@ zIhO;VxWw}g9ItZA-U9s;^Cux2YI!SV8eBFB#9&fX4o|wGMB1X}H)EiuWfFOJpILu* z-c)rmU2@{39O|(BNDTl)OE#v495FoNF$I%k4RS%DeUCsQ>EAE`2Zhw=bj6*~24jr1 zv*A{r%PU?$+j;jTgIHdyk-FmwH;`x7LU+kKGUVpv5{cQcov#rNpEVcrsY+WJL>ms9H z1P}BtxlVeJF0`TZzanJbC!6i@^y7?>f^%&eiz36dh_j$sK2{OF5jZ`w%SNLzt^8_?e6dK^wd1sB!NzY zq%-{__4`glg_JF_`zgG#cf)@XzPt28A2arfSr`3?S>`wXT664q5q3ypV8fQXf3*O^BM&fCc&AF#3e^zq?BD@rV1WEbc5 z^S%A`=NnslkMEH`K)>y6?Y`dHZ_8@o@hoiRg3SS-CJ+^Fx(GzRNGfEo z1vSOS*>&cSR@mNP4|=)#;(u;!>~C$p*?IAN|8LL!@n-Mk*7MEBk5*Ulf>(Q+^5TtG zySrP@_vL4rR$<5kAMSq-`o{@-G|H}MW;J6T52AZP%!8UUC`K3N?oWpca3T*E)(#ie zDG`qc0<*e+_%g};(2rC%zF&Z)h<-&*txD>{g|(j!7sh3rBe_PCcI|NCd6Dx~UV5Id ztczM-f&b(!aqV!yzV&#Pvlux3x;L8~F8uP#FTdRFT0MT8rZ|7E4px6SSp8xCqIvRa z^Xb;UYyh4ZicFH`@)w>X!Y#w~Yf~V#;K&PItz^!KE7tNCi;G_b6UzL_d@*M#E-jg8 zOpBer=voV07GvtKbAp4}wRZKYe$+S47vo@|7~e$Rrj+OGl&G<-MtGlV-kHKiSVkoS zhg;2}_#80giDQ2k&JUoKCHWd=u}Q=2*pk_BN#cp~#<#@1wl08DJrnch)3pBEY#`}a zCha*oI=YA_*gi{MvQHU9=r zLaze~g5TC~DC~Ac|5wiPHKaD3qR<_R>hOUt{Yg{Pzovh`q7o8xMZ^hNeMP@IF<<=j z6Vf#$=qQ>;)i1wDrnlMBhP`>cmNqOxYS3kEWu8;L{=M6Z!#Nnct6SPKbuMcr%n*J4 zH5%ErS{m(boR`;Yv9bYP)mYiGF=)C-%4Bir@@Bqt3)@@0lz@g6 zndy#!ZNPuO6QbAddN#a-aIw2)B#N|rIU+&(Nu1_fxNO6R^YZjoZHna6g9R^1`t=$Q z2N=z_W?cYDY!g~%&<(aEsI+fYb00zF`ARN_RJukRH zLqY!)6e7ODB7)>f+|XkYgl-E(d!=?u>~7}4W@djOChd?C-4xJ06vk;rR#{?sTm(%C zxOr2ypeu&>cds!Ppedm>7b&DV^}bneHctv0eXOXo)m83^_*>9Ah$b+xzIgjwvf%_4 ztda&ew5X(qg)3k0P=jBgy#c?4RgI=1`Uq8o@yK=ob@Q;uG7EJ*Mu#Oi#XlXDP+$-X zxki6?#`kxiwT7O95t-H+-=wglC*sphe%79a6i1oI$~>P)qknkVJt|jmPk6;z6h?vQ z8j8_9hFC76V~fZ!i1$K)27m@9X>EZWN+jtQ3`y)tzPc{V#@=g2B4Ms`4H!cD!O|;= ztTTBjnkbLW2Yk9dgvvRJvW_;YGZVdxYpZ{FAslvJSe{lQR-MGPxqESOaS`q8M5EE& zrT(xwgD3vHpfr{vy7$R9Hh9wWSEs<>GlNS}60izN6lpAF1nZ9bg(rk%imBu3v`6_V zuF;qNszDrsX#OHUV4uR!dv$>$p-0N{n{geZ$Xw(a6bGvNrt9-m2!hR%ZDK183LAgi zUP!}2hJx%|-qvIHN5o)r+RsX540e;F$jv`Y{5A!anMKsh|Dyj^9{zpa!2qgvGf#v1 zT`cu_qa!#CnzhJl2~CQT-x+Jtji5o0AT}|dqV`Fl8Xm*v{YUcYUy+c(;z>F_$q0*1 z>sTcvSnWfGP?QU`vx%gOCj#@m0-}F9835K%J6B5Ui0rncfhF z6enoB&6o=4F+oN$L3F)U|H=;Yy{%_k8~f-Cy5$Y6ef+1tnBJr#`kQPCZ+J^^H}T$p z|K3>N+g}VWGwXZi+h;G<_fduDU2c}avW8#1?tU{J@^b_PIeLSMbC`d-`$B&-Z~38z z`S*X@+TCh45}1YNCSc6^^Ud&i<}Z)U=KB8D`sU{1D8A^K=+CP?^K@$;e_UKzI?P|} zZf@Nx4E^q(epa$n|2LRT?FEAv@oi`qqW2tI{HrlC@kDizXU}W+?A9>Ej8)p zYzX0C<`SQ6T&+M{*xn5N_8)(ORV2$>c0|n?xXh$n8d;_VE2iY?b$F+cO$Px#`KJQB zq+TF42Q5lLdhZQzTKNB+E5Lg|>4nzhicnNQK7q}hJ8}g#QU16DRS;(Uy#HvGHXcqb zEcNXUsAx6$BnvYjBym8n%F>q72TlYb2wlcM+AG4Mk!!}3UARe#;0}NOs#&+kkMFX7 zeD{YX54>cfI&R1|ifU3+X7dRKO~3Pi3^{C%$;j-!(wQ)w)i+{rn-oZ)u_tl0A{(;d-rHBKq zK`9&eKi>NKU8C2`F3ErB*^-(sHeT%Qyx4oQyS4Y?)$YbtICy-QLEyBrnHaZ-m{-o? z%)H#c_cyP+q+=xaWLtPLtAeqdBvr+b0&ti6Uwr++)b%r%Rgrz34s7KAYNfN6dA9p!$ZWNEAeM9M|c1mY_CV(k=i*(aL6jXGRO4 zy#6O4ndRlqG=iV4^$vC7(WZlkHXCN=Ck$;QhbHG?d1vUG^~#HwPq6vW-gh~=wkJi{ z2u+a;pUXfs$B>PZ1|C^zvU#fH6__P)uiM?Ec8>Z#$DK+3!|8r(9{_g{VrA)ZGQ7a_ zPIHk+Fo`~@JP`&8o6)N z{Kd2iOM3`RoQxqJ5b|+Ls@^+rcrD}dD0qZ}KRY5ac@^6%{>7RFaU*hnetzCRPV-_~ z^^0=6Lg*dzE)~bpXQxTE(t7O*(~fa}Hu3uVWicCMh(;B9uEUO#Y&Gg8l>wCwAKo`q z(oy+d?>~gG^0lXll;&xj#?1S`JtcBT6fgJqAsUqa&@)JLvb`iYMRit=3&81n+^wWI zdC`A@7arme*%E5{fd%J(k>x6H{mk{&xrr}6PBqjPnVqHtfMw8y_CsZfd#Pl)g3Fh} z;|#yBK>?2mt4zWi6=W5AmECTGbUQksP05bOajH; ziz*WO%n>o4F@KBL(#{x$CNt>{hh!AZ5tfDOM_MEe=v3{wUWrA29r0=OERe(R zTYf+Hv9uw`q8i;^acj8ZZJJ+{Qx5+A(S_>iHA1=JJ7qVOsFGKl6z8anCvLlF?)#p6 zMj0&r;LlEo5Pf!kAV>7E3(SL8+~SH^_#X;X`lV<8`IG&ZF$8X1SThSYWK^x7lG^o9 zwX(alzPYp2pNtmVGmKf7#`Vej-HBp^B(HHZE$BL}Q3GRVnwz(PI-b2L%286TnTLn@ zNnE`do}}5RO!75Tm$Ss}30?PFF4Q2gRXGtKuuxW^#FA%!ztP%+Me6%AQo1B|4f{hF z*n(DVV5+*VVFPen#B{zPe!(FoI&JGDV!APo)2WIyF5|ysqO$_Z@Sgb|vw7XkW^RI5 zVBe}aKdnrn~piDM34YAm7Q`Tnrjdc2$QOMcYF zMkCUEI)jUoRtV7r#{&GQ-@kSePFcJ5KbjW;2qlD<~(?CHj}=nv;hg>^j~yL!aOp)iW=PEFE5$ zKbqYzv^u4m9A2kq_6uw?f7Dc*V*NtKtuuk|3?2S2G6!9ke4OoKlwdVPahb$H?MWnW zmtGM8Kmn_lpAi8W0X&zv5dkj&x0mS=0V03*I*D{`yex}x8BZwL74`u9#5(j^*!_uj_wl z=$0S6v$0O=2a^*q9KaKEy%vvW;3C?Z=4Sd(2l|`=^9&3DSp7q_`-pGl!r|^14Jil21-$wA)(eF5i%D z8&R&thExySKGcr3{k|3v_CzmW>*IeF@g|KOiGppnTyYtq;q z{yH60dqG9%Ekz`-#T4;FBY7w)XYk)kW|ngySW~%`iZ9EQ65m4g`VB5}X;eMZ>vVXE z*d!&4{cSdja~HA1nKMqX*rz9;X{FhVL%|ZRG7kl~PRNkCFa-##MQW3jr|W<2&4}%r zfBy)5MJex>un|2|ewg)^1 zY+TY-GTitj`k>ZpV6>$*GDy*y$A?#$*)s<)E9qlO zzZL_JxLJ2g+amWop7GOS1e*Xz3Zo@HtQpxj&6v6tWp?26IW7TUNwO;8&zC;3ut_I> z!6u&vv%qJAU<-fa(W1|fg9Urz6VzYZWTtw{iInW+t7t(nx1+;t1aJuo=r&2oIN*m5 z=Mmxxvc^|9Zv?)N?ykXGHm02e+u>2!7HnXL!3k~;-V&m6eK ztdWk6%rr*Ggme@HQRh5pk8Ju59|-m&HYu@1$r^%Y477Moc|W9{lWx^FnJ+eWpR$UJ zp2&Y9SGplHTl7nH5MJUTog@^JF751UqUcWIj`m;}ucL-Kr*(nGYMz`^^Xwln3XC9m z5dKllAy3TXA&Gg|w{hn*SgC%39!NU+rKukJQ#tCPWnDtwteKMfEKR3&e<0 zyqX(L*7l(3DCY>L0+{B%MwGO6%huau@IEiE#CRnah;mAevUzAVz2cAjBUsN4|InRP zFexhp6qAvyjMlB_b{G7#Oz72BN-ia~q`8|b`$}w4%xzz4^~&hbV8j-H1;Zqd%d~&! zTfo08GGGanh99sY|J(JOF;_?pTziyuL>il*z$o-4I921BHhpE?r04s{F2;3)c4g($CWSJ}<`S_K-Ie1F3J2LT$>;{2pT+J~O4YP_J#lLX((e#SAzI;g` zYhAK>w#trJFtrEzQnEk@J&YpQ+G2mEfrEELnh&zI3T4))Zq?yH^yi=%Yw}u{R%~PD+2aJPkpJ zEmNJRD8M22UaWfi*t(eW9`4t>Bj(Scoz?qpw=Q|d+)S&c1?CV(gXAPWOBuOodvTOd z?V1;pAURcjE{7+`+qVfnFihAj?v|$}HwM;|wVaC59{TpJqwCmHSas-Wgq+=-boNMr zj1=xEt&H@9wW7q$W?4?jn1z2a9%Ky@RTd-@a}wvXRwv=o+lDcg3FfYq1!8UZJNZ@=Aj zL_vCP17*I5@8z;PWI>%)Zsk==6dAVPtjK*m-~6Fx1fmxsnSmrm@&_*Qpl)>~u{`!) zWjjl)Yzrgw10&IHaQ}{_XTwt*#X+biq=`UKO)&e8^My%o4%!*KoAteaKc%j1(Kxa! zVo^IQh(T|iZho_TX?k)|QBa3}AwG6*@j@kHC0Bicfbemln-qFPQj9=<2hX!P$ClV{ z4-v@&TNf8xeB0X=&9;bQo_Fw~NM01_2Mm)cirXVvEvXfOX#r~(j~K}g?@K3pH~EE3 z=78C;*1gfgT-xFHgD8ulE=X2Zky1y3F*5$qA8|BV+Dz#gsgoek?F3nWy+&tCATo@_ z+Vh8_ZkU$%ESa?$IrGS`G&yD+qi)Ym*&pe;En-hXeVAF{O7UGv!d1P@-btnq0jci^wg=Xn>98GPDZy3#T!uko#h zd2QCrBmS?m$zJ*+ZfnE}=x)b@+w@tsH`mPFPZ>Xu_5fzIX70YKl2ZOsRN!P=Gk2e* z`RpzI@t4Egk2kof&>E|gVdjn0;Q}rBa`MI{Q{Twp`Ub=J2K@?u!e>&^I$Yo`rQl5K z|5R&>Z^3mP4<*W~`7iCqr&T{C605Vx8w%;P-q9F0eib#ALqq=6H0IjdZ@m5M4eeiH zbLL;yAC_Zkmg{BWtx^xELfS7U9YZPzRL{b56x|8tc~-tXF~>O}D5;zcJ=H`Hh}tnWEB>;~@uiedvz6mP+R)<_oVGcs6eEBOp=4(SYkNceJ$} z|H1*&t|)<7j7R^3TVX2=xqcUjLS~y;I?RRZ9QR}79@#2?KvGjg8@(s?`+ZFODg%i2 z!76D(*b&shw)Tj2qz%_fpIj$UJ10QfaF)Y9)r%Ou)pE=2A_C^c)vNpQ%xRHjHXP)S zCi14UO5@J}J+n1GI!t!kllgaQU}CA7W@7F{Ji+} zVJs;Jss#*VbG8z(E&?V1p{?S~xJNn$@=%_EAB=jT)nSvUezp^DCSRVDo~+^vho0>; zt)ZEfV?yUXWGc4HL(b{@#7SCFDG?XS!nwc<+=#V*bpmrZo~H=rX4J{GuTSKh^K8bh zn17{RVhh?@{>a*|=>28gk1dWbXl8rYLtoSD9D&C@HzA z1h(~Dx^u9tQd#~tejzJrm1%x~RHe&w?jPn~^_7`DF$WDV>^(e_^jIAVj)-)6B55uT zsz(-ob6fCBI|`6nl#TEGQJ6P)+Epc>KG55}p#zi|BgH&Thaoug{&h=5=e#vn_?um2j(t>)gpo9!AzZ8V(tqG0|fI^QE+e-;#C$Yr5$Z4N! zmVx%oHXtC=s-w8Hv$C+~mlgJ|F5T;Ol+5*i+Vyh1`DJOnE9=s<^h3f!%>vjqFz8cM zlJ;O?(8-f1K<@)y>q*hC$kUd%W4ak`-lNpxLz&}s3RxWro~C}0^9_n?Z*c9X0EVgJ zf?Qk0O&Dg$e+E_5wn20n!~19!ymnSR=%T$wAt{rDG1n5qhKg}Qm_WRdAl(G`c6HT% z+;iMagjRtLrI6S5-s_+i?o*Xq`xSv|RX+)~HZC!x9y5zu>*lON1rm*ce2ps}8%mj2 z1=@4f+@+6CQsV&Q58+MFIwIk+2=<(Oi`@e$7PKXO3buWgpP)=D39mDD4E73l}$6^P-C0TPUI@2 z{DRj26@$`(Wqo0wg>iP!AXsBlRtAwuwwETAt~k(4SG8c{?6jo{qhdJ2l|rn4(^>HN zK70osUV$08iRs4UuXQ}A9s_hsoFJG!aXvgL$cu2shtlm3?%6GmElhtqC8?gSCMP_p znzv%IH)^?3lLGrhR&nlxeN6l`?TFGy>Xq6jEZy48VRLm0RLHSAq7m zb_vJh;M?*8W%hW$u8uRLD0}9A1=n4NluG(I;r$8+qBRb5cViR;!~*z<;>bcjUrSAX zXH~|R_PRIMwL}-hL=t_RYFwcW6^O9Bi%s z9**WK%ukLzkR$Y8$Bb}AX`K`tT&nt6tbH;uHwZK%hH~d-ZZbe_ncc+3C9&Z+PWs?J zmVY-uW`k@3sl1++X+BJ+I8(4cbGf3t)@k$|bhW_FH+ak<=FLO5Yyv}C-FZ?oquwcgEII=6aKwPPw-_-7viWr+{ZD4ha>Cg z%G7G>g^0bERS$gE-$Xw7Tln=|eShPy6F+omG^Lm`|IL;LESgd^k>-~dBwdDoSE zQHV{J-O>6K9*u>HZu$M7FLI`-PgrS_NBz%Bw|Ql5U0*}14s;bOwCD4FzoHb|NwuOL z=p8p^5sz6U2g*&741v#2i}uPRVSmj$P3n2i^T8^(lz5xm zx3eN0QIUO)+CR6qs4fZllvaGsu9)g1o@%7TaTmb8Eob?sIV3*YCVcaG*u@KhS<%jR zu9NX6t4&jhM4UTvx0-vqYEX36EOB9&!=Jp2p@?l9Ct*_=1mBXyGY|=6v+GL zss^*d4h1ql$EgT=ZBEGI{!TXMri|s@Nq0aw z9E!-nHv@Jsx$bI+rvOSeJw8dvlhR%N{)#)L8qK{fFSg$wH|9&>=7lf>ZJ9?Enz^pGt0!82S_r)%+}e zx&qGTZr~%v#!yAw#W=mQLUn$5tZkf$vZ`;V8KCjlaV{%F?oIJ>CRp>&YSGwnEwzA8LA@G40{ zNuto=Bk?Ic1Jaz>n@amONw>dOC!#0*K8u-_;)%Mouj6c%tX(VG#o{#d&+ia2|D$=5 z}M z!SCGxvUw$qiSVAd$Id-bIuoy-gmEh;jqt>C^!KU;Qc?4ryVUwS?@1_kxGZj z+6Qc(@=a=EsFT^UN}7g;pr$|@V7ZUnVv|HCA=KX!AGppKYR)P9Yo7oFw&nsY8YK03 z0^aV9+;W)JbmfyI)WtOk5c+N=|4lW2V_d+s41TenNe!HqIahOYIRJBpIVX~{V%_dR zD+O;0yH8@IqyQa2Vt~nC(h{S@nP<=PVQu8xLsxQ&QTWCP!vcDM65AJo@|rE}nd4L@ zk-s+G4o95SR%(N)c~n9WL&g$*$})%2AzwsCPf514W#8*z*OYkrdz_~f@)v)9oy95} z_%T|T98kPnpnaEJ@cuyitDkli(B5MjmNb?F+1rc$C|dOa#{SDLJbl;W6fbJypEjU* z@VS876!eW~-TCpx4|uyU9!0u2AW*5)U=img?zp$QTW4jmq{w3z^6PyvD3h3^&fvXW z4EvoSF_T6V44sxJeTrN+fHDAoiS$O9gExuvT=99UQOWHeu1qRz$f4o+t%>;5{PK?@E{$P`w!Qyf4eCYOeQIxIZEOGvdh zOY>8%$Pna*G^|01O9U*_qW?jb?q9mQP08Q8dfZBGcj6yN=b6UrzfAFeNZ)LcSh64~ zhoIE*Ftg7v%Y}sr(Et}i)0~Y1h|Qm;+G`#ycHGA62p>0p;X~a@&@-2=`SjTz#a4K*1A@SP(=3nvAl7iIzCGJ``AQWS zI_o)!CzPpi(j4sIMd?dc%0ON_-iGmff$2?)@KYmxU+;uS4f;6CTn>(7l@}DpouC}w zn1fJ3)}U+$F@ukr^3gpxNWF1M)*!hkZ2yti3F0C+Nxv}%9dd+!AC4in2W^@Uv)L$M zbZ(h?L6b2Ey5K(`0E(I8iD`cX1!G%=#X`v%#EMn8LpV(B)+p;nY*N3**Oe!J`oc$d z(#eMG%ptoE+w0WiGO|4Eluwa8U(_u#rYU&LdC@JYZdzr zSt4*f3aynW5Bad$Io&6l4cFN?Q0PgLq0XjJmKCUt5C=aVp$wfPOKzK@sE55`VDQTr zdt|7VrMN%Bbdz5|C$8JcB^Jn6KfMi4MfQDP2rO0*sy3%g%=+$*DF#T;DY4k-DtICb z1b?9x2D=EnSE7i*hCZ{OW-~91%5fxTsAiTJ^UFjncLm2u#GXs?NHvqmN}2Z|L{nQd zGYdFMi9j-P9Ks*ihibNuw3#e`9-O=etMjQvDp^e&IBCZ-iYNeNSbqUpg-=(yqs zcxhPPhsaL%YHGvLmYYByXd}Gc07(@hbI?f35T#*d(sYNeRNlDKf@tUPOV1PAR2mwd zheSo7bb+)-Tr0s$n-No1a;BQrM1NW_dxY<<2@eQO)xw68I$Nf3ppO?{>TngpPJ`tI zg)Xin;zYUhy1j!-aVf#gLB-BB^h*9#H`c}E(RzwV%D-UNumpYq`bNdF)sXrq8FajV$!=Hzd)M=c+jSbX;1d| z&qSb@HcQ7Rmg91Lbe2}+fk~K4+Z?EY&&uHmJ6esaTFHxfmx?4ar+?a&B7ur9hbaX^ zxCR`!(8gFG%@kNVmVes|6mr%VJ&&h{|K3qqOmX@l{s7|q3i?H~C@b6} zQ}d)aC%>9z2GNtze=@kRx<F$4uOnU3Bp`w_Fvh!$BgEvXL$Pc7JbX&op$HA26S3$t_{_6t2?{xvc zZ7SCuZ6t7|hd@WpSNw*m%VLYOiz-EyvB|BYbAeM*V@xtjlkTT@Q4rFd>8%j8=I6O` zHJW@K`SD=;ZY9($9Qc#u&xNsNPD=WgsmEC|gHXtJKtn8|8%GG2^3Fui=3-V)XKXNk zcb7=p;tw0#^u!!~Cv4}mAV29h{~fLQaV2OGkj>F~%n&Ng1Y z>LJ}z07ZiBCmtsrl_N)fr!xVRC`*rjNIHFjPPsFtk8+U=e9@90`BzPrtN_TPbkvpj zNEAf!*F(+~;vIU%{KPHY`%bt|7Mz&R(9*+zb(s`PX zigWBQFkMkLinu=WPY6@Ra8{O|YE`&cClbZ_J&}G7E2XD7g=|`|C-sn|1k&@54qnqV z!qSk{g9q8Ln5j#GdeN-Z`TBc*_*_cE5XA_5D?Z>r70+cvgQBjpB&WQ=Nqm-=Vn|~( z!fKhs7bck`<(QdN55TbIwaYn5zl#qwi+j)39pPG;RMP_68g>UFPv%A9TxxF$*N9jN z<*cdVV=H_Oo_9)O={muwOs4~~RE;%4V(i}Hqey%T)+Y(8n4lZ1M z3`=h$MEzBoe-^VcPc9lu?5xOUmSI7W7Q+jx5C5qLCCZa?Hyk`=w)0_8P78`nGi_Cv ze4XXPq=Yu?P4bi1AJLpBmPfxT|S9kRk-6r^BSmE=a@19KAm?`mQ>u=K;p_s z%Z~bzWf!n8%R0jBGmGbcNphN9AeL00WEb43tjNdm^S@?sStn(7u@dKyVqfyf5k83> z#-IuxY0LW_g6(pqSXPKe`w4<2VcVk<)`;DL5y zh8>TUv4(=WszACT8VgJ;N}&)`Fk^sD7+jdNu9EDyZ?=z3EZd=nWuP)EsvEUcP6C1m zrNkLJ7c2i~gNgQ|*Ms%sd=kVb?VK?ciFK04e)4KDYc`Pq+KxEL65q6k3V+T?QKmma z3_G*;EXE_A;l#v$EE&)xP0pSnTsrhG&oH7T@zoO2*aLdsy0jQcD{|~q7(FCvLMiPG z6N0~MT2w?Q=(Ec)GPjsOls&j?zIv=R35Vj?2P>lOUZ39vR3ou6c@tdJD+GYR zK0le^oFFzKss6fE(Pv&r#FJfdt_^e$jvZLQ*jSN&)gw8JVA6k*&m;d=vvQT2-95LI zi4w{N2?^Jt>0gWWQ+xqGMeO7Wl5||sDdwC>sHB8_HK~4+ zMku_06_H^oj^iK^#v@AyJX3Wd`yO2zazsPsdw4vDc$&9^-K5a1LUoL(5HnZ7$fNXF zvs*nrbF>heOh^merKY4gt+6y`eGf}(&Z>g!y3j9HJxjUsu!&SjU75v$7LSWNc4&Ru zP`nHI-!v+%PmJ8tz_O#S{@ZL&-3UR=+B=MYZpO2?1;lK1n${~Pvq2?)i|}uU-&k^~ z|IhW=ng9+Hx^{~c1W7;w7;+#}hJwC>(@}si;EsS70gV|H#SOA>G2`3xe&1!NY~3Of*H?i-^9F4oSawH3+A8hcF1EaP0cQU|CaVX&lV8k2=MF zDBQ|}hm}4Py;otgt3E>Byt`if{d4EndEQm|bN?CF&7t4#%Ap59+(3-{FJ^8ka!y0+ zDR5gHOpd>gexF1CbTt{1EaZua35uy=2^MPx>$?J0XGCX$Ee(cK+{Gm#aCSkGJ7o=_ z+-9jngt>pW1m%>+bQCUEF+4INvRUnaf@py)@MGB(?Ky{wUlO5FuBr=X2FW=~jRRH1TP&hQUNuaa5Cn>hN}8dLI|gs|MHE+m(M2(f z#sw$D7*Xa|TxdSz3Lwfl?DKI@U)IF606?yJ?YhE+4sR zMUa2(g_NcF?Cr{uu2;rmhesZNNgG=eP)Eqx0-yAZBR~=gzuV`nP&}!3EFa{`dcPs^ zKeAk;#n=*0(^`&j;VRV+7^n5gY(VX{U!m>Nwhpplu!2zCN>vV5@EGhO+s`+*{+H!8 zb$fyQ-oJciCs{hCARlf%;6jCDWVRJ)XiFqMTox`ka;x|(kx{|_Ry9I@#_o5bw1_WM zEZ4{FQ)X`(EM)&@iU+=BW@ibYQ5Sq04{OaxcsGi(H^=EAlg3g_cMYzSm;GDy9+o+#$iH#z1OW*H#m__rl_-E;+8&#lYIIuoyQe_1~J+nA6H4uo16z! z(@F2XLZ(tw%_ft$gdqSU>((1TjI$xqQDn-L4oh!i!8B22?+NF!oyOj3unBJeaOCrx z%rA}45`G==I>L%$dpr0vgmO|5SGkj`Ax+2HNEfb>`}K}r@JJbMF+O`Kx#JFBH5q$0 zL6#Bv-U_Z+4nD5^@yB0bU&jPrr%VQ78k8HZ%M>R!+prWA(;{8Hi=IuDH5QSl;Zfv` zi2j5Nb~}}Ko87}R_ojDs{9<2^k^b<9NxNj4I?5FIUYMjW zaAL%M<;x-LCclQ9a>LmzQ6E^S2xQcJr4x2H9WC`e?Mg z41EDtKN05eExt(jFm#inf?~QR&dfoJ+~A`PRR1u)j~-bcjf6!d_#|}B_e|j-yO|&` zjxVg26yh_E_GG7jvw6RIbN1j!>(RJ~y>AtLC&>u;ap+yubuyVssb*6@;iG-|H{dEr z>$?FIj1jhf&Y!*h2{MflB!FB`|1f_*U0PMe5TEEAdFoF1`1}g4b;1r;ii=-C{Sy`q z&Hs73KtCNFSt<$Aq&aaffyL$>%Ac&_uuO&tQlKFv0Mh_GF8(T9fj=f?@$tS-5xwEJ0T)z%!c)#Gz)xf3E3`BM2*WBlo@E@< znZ}&xa3LK``J#-=lv2=-&_SCx|HB;%U9>BJ>nuZ_il-FJBqiEub&d9i?v@8^SkPo^ zuknx9YcQnhicBD@ep-~%lbA{P_*1Ny$elaZ1nHz-wx){5kAIxRigHL1$RA|s5RoKS z%6rLwWt)1mq=eqGOZ^*CaNT&e4gTHpq})46Amdk*W_N3EAE!;<>?MggkmvpX?7i!9 z+uE50_$p|hlUPy{l5EGF#O{+smUT{4v24e(ok^rr1d&@3A`oBzP%<6&RDSiZshX;u z{xwxoHIFgRb6#LxVQPJseE~p^UajykTbJ&O+T=66eZ;+uga#V%u?!Qx9I)LoV|c%GHz=}r0x z4ofKJ9d!1peMyvnl$eAN4HooPMFf#a?h|0!8`V4Pq7~Sht84%+aR7c@C&$%y$taC~ zAN}Om6p&>^&`+in~FN}(b=S;kSe{3WVLv3 zf@Q{3Q5B*5j3$3BNh}NI6{7N<#YL3?xLGd|I4?~#&WJP6-JDrMb)Y)Emt_He^ULpy zHNjXgldG?EFlp0lcTcy;@gb&12t8>X5%O7#-kEmUQFM};Y!D3?pc#ZZ);$Jm#-pc| z1Qc+w=;n_n@6aaEMZ(eb#%Kr=b6mBO)Eh&GcJUH`W4ANL|g8KqT} z!3IO{EN?TP5#E<*&)^@5(XW48E`>tM;YlfzNvkL?sP=k66kf2R_-A{cA&vm`;&L_H2u@TF0 zZeOwKLoT1&jxQt#ZKXgli+}GpfGE^j5#D zK1(?$ZU=Gw7VkD!OGFM=F=$22j6Md z3cWq@QbGYw6~PX?Iu1$}p^^}R>R1^q1BHOV6zkwA3Un&@EZg}+N8v#*4tGG@!bMFb zli*6#+Z+^uWP7zed`=-3Woalg6>xvig&pwaj0bZP#P_q*XUX}0HRkI(`XKISX^dx8 zb+dfyDEVwNLwGdZ)G>yFoZ;A78m*W(F9oW83E$zgEH3MijKan9!gQ3a5ORW{T2rEz z7l(#71lQh-#n|0(otXWRjVLTN)`FqcaXg|dVglfeFffa>O*%p?D|3tsp_8?7JL13U zn1Vc$%Q|2d(A27ba9MYhb7u&079OhU=JK-Xa2W;qZg1m7+BYNDcMR8iQVd-0%ubh*MdaOSKhFGcLSXi?%# zAJx6Kl@NNYQR#wYjF-3EtTj%>c{7l}Sb>s2!HYd!k5F@DE~ip6-qD5gT#J{yTZNW5 zTfi&;mR6WA;s>P4LjlngC4aT)FN{!5LD08_V2WKe&nRJuJypucpXBhxKni zb?j(U3AoyS?J%m7VzDMWiM5oN*Do+AoSm;wqEkgfK%Z19gKLzlVi;15qjFXuh)Q|u z1XTU9PLDQnPkH1G^pGA$FDuUTT4|^&!*#xvAaBV0WcZx~Nty zOQ&arWriRc7AiFn4nj7^$ztXoe8QhHZ0p%&q z7Qq-BCE6MsD^8*VTYJqsgSgPP87kh`ba{a$kz#3EO@X2lO0(TDK+J(b*u$~?#hao z0EQ-iP)ne-;E}_Y+eI}js_5klyXp9P3Hjqi@HHfCH&M4EXpJW)SU+z@W(JUjd0Kye zy|xymeNBL{FkN)uL1OgmmZsO%?(`KOuSakA9oE*~@(m_rk2F_nYf+sX+gCcUr-N!s zwFGNc_&{2{%l8n1+b;YM?E=V%^6X{i0@*yd<0qpQnns+<_~Tx*(l1I=#n36PR*!no z!BOM1J6iV1M4QZczR~x|ahdjyFmF$P9O#L!Y?$6+f^dX+Zs+F4S7gsq<5OIfg}U{u zTf&14(6rE8`0C-b%}se1hy2ghqpi9Iui1eoTz`^Yt7!VROEp@l`lT^B@gnz#h_a+C zpGbgf-b;y^g(e5)t=e%(zXtr}tiXl+bRAX|S%F*<#cE}=4}x1<+INSO*Z^1E76w6F<*3;U*M6)&O7nBt9 zgANj{afYrG45=#4!Kh4;1;b5skz`A@Inxt(0h2xx=>*ntRW$5SxC?oXQ<-ot#kk5Q zjl}t)JiybeAm8IAj^EVZPVx7Devt1+KaIZM`u+UA-V@K)YqoKiZx_QMOc4rT7g=$N zq%e&WA)gq{rEv@E()pTs@Y1UFXb0y9usRbKrq+~eGOodE1SaVw{?Ym$BL;VufjKEKiKQjt!amB@9}{?}nV>ra7c{n0C^Pm{tIP^q{p7TJaX2 zOiu}SJe~9@pbDy8rK?aME_5U-J6rU}z3r{lURch3&?1HYDh%bl`@)-S)y&$Y19Ozc zt_oDHKYJzod1W^BvaQ6V0xP?(nhsG58%Kq!tCW4T2d;DG$Z=*e7~Bou&?HpkY_+^) zx>SJsHstL(OQhF1Hs1k%yW?K7MlmB*x-gS7295_ytC3l?Qx(`KuT(8TkZ%^gu}$kv zi}8v{TE3>?`V_4Hs4TG0bk`#OCgM`ex?>AX+2c%0K>ajl(v*PY+0b8DIZUU9NwQ_r z)UPP=rL`71rJP>FYjkN`5ejw6kl%@P71`Y#QkcR0bjLNTTAL7mbjYimlt~UbAR7!? z+=9>i#&gTkO_{lBlINLJ-Rc_r^7U3}!jtGE{e*pI%3+6GLc5P#p~DZk{h({DC0eGd zA=WVP z(8DQ^(5=5)HPGmZnbTTT-W;vIiuP!VOT8sjC6#!4QBu%Ua%SDZJQesRn78s;FchHCAVIf9dSZn@?tND@XmWP zrY6~QOP^nVO%x97t1$zmuW|q(dz4F9RNTOvkP0Vr>fMOHecC}xcbxq7wC0ztbQogR z*iu;?Jq=zqBue;g!CoAzNsXjl8{T7!s?-OM=Fyq@iou!LfFt`RL$_lRO3SQHz7!*N!pwaJsb-f&WE8+Na`;7rVN z7O^~abv@eM|43zCBIZI>YgIuYD{issDTg2uZb;ZBgLJG)n^f@!9uX;@K`CU&O5%9} z~e^K>{K zMuQ@M%aT$EX<*}W>tcTBn#L|F22PpOYX(xf!qgIEs zD1;5J5N7u*6hj0$V2A`Q@^^IkPzRs$8;6Y|c1Xu*KJnk9P?iXr&)@&u2N!C-Ml|*1-+vv%XQ3$5$|;txmB+KzkK4 zZ3VhS%#1EX?^g+rhT064N4U+Vi8N4uBanEP!B`GTv;xCT>ApoP_9Bx65WTTieXqRsry-f2lVVOZ)qYhGkv{Fw- zg65?pI>F^X?nNibFomv*m8?GYIR5AcJxwnt;mA4VW?1t8UHP~tm!5i+*Y;J=%EeF; z#o7wpCkG8ur5is&+i5;TEyji?KRX=2TIIw3H6h70(yD zSoc-eCca?vj#n$d2dB2$K)z zV%kz3y=$jIUUl?dJD!y08j%|gq$LApw256@m`LU}q=J_M6dU}27!TNg2+j%VfiBK1 z5^$Sb?Ss?Uj@j-eV<4jLN}L8&LqHCVb1UbiF0icyxns|p>D{vggMA^C7<|`yyp_jE z#g!Yj2+uPx#Yq>VU9l1}61lhqjY~n&H`bu$UCt+jZ&`mIYD?(Y_Pglr#Bn@{n2KazdMN)#bu)ROAIrGT@k8$X)pBwY9@Mya5q> zQa(mo+^d9X*7O!Ak}!kH%-c+pWo~Tl&L)Pwu{|w_US1%OJ)5p^c9-W4&BfZZLM>Y|HqH&o)0(4+1$|-Gqd$2-IEL&? z;SETSaQ{CS?ntqugGLZ_QW$(`Mjm+B)iChd(qn14hdS&((J~PU0!D#j$s>uz-lCHj zvD7G2&_C^*t%O(otRqdvT|?)kRy8=Si<1CI;nmpB22)snXJZC`duRUIOSIomk8Hj) zuX2QVA~BlDZUlv=WTo!{cEEK~^_iK>%sFE*zEs6Gw%vH|dRZU~=Jd#MJmw}|a9%#F zT0-us1bbr9on-S_q*mUU1ddKok~T6yLRtsKs`9xU1h0A5wlF7sTBbdfW2|)5eKfyG zG-Ip2L?H2hEW6rqKiz1xhD0&7G@>)j^&+??&keG1%>%YmDp69kby^ypjX9sGyc4$mkW7DN*5U^8 z)9y#C>};)0c@Cx*)WD)bK{3)}T-hAxHaYlXxu58Nh(KwufT97!f;+C{EJc|aQr=*V z-PvOHY0dIgQc%0~na~V0TwpAr=q)^Z?i|tya)t%<>KJ!14m##b>kG5?@%q(Z%RhL<9gqrT_ zsKnua?qRlY%C&gJ5&l;;XknS^$Xa8ismCQQ@Frbc38PWg!ZS@p*UK6UUS5B?H>~ZWUNVvvw+@d=`X=85xEl* z#uY{%r^x8wjD-Wve_Evlc+h+aU6PHnwYpb-qxQTV@E6iEVeEC>{p}-(4nvQf!V155 zG!Pd5gXP`T1ZZb4EZER?v#UyRgEEe^qrCMi9`FI`8BjWkRGm87`T&}vhX~{hVU3lB zfOPk25_H_ssu~ld;O#Drp;rJaEJaiUCWTIq)}vQcU_`DI!QBqp1AM=hn{`yYgYJcY zJVqWT+paod#SB*>=D!0#Cfr6lrLLw&|$7UxViO zz&L>$ENx-C;_AggT8*+~VhN``;OCWB3pkCbRP#V6c*S3YZB16s{Th@NdV7ITskx6} zlqoGUWiYYA8e`2rXY&WwpLe|ASof)a=q>2*$~)3e{WLkHh$Cg->j1{l?-1efb}!;1 z-sN+aj_%jsBi=m8`$Avbl^N3Hk`sMXD*7OgMPp2?V%Cxy0>FgL+q^iPn&vQ7rBMs$ zX16DLy!q&9y!rEZ^AX)VSP?i?!=tfrZQZklO=F5HK!t{n9&bMSW&CI}-h32)3u`zX zj!qQ=OBkRFaX_3qwkWR@C3EF%7exwI{R5G zC_}uNqpJP!Z$gHUlGl2IUtZ;^?rq<|R|T-BLTZahP*tE=-BtZyR2C>(7tP1~qJXto zu`;mq@yCDsC!AYpDR>6s2)?R+mup*(6&!VaZ&!>Q>*~I^(P#yvmLgY9+EGQ8fv%h# zVp5oJ?8l4rj&GQ`XH>1c;>__}z2{T>Kd$@ochF21{^07J)7UkB33&T_g&%PD#_gN~ zLVLFrS0Dqac{f(iJ(WEgK#Nt=Xa!7$wzE(0KfA8T#@cFm*y@KJ-0YNp_im>9InJsa z=KI-Vu6Ep-qau|WOujKo1QqN^&|bBoHJV8uO>yB5cC4y^=g2pP`JRp%ssZM4E8Cd=f#56K4@Uaen1VuA{Q9|kN^TVorcPxGJ zv{y;&#?6|OQcTB4P!j$+sOr)rLx92tLO$hH{93olPlC%Nv|s$5y<}TK4)^zdlI+{K z3gt1FvKPzC#stXhZ-;O2i9_TzzatzqV(Ez;zU)^q096b>dcd)e|LT zb8eH-NQ(%j#R>*Ku>J- zzNeE|LKt@h~+{MMpT40=81HLl!5pz`0Pc4aW4`+?mf%PKA`#We)FXA$M>+=5KokwrEG~=hyyR zatg7!dIlALq$DjZnpONHVcz_>K%E9qZB!Lf)qr|m-_xEO+0|-!KFAyS*Kbk7PPA{X zX|1bO{dDu`EP-&XgdPb3g~0^RJ{t+um?GE`=(mSERi>=-CCs7FVqCMLgph#4@Nxt1 zy3mtzNbqT1wF(ilDF><+6S9d&9Ro&hP!bJzz!#2xs~xo+q6RlW9}B{1@%1*PBXX~) zB@}Yyf>vDX%)kUeQC1a#_9!CO+59{3h8Vb>aS4OuI+uwoiOyBPb$cp_0x8D^w>QAl zNO}X+m(e9X;Q7qb{yDzKjGi=$LPn!}>NM_{2x}}=XGK}}Sxg(?9R{z4_z6Ja_}aHt zsFy>3^vtcr?};D(@t>}KZwdi)BE_wo|KWONdP%tgVMP!R^pF4ePen2~E){>jxbdNd z+RzsdAcS_;9~2%H$Lu23)`E ze=x@)8v8HjA}f-E)X0PK@j5bA}}}+Lk9(^Z z?Y`gNqmGva2&u$6;hL*aL5Vj(4oe_QYkei#Lbab%NbR2+>}+GDo+VWzU~4I^=s;TQ zVZs*EAgRvCyin96Q!x8S45DxcUCLR1M+?;HqQwF9vz6fDpc^>Nn7-^)aT;yqNj9m| zKDnTzn;pH_6(VOa#JIN+(MFPr5nkzv4SXqYt&8X)tw6K#*|4)hbrq*tm&b;Qs+M^Q z$&^iHbH<*_uoD7$Ts0Xar{JN%zb3l9BmdbEV25yeBfic|4s{V-CS@ML(xpm&ayrqJ zV>OD%|MK{>s&z4`btedw1c1nHzmm_L2o80r5NF@Sw_AwrFgor5A0DM(TBPF;uT59OJ%>W5^6mc}iPUkxh<#Gs~iM zIKsUt=a!?9K;5-Rx8l4=R+XKQ*+7_okl>5$ZV6(d@8k+T}%@h!YkJ=LYGX!wv-zR*^^EI&tq=6}~>35EKB*#Z{v`k!J;NC9%=9Jo2yO z(^HPnn-Nq5>6M*HtrJ0tK|Y!KVgAMb@e2%w1XAFfEcq$gAV)|B{Y!*$P2fo(9V1ty z{ZJG0#BB5h4aadDb^L#S{7Fe%W!HUit3%*hA(bkT!r54(ebg4MHof*5z{<-nLK6rltrX|qOI z7}4Pug9zMz)^0C)X)dA{#V7sPW6$03^2Mt?v7dc(^YJ7~24tvmIb4TXsq)gowa_58 zA#)LmGLs@V50S{W)D(nX^OQXpa^V|Xvafw;H@@^u^gA>0V*|>Y3pk{B`Am}AASB_S zHP|VO=xQ@gSxVsYk;VDkqe$UKuwiv8>BYC`YnOa~=YzMNP3Kuwf-I_{6-%;?Kn;w% z4Yu{%c>#kP|8glDM@Zd9rt>7%1%Z1^jT;#=lnMu%Jj~mP6ekTdAK^;mXj#wcwbUtw3|`2|qgYas z_*6qejHX|4Bsp{t8krh@niL1QPpR@RDR=Z5tY z5~>p84Ygtq--Ub6A-2-fRejEJ5l5qlut;Vk9G&Kx3t2*kezqPR2*XxO7+JNGd0?Q% z9T>0ZnO`=jmPRln3lp5znQlV6PmiBQV&{@6wHdS8_z+J#)Z0^fHqDmb=@RtfvtR*(VN@Tut7l zLX;+_d4Z%h$zh))eF>z08-mzK;B3pSD~%u5$?+Y$B>Am`S)4=_BCe_qJfa{g-iS7L zzZP{CJ@8Ra;%|`CG&hFPY#?oMP+LL9S%duX&!V$pToUp}OFoM-I!!39K^bX|U+Mb@x^?W+g+(VYzVjUpzeGsn$?F#m{QGXZ& z8Ww_-=TmSFp_C5 zCm~kw?nNtU?e8>mSonMoi2|yGqw27%I3*!UcU0Rv8W;HwhsZtR#G@eqWFSnbNt){S zudYg}ty9?~p=tGTJu7YfjCZ60nmjuW_l?j$1*&+o61HD|?QXd6{>HnV{r5Ht#~3FG z?$Z$2nnCfRkd2TVo(jza9zA<((yzR8Pc+o zjYo$rtSK{pD)Mlwj5w0h)*=`5MW=u;RoHt;0G1>XL_Dbqs?&J$BDzo(`Zfh~2kl9_ ztw=SZ*4?UED_igOR)yR^u%el%=?<+BnAW7piJXny8q(fV(yHiLHB5RFKfMhMhQLT(vbgH^61dMWY{UmkO0N)$ba{@9kBPqiHwzv5r`Z&79*EVw>S9hhO5WRTgfI$Up=!piN-mRpwLf58qOOx z2?8}G+?`vFkZcK7Bq!`i5|YbpQTiJgSKQPct7=iW53|);6({EH1}M8$j@tme<;bs*2of&A=L0;lR%XdQ-|e# z+h+43-U6?VkTxL`26dDox;>%!0O6`W<^&K5EzICnlk-h*6t0qxG7gwv)NzQBr-+R^ zpe3Y|+tiALnOZxQ$z<5HT4*ofY-_m2?+1;qeY74Vvh5FA-J@j6?K~Fu(5O_21=3mj#F1@$uur>fQ3sf84Mg@4>?TU zXg_ZdNe>M~Mv2#)lzpv|`!YvZq_A64dzP9KTC)>K>)?jP|N2AD`RJ5~`n`XLtHKUb zlB1%Z9>G#9I42I6dj&^<7~J9EaoeeXaJ^i8c9=&|3=$?FX3&iv@Fl*xHN^RbIw8b< z8iQ+%2-^!Tb#av!@str68_2~GWTz!-io#GTjPw{2Jv$U9F(O1H(a@H8>CGg6*HuzN zlsa|Z@$XS?B{AP@f_=>1)h>9I)WmiJgsv>`&B(d;M~(2! z;a^c;;(tXVbfLezCnw}AFM8(L*JG25N2Uy2*i`@3dc2?^M2L3j&)gKh28cBy>otW!f(d8@1a+ zwbd6Ca|aL&i>5v+PHBVCH;J*uAQhcfL%KJbJG$pKP0O?LgtO%~oNiIIjZ;bx)A-@6 z2oVyHO*ktHXrB+3Igs>!N-d-KxoW}o$cZ^HpI{%Pxb)!2aHS1S;9I)%3p>g=jYy32 zOneAEW6%DfyRsbu2u!HM{GSe9rU^LdU>|!&$qxR zEYFT;6*y}ty879Fl*R30cHX6LQi@5dz2gVknp%#$2ju22DL%kO*;j|wZqr=`Ryqs- zM_Cf7JF?Z-VuZLZk`|8yMt#LwupfEhllI;HPSNtEiLQQ}DI@^+$ipmWN;4$%l`j zPi}`^3UuUu&4{U6B+T1t15DcO-JG;81)E~Yj^*u@4QlzLj3P+NGByUJIEjwpN1KGZ z7sgE)pGTWAAeRWboq`F@L)uPTustsss5r#t1B`H~tSfY3j>gcFccS(-8mnH48A$C7EPpt#3>B$Kx^=U0Pez&negRw!eqNOI$B zR018kFd2?<86EhJHQKd|ZsHY{Edl%H^R1O(t*7i^3}|acQb*475)bwUSyviG1Z~l?h2N z%{z*JHanCuRN~Wi4`~?dTFijKVZ_Vw*ocM4Kr*4L@|fWS5oRDtW%A~z&gV-0C0lax%nl2HP@t0 zhP}WwW9PktJrZRL5LV+D*j?N%zTHLKsA)HUdn~U5X;_hpJeocXP-?AWpIuZ@kiywW z)5m1^7%K5l05%BBZD*h_02w1vS7eH`Lt^#St6ne**Y8W`w0U;{nEnuAKL$9#?tL2o z^=h`5?$X^y6gJ2v?PQJSIQ?jbf8#F_Lw8&7+>KCkes#)xc)6c>c)4a94!t>3aS@n* zN{)w!3q+#I4#wpONNhm^$^^ar*Fi*bFcq5j=auz!0*>LO;v^rm_!C!UIFue(qO(1T z=$jlyl*?4@|Ly~2#{r}C*zvE1@y&wjbFik7r)vXO>vobEbzDCAZjWnn5SMk@rJZc6oyS1@fx2@NnENb-)j+W4g{ zsGF&sZ34G3jV^>o-n8?iR$j_l??pTIzf9dew=EXYg)I0ea{rc}Dpd|j*NZ3}5CR;t$=PWxFje=+1&+pfon{_?paO%-aXSi* zSm)Y~;d=XEY|oLS0oF?81HMVUX~d*aT^*i1HmI#1!jLQ?WrHJCkHg8By-yWLxh@3Gcw)hX@FW{@bDs%RxR zX>c#4DCMi_Fof)wgUu1+9DGUuk%V-AHiW?lHxK>TE``+**6`)g>!RM$f%(2D{RIAz-ZDq;-1{Fz{URF=^PU|($zNI67Q1^$J55`x z%_Cp#S8pJ_-7@Ka*ss39H|A1Sf4>wIu%vXkWnr)p%0)1K%)QV$Dg%`H2*o2@y#k&A z#2$RsBNtobkWFJZZ!aqT(MI6i!3F4Lkk+gR1E+aC`Mc=0aOfzgz44< z=MR3wGfUoI7K1VCEm-nR5ku1RB*q&ydbYB&#hq@PJd_%LI5E)3@Vng8T!JIm#0y9? zQ9D3_kEW`rf`K6l3Nj2la(f;|^-)~2Ewh$oqFEkf=OBUNS>tmAm-u39AX5SHlH~_>-2&OpNmt)6453&`V$<6ExUQYPtwc` zj(+^df2uMAjjd*vTWDi@tI)NBfSaA0UR0daCiho=WBYE>oLWkZn|k(nfeP+rR|gZJ zgUS4)CDuRP>72*%gBMW>;tSfT{%!#LolXlsIwHz?p?$}e`_Y>VQ`+yEf$N$eYL0Fg zw`iI5%=cVvcxfAXJ=z{cp(#t(@0E{xQI&p1dZKyD_vl8?h(Bi#<)+3_L!qTnS$u-s zIPu_ra}u{Tqcg~4z_UrK^Ir5JgGML*dsW9sZZ)z=um&lxYxkmy9KB;;jNe=G6DZRG z2nn)}EI7|B3uLyK(jJ5_S?Q&5QFvyoi>xpYEE_2w_sG|xQrY!U^~jr^)3iPtAJeSZ zIoe1*_mj~u$v0}y$`6w?-w+;8_Olq=MmuYNdRHLGOKA)KDX^xaab3YM!D*!Ci5VP4 zEAPv(+4w%ms$kV#o*B8r)M$|bksv?hynOSIZDMR^Qw7aaIeDy@Nq|Tp3weT*fNmVI z0Bu=?JZzkMRsma3)s+0aMi=gw+vN{K%9w7be&vZ2xzE zA1W1UW<&yNZan6w_VGoDZinZU@>ra|5?;7WCe@79azd1X(+VJa_Uv>~34yc_oc#>! zKLXG8JS&N{iKi!y7)`7A&)qkpqZ}fbBcJwxmmWt}ss5lD0>4gJZ?QpJO(L+X>)txJ znt1KH27GUkY6Mzz=PblbCEQFCC$4*cFWfnN-Q(D$?$ESfD|l(LecNQ5jJ+2KN&N!NR$%zy?6 z2@hfDk;BYe^=$f;pqS4K5`9bZ8dJOfYAZy-0Y=CnEHF6XY;wyH60%%7O<4_p>Uvvd zs=)_W_0J3r8)tnJ4O0TQtTNA{{ZUb4uC*aClZ8Tr|9G1~UNtJ}_+nTAvqdY&Lfu{0 ziy~XV6TUg2;YRc*PO5W*_d6CCVx{i0EK~Crp(VEJ@eP-SIuz=)v4C%xR zLoiMrodBGO>v8%e5%q@ya40B$EEnECHR9Af1OHnxUlg{o7+GP8$wyxn&c+c9Pd?CFSzni(>1AokA6Jt!{oMZZmtIQ+bxFrA4HeBnG2 zU96>{a=dWSQn#Ic2U|?=r7!Hf@*zdH4<9&E(^x&H4SmotWS)TeZB7oG$M)K@A`PqR z^3f}JCu&Co%Syf{*`$JhAI!Ed)7%{V)9&8eH}BqWy?*~^{F|6bz;|B(fiZEoEKjmP z8t`g)Y}*pa@p3J@`yWADC%H4?KEc%h=3(M_B+0X8MUWTxpV$XOR-tb@cOSI3X`h#9YkV)CLH@`%$V7u{&#C-ak%d|g~0N$g`&3|r0w4_V>z&zPLy(6&#+o}CD zKg~?DS5DF3OSC^svdn}heNlD=;esL9@>Uvrls(2^*ayF2n+jm8(b=T3_LYJ)qA$_5 z#>gcnBbn_m>?CjNst*6N!0Lzza04|HFb$>lnGov8H|2+lMIwC#Itbg!qw2T}ZH zT$9;(_+Z+1gv*NGD)f3hh(UFjuOA+Ew-Lqk<=?D4R5JK~zr1{0{pI56!(QY*+To8@ zqxh9LPxKR$RQ0&RH!ltT>oLCZo`$>vdg$or$QoU|^L&g2{xoAdt-J%1;SdS2K_lo2 z@_|@iTMrKbf$?6kxWpz&3m{%t?HR=sXcJT&n-b6axJLs?RBOqoYIxTmG}l$_g6H(@ zHxe0uH(Q#2Gsu%)m}q%x6_mDnyMb~Mjn!U93za%`NB_OdC;W}DM)7jCsmF)aAs z@S1TK45`FG`VywJ!>vfcou|b#6DLKcoT^M6#UCp3Ru&({$Br5?gN`YcCFUY9;^Ymn zxx4m%GD%3u@^5EY=eO*@Qz<{)@Y{*09jCkHL4s{=fR(pezf!K*RmZ!NO}dAVVr3Mr z!a%(>rmT+OJK1;`B@@Q=Sy58OJ=TUC9~$`UTx2uOoKV9laa$+2{)b6jrk~V}vi|$* z<4KErm}?>2{p@2=S-QKy#qK(a{jBotpb~0-D|ew$r!DEkF^o%uV{95Pyh(_s6D-6w zghZ^(BAJQDvEaRjK;2phPN&euf(1M!gT=!^r=1S~YH)oi%W7Ess#p^U-do7K zjcPJ#!DFVBvPz%lpN8LiTTYfO@=f`W=ojT6c<}B^pXN|hDXl^j|EMlQ$#?~zSaocF z4*q4ysSUlkusR=c0%Gvukho)!1kO+8US!T2z{zAT+M!krQQm#5wGAZFWQ66OwV_aZ z4^un0q$_Uer6D->*9cse33)$XCDvLMemPA*q~e7@2L<_{l$f{I4yVF2 z2B0NmO@<@7;yGi4Tct@QV}&^-3@Ma&+UaT|i6ROS&-@$nAdA@=^X zIt%K!Zd<*@^6P__chIWhi**XznEi%^8D4Rs)Q$HKSb>dWXNcRko z2Ena`h)WGr=0fF~DFv3dNmg5As)0^|twLJ_xx=sP;nW)d$#MyA#?v%n{w?riHCSqYmO{ERWso{( z$jDv@s8)2Zz($10i8W~Qx)f0^n9XC>N`Lw!x|*FhMq{t+|5cPle-K40P9VsVVMiN5H){lEOwAwGn9Qo7-RSp}Z0CGT$zXj-uu3?mlvbM+ruUU6Bi~qpiqmte( zO`TF;FMNGs+79Wtxg2g>5yWRmh7&pS9VNlEO4Fg@XM%LMKxYno*0U+}f7}Zs5ena& zwv&^Wms}(Q4+M2(6S}~;Nv%8=7nsO;RD`Ljli|qi2O$h=oO4buz!7akX>D(PPp^dq z{6r3gNgIssXCAmJ#4w<6{b2&d#l^5$Kgg!W0ICf1f=yi`tygOTjjXsekt-A1iCo$; zhPE1o0TQ88*Uyr4sL=@Ge{^ibp*fb_@h6)bWCl|k{8iW2!@m1Ol|xFVDy+t1Pf=J6 z#~JS4>%pV#OWd{dDmZg3#cc?tvCtUlrQvw3w33M0SVzbL%Yj|k?!-S6HZqFZUSH5s zD-%|cpt?8Tr_(JmV%1gNej02cHyMd3AW&$_ScWfxAW$^{vqUITf1!ubtsxW!Q$u1E z-to4K6Bf(*+?Y|DCy0|;^w#jKG=yR;qOY|G3A5kaN;KTdjh&PRUZ9;)t=x-}iz21G zh>%2jK71^ar|QbP7_299*XCUU%ZQc(_-TE9br*77bZA+^+FqqDfxD#&H!uQ1P67wD z@rk$S<=pK-kJeL_e|-tPR@7_W7f_#1Lc*`UfRbApyzN)JV)oDwFHnS^G_y+)ntah2Q|l6;1_e&F`UFBO=w`12pwF%-MP>T1zg2E*w;@LqRU^n?Ys$Pf zd6EOEJW5gyB8Y8=hg*?8z`;ARO7|r0Lpeu^OZpKoEk@wte>aNY$ok|e7tgS_5S)o7f;4&nudr@7Sa@7g#+taM5DpcPMA-_cR zoD?e@Y3-MEe~FD)nJpIMRRV6}awV9IM^Pi6aHcSnAyoR$o*XRE+2k}efMJvSC^Zy#m6u@xhRfXRB;iDtyGQ#%Ngs3SdU2ces)ncR+HLt6MVgG` zLP8sE`?~%2&h5V`G*7czJj@9lDv5ihRyUtS%OgwkfAb0!;6MY#EoCiXk#tuGvdT84 zuM5C2tn z7ww_$8l^G?t;mM5cogNvuc9yFOT6VjM%(s}(HFd6wP6Wiih(I}clKWUxgtv4HcqlM zAAj=tek36xQ#(h{2cH=U5BvVj_J@6{p%^9|PtZNvZf!OM>NqQo zLkJWr+D=49c7w}t<1PMl3m*blf-Vsl>tt+U$dSa(fBg6V=;$HAjAMNY+gY(ZjGncu zuD=*(=UcD-w7^~;kF)b6`@HZD2mf3@PWxtre;#*ye8chW-SPX)iBh`lv~bCyZ-m0e zRP5A3-=YcVTTIt4hV%@kgkMm9r-21;+hc%iT$kC`yM3R5Pop7zVRCbl))sOsB=-v% z>SJ!bY_xvO?zeEG=-Lly{oC=eU$Ajiho+tX*9EO6gNw8(N^}Ai2Ff_%E&i-y81JlG zf3!Z(scE(19X)A~YR=OGz9(b6!+Bc!ORMZ}{B2Cu{>JX>mplK<`fxxuDRWjry7@c> zzzBJ8P(FRS%82OQ@?yWT+KMMl|2HPKyT)2|hKEdXRHmnAb(MbBl1r`fiW^|5 zvj#sD=mto=`g%sxbzcXb{Bcp7^LrJZf3P-QYP+C>wfivA@6R%*6en`)PFA{e8l&c7 zue87TxVh;TxbO**efnc0f7CZ{zvc(U z@}%aH_r9m_^6oEo%~2Qo>x{26LI;lOBFC{^wuk|`vhefTXViRzGaM99A5?>He?pio zU=jYNx~US-K&K@{ZQ)eyE;^_Gmi=rI<2b;Gd?Nr(2ymIxq~1{#WGPg}TJRb3uEe|V z|2O=NWHjn}vC$~nmp8#7L?pV~kPoX!{>CXJtHIsAL1vgQ3paD_Y8Z=ZSXA-gcq1>Wzh#OjZI}lQ zCTofw^@)ja1CeWRs+9qaI3fO#Lhc*F3RiPl6TM~LFw*Q_;f!vGLz&XFTPEO-A zKZC3b&IF9k`vh!^_M>P7Q3s^6zRbJX7ur!Dg*vX&OuSr~WpvmFk$T@~%kSwZ??avRllPc~w3qWSQ8ETS(CVb{((BSft1WQ~hV0^oKF(e=X@=v>oO@-u+4t znF2=P#{lJ5>gI`qF)Gs>vNstG`P!O)ms1r&QLe2qoWHRiGIN^rC(G)xTsMvsC9prx zSCMYoY1X2Ajcx|Ek>@#geeSBZZXW$x!1>B6E|!%1vc`wux3Nj$WWdF>{CqYPsN`Ji zg}a@%Y5n?!WGOJbfBePRD4J^R6<9Eeo|>ZcYm-zaHGth30jaGxg-YyIxTDqUy|;`fK&bLhR@q703MRb!^xN zr7hj*ahhKgDce)>pB77O4w!;{4QdLEtf9BSPJp@R}Mi%M-iS>si zQG|k)5LKv(qp$X)?%HEep!$1hkS<`=Vl+9VW-?~)$kL>uGQF_SfdDwP>H5l$GUR1-!?Fk+FR ze8Jw<_BJ0+s4KbCYiVq?w_v-{DxGS=t?X>A-mOvUfAtP`y6v6~sYcssYny{OL3*nZM;|17j-M^Jyse`gl|G(T^=h`@8%RwxK- zeeGSlWXCZ8wwO<(tZo!EJyU9>i30fFBzI990Dg=XwLeC5y+#j)d?k@Nd4x zo0Er%MBzBVGJQjQ5UttetbQ=ZU!l+Z4>O2Cq=pc0JQ|n%Gn8I*fTo(^%YTkusBz&r zt4++*^|#}VF^3Bo6AIjF;GIIEQ?{lVM7uISLg?*#C@N0@6zksM^yXXAXrpzc&&jutlU;nK-iNk0y zU60jl;aQdGgm7e}Qa}n6kfr07xy!Mgm#EHm)?>w6)>sKFnsD542M*=tNWN>L(7zsJ zrnl5d=ZiLIu}VM`?q6g~faQ~6wJzY7a-$X}{#`=6gx@%vM#OW&3+#* zsP0Kw+Fo)G`^GbY-Ps{d2Wc}{e+s2LTT0b8BOvREMSdVChIqAW#E0=~+VQFT^$>(Ko%(m&p>McDmj;ir-? z=OEMl?|t(cpP$iqS+_Z5sQJGcmu-1#7yZB`lJOCWtF5jjRNXUEDp#I0OUp~k`LcoF ze37?KCp#WwWXnr4A32YPe;!nE-?vfd-7o@i zo#TF~BmIqJWUIJ1iMzh(isgL494Rp97sKO}Bu;`HH$@%oj}$R7bMh8IL~_j+M=4T_ zo=$yjjx+&@K8Xldp#0T#7)B-DrJmgNn{g0%=KFR3^~w5QM?v_QaQLj{*QpF*Nh|BK zv}CmsIhqDtLE2qOlGKU2h_s4&yU0k{ur{FDhHNWBq}y*l z^rE2|7UiU;F`-_Rn;PrS^R1jH8}bAo;?Mh&r4qc|d;~oBd=ls8GSVZea~>TVZb z6~Uk5Nd&+Se}Rq6rx869)O%(0*J51eW&(v`#4fmMKDsEf@ldI^HPG3IZs}QakveAM zdptOKtP&%^5bZL@Kh&_3^MKLdGR+6YWn&<4C&)1Li@ZNB%e!A2e)L7uIN8|5$C*>; zT->pFC-3l0|Ewrb*aiZ@QHd&r*xhGzD|;F4JHFAXe+0M_4xfBOQKSAOrY%HcnN|h+ zE}U#lt4W-j^z`hQs4pwa4!JmvpM|`T9+%zQrPX~ zUp7m1KK59_1*f3s?)~%e^?AXk_YOJ4jbxNIVfkK-QL`?rJ9Dy(vXQEuWQJj_8{q`f zUsy+{qc8I+*Ua6Kn+iEOpo5C~-3#d7H4p4XMaQoXq`Ee)ZwXn}MT%-+Jv4>AT0p!1 ze^P7Xwi9-nX=ue)#cSU1@G2)snn`@}=*@*GaZA)CXg&v9_FJL`Kj*o+5Y?_}%ktVP zUGp_GMV0G4yDdKr!|~Eqmn>J=Da-ZPljXXi$-{hi|08t10anPM*M)nfyXwCw^C&9c zqEXL!4qCNFvTSz6LTos#rO>MU;TOX$XXf>+=pKQD62L{JP+qnne+T>CzW+e;a^g zLJzc3oz&o~JAO~}oJ%t#UUy>39txDE6IwV5F1NTvc{xa0+Sn<7Ydv~TtS(fC?6@<4 z2OigFMVWqv@Hc9zu|jmPMr8r@I$Baqjxx*+iTxJk=q#bEFfB}0U(GMl8fF&u4I;F} ziG1K@scWy?@!*RpD$^nPCjz6Bf1$3bvVV}Ll^rXJt0`VkKngU9#EFDSDVXh%mZA;_ zZPI`{JWEeRBi%dT;%IH{jnzVi3?OSyn&==n6Pxs!3mCX7IX+2l*4Fhk>lA_HX8HEu z!1d2a9bH@~Ws$8%+sTNse3k)@$9?4uc47}c7VFd&Wv@%?g8EvNOmyX5e@Ut*ESM`o z+Bhj|)woB8&PDJT;*PXj*Vb6E9{szh)}=nM$T0<^Q0+9GOH-$%p<_Ku(xJx8yfc?i zlCyL~hf}wlczVL;y=TlhIr+QLiH$BXE|7;W##J_9PCg|0UutP&tIs&BNGpRRy5$y9 z6SRjhOD6cC$fS?T0nnY(sD3`99 z&ni#K`_XBw+gO#)I7bpGfm~0I_(1SJpNjc?` zp>g0?G-u5gfe{sXRM6-mWs<6`vd=Pf-AA9Lm!n~)!x!e;-JFC(m*NkfJr`-?6f_)t zj9Na1#|C*5o&tGeLn_U7Sd}#Uo~&?EIzu7_M#MPdnG|b6PH!3l5o)I@{Zs$cYb;y=K?OK|_#F>ya=J*&&5pV7W{ZAOdJd+)WU?uN}g zwi{eu@01(yzt|j(Src^a#$8kUehg)v_ND|~x?A7#l6vzrf8L!03>VxV6p>`jpKz%) zViH#^FZGQmW8ATt*4NuqtqYr{nJs(6IK!8{vh8MQzWIZ$7ntWIZuBs3;dN2~E46Dx zL`SRBpE>(M`j9Rn%_|42NvgTj0lVs93mdTM57Gy47458(b;{Q2I7|KH){OJCI|tTo zck6fi4({m!e_8F8lk>_#&So|E+NI$IciV1jR;oTcl1P)5k!j8RamU%z3iMxfMET{- zQzm6fo7%z;cF5S4v^Htjy_xCdt9rTD&2iE0@LW&nSW~m+eP&#~-6q6)nLSiea_ttU zD6%f*=%1r;Z}K|jkLPK)QyqNPLuQDq&;PvXLh4gYe~>9kBGIBbpVqB+H1jbp#@YGSt3O@y369*Xy;U^3!MIzS-)OdbMIvi4 z+vXY%X}^HW({?xBmB;OFQIa?|sM$HrQxZ>8R;FZ!yW8?|#|!g6JI|jR_@i^QGcCJD zXYfzme+jJlv^TCqA*zc}+OL9i+M}m_KCRivVa_2HM4u8s4r`MSIJEk(ia_vx!IdM5 zfFdt{cmJcaFPzV;F&w^teP0@BS&7|1CfgZiNZ7{mfA&B4U-->I_hJ6$mCmCYFdK29 z&LDSb1~wF%WRohj36n>goB!M_di5SR<5<@xe@{QO(TS_#mR__dj2GH^UGC1bqyEn; zQx0-GTwT;~2>2`d>}r@~8Hi`CFG(XnvquP>&?dXp^i97)crd445O|rLPf#AHLu%qC z?JQ9ub^?p26H~5~Kd*FO75m(%&3=;g#~E^>>!Zod7o%$i4?=bo*7Z-ygO$Dntj1C@kAr_6uY zljm%mA%G(+@`{~h#7;z?=i2nB_ae4 zgInGiCTZrqC))WaG&fab=&w{nSu1?UjRCjt2k6G6C*J31<1LU5=8_>&#zCf%K5(F| zMz)KrDC2$slR7I-0jfeP@6(~F>SQokX^t~u6ZtQ!) zOdu$aHulfc5wCr`g+J#+4V^C>^1K*Z3=rFA~0y z`|aoX>&;v9Joa|2e-LH>z7E%42L8^T1>DQXKyyK07)(a+Mc2-blQh$jlZ2e^S`f#Cj-A{Dv4IqrY=Z z<=elk<9jd7NecW$kyHO;^S9{mf%llh2T@#fBK3~(S&)$1Se|GBx>1q^zI6j9S*XWt5}Hut_J4F=8d5rM^nSqR(U zgsZZFI_JnNLKqZV%b3@59b>g;#k480ebH zCWra@;o%hHDms!hR%6{nzgana0ILNn?l%PD$|o><4u`@L(P-MfHB!U35H3LalTdC zy=$<`aUJXC4$Y_kCL_d_gZ_)otYEnIw8F(+e+S*R%RXWa&Z@J8F^#+9rYDWf$+$Bo zMzEuC@c7?5Nht+A;~P}f+&ZQB8&?b|)$?AlCH>n*;L!NPqxHu9-gHA?gdsu}9CO6Z z!Y(MK9MD>N45RSz`V@a=8;IV9Gec`Q%YxZ_f(D#H(`RxZY2*i@5Mul_*)!HltPb;^ zf8m$g?Te5c2qJ&;4w`B_BuijroKskkm)`1O{uHgeR~I<+r+5hQ-n3SD$k&epulX?l z7aCIbifm58b)p*6aBWDX9ozF>&vswRgyFb|DDumHH3N3)O~a9Yrruka9ca4eYinev zVBh;|9g74%m(QYs0eJ_1pTezv`3C%cf8S;G?I_r8?qWk>L$F6F7%_&yhPVSe6{GQS zmi8s=z})dAksXaQ^Gw$6ak;@?dxp@$Mi7UvuNdJ#Q8*Ie>>5- zp@uqlo)jQ>P7%KQTXfb03tX00g&K!GLbEWeXiVOF)e|x(auxX_dmRdcV8YpfaQ$iI_&q$v>Ii}gdMxK zBgsRum*(kkJhVsLv#8tWEpXcU_Nc!~@&bqJI3IMrFT18$<{jK~`KRC05{}=KL)&ss z(ee(LiG{X(CG|do&Su+I$s8lu^oWDoO;`Smx%T$SS&FRDq^oaUn;hJbf4;rkdHd?k zANO`%zmH#U?d?qKu;IfH8s^bUs`*ng1_euSF5_uLq z{65Xh+oV1V{)P{pMGwDS*`HLk8Lq!HC&@Ug0Vz-O)0d*7K3UzEVkQQSZI!27IsGj9 zm6~?V_5JNi_<;rJcAD4Ut~5SfJ$&GP(Pa#NyVCk}Rn17XugMO8DY0~) zMGs#QQI`DsVX)~W^|VDpUNxrON1=stiU-0Hc*YO)7+-#KK_E4lL^9iHjupkj`%L#) z6kTn%cY8eF{{8PLqE-}=*scRPRC|L|ge``zx__q%Ui|7G`O^l$&>{E_L?^7p@k z!M|GHdbRWJ{a@bge{Ao*-Q9WpexH7Bt@Y`Xq`!at=Kb#XyW3mz^qsw}-B;}n1Wr+V z+TQNlxjKBntY)F%FUe;vWx{6%AK`VwBv4C8%A9`u_y3qTd3c-^$6*FFFp8^b`$gl= z?@$7bl)Zy##dG6IVjsre5pqB1FwhtFVjXRxM`7-)@s?V*e`wFnI65GEJ!x9qw=d-* zjdt5h+wiJ;=nN;JTGaDNHlCCVV#Ii=)#YWDErMq;IprzM&CVt}V9|Vem$OhF7^2tf47G}A^HUz-rDTm=j@{U(nSI`&t zy;2JP%GA+Cf0_VQk){2#_OinSUP%Tj8hpeJY|-zJ!ttq-(_WOBnzDFY(9EF#KjGd_ z%5viW6}T1rK!jUtgt8ce_Trx)sYVfEksFWzv$BprY)~9 zYprSCYXpSnNHNdIFkdfAd=(JTPY%mh!%a6mIqY~ZqJ#(rno~{N->-AII-%S~YRCrE z_YU?LsAh^XttXA(2=;1rA>o?i;1^Wko`Ty1XPJ#69>uzN?e1J#i+=paf4Xf8ycDnz z=Z0t)fBFW@)EYIsV(UsNo-T#50$rEdh-#9nk5gNMl+_H@DHB-ws%q&w@`AgJ!zGuPCcWtQ#V=ptjUNG2e-h;g+0nMLIsSYw zf3-OzYC0Q>CI~VLbP|sYXBXkKHd=tTr6n?=dBqF1xpizlJuR!+-fz_2E+Izf4^wWh z=qJ&a=&7C8ebX=UL02REmszd+{HdKwNY8XNLVuXm#xHG8zPI;o=PS8enQoP^l}DSK zHvk!+*(9sXJTQX>cB}DAPL75@ReL~|i2;ys7QUz&hzLZJAUDURAd@)8_aSk=POz#p#?~)F0ZwMl{63?dNrJS_KpK z9eV9e?CWVh+F||zp((QOdJQuPe z!npLtiH0JGsUTG0mgu@Z%KJ%Orl+T-WVc&9XQ_}u&5gKSZbYBczdgU&e_h_v6vziz z{S+2HBCFIKvTv#xM0kEw^rW_qbxJPy+R4Q0B@zQTE_omXqJ6l-dBTTN{gvR5RSP^r z{AVJVl!g~efPs zV39T9395pcHRWa@AAc}re~CC{gKOp8XXL5h-8kDG#ZsaEa8is*p;L;}!NaeRCy-#o zM(eVhJ2fy*31!SBlrkCKEj+cT&40@Lg|r$dx>ha0mAL`FB((5TdF>Vzo3G&krAZbi z{b4MWfATEO63h(aqU?D7o@hd(a*JcV-)?lNrDra6w5SY0cY9Z*e+WDxj(KtfKkv#B zcx@c!E(_Kw{=f~~UXt_H58JA3-L4u&G)?BtD&NP&x(z<_z zvfKPL0x?0mKD=k4S<%@zACzW5EXyzyt0c!iP8#p1vU7Ddp*l3W6!=kU4n{we$>^*d z79XTlAKQ<)22*&Ke_UEKWpL_(%9UvVQ^{~VtfIe-(F8~6uS^o`HD`ls$pl2`AmlP; zXQ?S6x;23%R!EF^ZLRbDyjU^X+R=fT^3pDu(0*0?ek%|}rfJcUeON`0dYhY@LZ->@ z&h5RG8Uw0p(nm=mB#Y}5ys27-VDXdkQzs@E@HgPsu40U)fAIu%QpquQpTP{x>?bD% z`p$kmn&uy9c9VXeio;2G!tSw4xW+aEF-H!ewLimh%PQAeUHmk2$G8Q)3SkByRwBi+jO?kq){*r%q z`w}&4Q3=TEfBnwut=I1fvKB<>TSsdcrFWD50~0rN8onNIFlf9n9NP50!FdpGeU_K~ zJ)J&>57e{7Jq1ON62b0E*y2?1AAR>-^w8bXmN++bL1CP;bN(oVncQ_z8jpW7X~645 z2#U21Z8fa!Y7Ba3)}b|TQsm_|b5-dY?eV*KasC@OG*DRpy+$xL=EO zu>;tyf4b_ZS~U4ZS{8(e?;J$U-Rk#S$7z#nBo@qF4(v-{BZ?8d!|VYb zn2V13uGwRZ-&|Fa_15#M2!7lwP?^WyV6(f^KRmn>ogb29r~`;eYJfD_9#eUfaQJYB@;wH9}>a|#uC?5VUho~xb$BWUfeVz zSLAV|iD-pqz>(;ZJGAn(qt-coCd9JcRv2gnqRWClDHIS>Y;7eKEXoKG8NAq(;zAmcL%!%EVT_jDxH+EM;B1S62(x1^hp@_KCl^I+we^`;`<7?n5La zuhW24#V;9zzm7%N25eei7c_vlthItre<~E&1)g3%NFB63n&%*s*v!CrzDleDXQ1gk z(=O|n5O~qec)$w`W>lr033m5=`iWIv_@oJE4{|Xa`&i-giB2F2GR`q(a7aUhQynD{ zZE`Ec0!5j+=Hfnr6!N7_Q7R$elJ|>__-Z@yq)G&efR{Tni9HK;Sj;#~-{QGSf9Dob zB6{BkBB$xkw4E7sVt@^b{?|v*FwH?bE}!v-oARmH_B^`uhsIx?>R)~lofTvFbl0kV zwAj3vWslCG;yT8lK(TeXYbwSSCVD5UE6CGo_fs(Vi(oYaLLRBhJrc7%;rvLFPzV?2w zm0q41*Vx`O5=}74?n7|F73@i*2f4T;Q_f}#hsJp@IYMfiwF5p)aK`ltT{GMQlwqr; z=iKBT#!VSm%6ci@ID#ZwZ_e7-jw0CCMN7AC+7hRU=L35{rEe%2{+2)Ze{NxuOcjX3 zQ!b=Mvm1gpFRKlgdUDHL)T!)>mtxz!AJ9@ z2>?witP4byp0OCJcYJaJf3RXUSFord%mw zg`tP}w~B@ME<&E(Hu*lO&fm+Q;y)O3o=u|oWiqMWoZw$Ttqzh&6mQkh<79Z4e=976 z9nEloVifOuGJRaMhYwtT*3BmajxVj26e!~h_#Dmt^9BU~K za}{dh)uDzZctDr}H{Hfs_oB)xQzRR*979k7mT4E#dTN0y%eWFXBTy0ZP$XXgU9qEU zS)6Aq42x^Ie{tz-JK%a?1xr6)I7K6@Bg1j{vWmHMi zC@`Ht`tQMuT4k%PFV}^xSVscR5uXzPmmN^Hijot61Wr;wWVq_f8_gY;XtG$Armzje zKSX7n^|kGOp#?{5HjBZqRM!Qu+!Y{Y$*7aBRUkSOf2+|xZVHKBG=Y3wWu0HSPPBRK z;oPc7e1Z=sE}Z$F3ex|nApM^T(yvxQ>YxvET7*~PnLJ~8ZqUb#>p11q=}fJDt)4Ep zbaUQ*cEXXaRcd;3`sT%tYgb2mbCD}|;CtNAO!3D0OnD!c27b*sx$;$mLpl2SrYock zkJ{)Le@|V^E;v7IPRs~=h%nS~e%;@I*9}qz|h(Pl4 zM6%3d(s<+BxWBi^VPju4y4p-@HxkD#`LRem!%P5bS1Nk`df@*a#lL~6FlPnuEDhIK zf5d^q)1g%cd_A^NDkYv)yQN9-`(M_3*D0d^CRM~&$zk6zm2QL^VEL_5(B5Z+RB4N-wJdVI7$PB-tc6n%2uM09}zQo#L>e+frG^9 zhj*oXBzlwNgJPI|7Gee!BtJIwr7^kfe=T=#4&9k{Qt1S6D7BgJT_0l`0yV zBzFTq0_cwr7zj?Et!S8@o*`F25z0hu3xlMlP4IL)o7p3#wE9B2VEGy^Op?(nSN5f= zUUYeu_RnB;_REx|Y4JX!h|^GJFZ*XH5}|~?bTM_nEw~TOv7ep?dK*Z>H;R0@f1g5n z()HF>mszzWx7#}M@`BEqJ1Z__N~xPxUR<%NweFO1PaXw0MPj$ z$@`REW4jRzgcIGC8$~E}I1)w^f1y4N4P$B|F7+Dh(q#aU*A6}5&in<}wImw1X&h}Q zqoj{>rZf=u7Jo#CK_ zUWX4*qBAh%+TnwLyDxmB)8!@`GCvGp$dhdH865%%)HKQ?jYhvA7Zeb}e};VI{zsd^ zO*129#kgAE8jwZxtBbkHYRB}qc;2|~9Jl#Z?1g+2`bU&(w;Mij3b`HOA8jz^bes+z z_M(S_(*4t6+uR^aH1Xv-JY>sWRQ>9r;a-u1Tmu0?N189G+i@yDt3~wpI>S)AFRR1+ zTl^KT(<$B3+%UoRK=0!BhR-$`)OF{#hKzGV`?GsioL z#t^rn20QW0TtS$<@HK;f(jlqxti4xk$l>jJYQwbt!Qqy9%1?XAe{p|6pVBvfxtSct z{ed|NzvMS=9y1=kK8jK&G}4oa(dSB zIO+mE!YBSSIr1Nj?hW4b)=z!>Ro?Z+B-2e?}w@gae_Q2VdG14FfT* zL_@QEMB$0@{_2ST`0xJ_g%0lH*01dboa^^b`1js|o9ky3f$_o+4%|=|(cuI6&I7$m zIWiDlq)Z&bzBrc0h_qB}G~4~OG-h_JqUwPuR(LKOUgT+!WHxO@mHL-OnK7T5t{k1Y z-Mn9vh|xofe^KIlY>s6~DkX3ZmGLJV8)@S+zJsA*I+x0i|JVQ4$Z8}MwBjHN*lH)% zzYZTA*mGO@{O{b%ymU`_-1z#7*Pya;5$m2S696UIt~%u&qf10)#=6If%Z!MI>Gl%=tqZ zaQUWLo2wCE8VWmFHuV(P>$s59;8+h}gqckf#uG=o^c-z&iUvCk1D=1IPsEVY_wn6YPG;E&1y{;M zBqq@Xq9KRFIz@E8j=4&-PST$cqr25c_n`kbR#UMj+Fyy)R7At6Pz~|o)6aMJg!#BB ze}3kTz(0vS{l)9mwAE_7K8mN;XPwSbnt}9P>r)YltqrdM{MJ;_f6M5)VSShTWWVAl zycVricW6YoxCfyw2tdow(0_B58n3@)XIv7H$_?yYU6MOu0i&pG@Iu93ZX8Z zkS|Y+)3-U2?Zf1Bd1LMbbdsLZBr@E9Ey5!V#xcE0ZdFsw zKy%a($RUsWzFlJVC(C3Y_T+G*C&gPi&)WQ@;@`hbGY^9z{qLT;Wdt9T?PyZM(JJ*Z zQ3e^e2i0s%3%kUHw?qWb(CT^17Do9|6_b-RkGIpjzvZv_7jG)v zoOJRcL&_ocY6k!ZNOYzMBvgsgq+ zURAqwnFEle&~xcN&EI9i9MQzs5wyP~K_yF9Q?)IoM3$kZ>?c+~fB)hRXoM=nvIP#` zdd~LRe1LnSH=B?tk9Q%!t=po}*0ISlDMC|GdsQU1{9CwTR?nf(4xtShlaZ@S_`zDs zxyKz*LVCz4IuzRoHnCTe)TQ(4lPb{Af5{nG*e)HDVe`b64fHpJSy1pnGzYX+R# z`Wn{qlnUxz1}pH19k+Dq(tq;?wISBBd@{XGW-v(1BPKVxxL5z0quA5X$b(*_OFOXd zcy@S&Fsu*<=7okWJKeXK+c}>E02syWa!Z3RirMA12fYXrfAYD+5-UP-#mVe)9)5$| zKP=LFiXgEq>r!22uGJoDd%Z$y2hV z!zeDrrwv-0V<6|UDgR+Te3DO+;#Hykb&4#wUkC>DTiTazT`h}D9h^v3-?}UOzwHe-0(3b9zz?ue{GGu7cz*EgPe)=vf6$dDO%d_1 zH&dBesRJ@Ww8j#$D8>(cmV_7oe4WUWi3!PU@LF;EfAP?@uQaeGo3v{r#=z!i)O#Ia z7qAgDDB?0I5}015R5nP{aJyvwlAjusG6zW#566!PI;)_o87e3~kz)7TC&#aB^NsZ? zaa;mgPy%v#ljm3#(W-M?KFLQTC#miFx}}T0m0BhF*w)uWDR0SvDBr75Oj(~)8nmtM z+DX>mf2A4JNtw3SZ1|R4pjRFtsz+c)zA3zTxSy1ow-+OiCD7=!`{Uu91ij@7n#%{v zk!B@xjrQuJkSVXp;mq?rlHPPR|8Ilx^4qo`JN}rq#dax$CzM zc4ujD`Mjd7wgXyv!d){}$@T485VYu0nRsY!e{Or8qEd2uN=L&>wH@74E3kna=#wNa z5^*(&5qXcOP{W)EJOqcD3Ns--b|Wr~gl(si-#(c8IM$4CyB0b z@GE$`{Ij@-i>t;%ro3I%A%E~i9mQj9g)UiBKA(###ui0p{?Nvvwf19b&ClGODA$a6bvT_K3jSy2o3T_n0RGtAj zRAWn)N(9yLi9RfuEk8>mx}AC=q3Yz*Ml^|7sFvvtc~pi;m`i3Z~O2e>rF6 zAnqlipC<)orq5T(hV&+axAc<)(WPltAUIPcs6YlX>-rG=q?bb8neQ0@eL#Z0+dn>x zhEOwPN7W1}d7AE45+UvB;Q=6L1i3P)#(^A$l)8t>d-{Et=Wj0K-W!>gjq+cr7?1}W zVy8_>+3vSRA35Rkfw)c!1cZZWko8ig=zmmBN%SI}auS(jG9r3#Rl$R{6;bZAw}sf@ zf7#0}Z@9-Cd@l204yc>N%Se_-`6O~l+CoG=5i(>Qq6UduG-C_7uny#O($dL85t>V^ zCF(UW}vPH_IEia|Djq(iU8Y;-=$eUXMgt^ z?*V*`EzZ47lVQK04FIlknSvurgn;M8y-l!;8H5gJuzrOqHR$eKeA4uoa z7i!M^E;3`V_hOmC{h<4P&}q&X?Oe*M2>(nj9~c z?C`QMI&1*9xK)prTtk_5`aH|?H-C@g-kW3MU@o2S4Yy(j=X$)J#l`disy}G=Rx%lR zt|RxncEs`44^&rh=Lcj0#Q)bm9cwtcq7lO{18B=`=BA2TsPdp%D$w+{lO`J~dm_8G zdFkvh)2L%|awim?da3nC;zG~Zg;0De5ku7TdZ4ceeJ{}4JMG}>JMD`1?|+Bizh8Qv zJBt-_yLi0y1HP8GjmK~KjU9Spr{aydZaY`K)p|-re5Y)tlC@j2r&aZ8fltR!I=ijA za*NI6x*~{U3Z{g5y$43=z#UIN-lx;K-JyAPRu+;%=;ZkOQ{s|{}~E!-c?d6Rv= zYO;6y$v${bNM%)Dk<|FQqxEv8D!`EJ-iybS9z$8jS7mk5J@Fgddc3Yy;XLj&OgHbu zzn#2z>Xm3V~q8#u2iF$zf7n8Hv!3Rq<4sG!iu|xy@Ye((q$$CV#5~8V|`qSx81k zrk>_i#4}RGD#m$MFefl@KAGrG&pr$smh?|_R6TM}{)Wa$B97`f zCG-PW#ZenQ{z??dtviIEln?wD%R z^s~LAJ_ZYtfwWbW?0+)2OHJNKN=T@MG_s;ytg=b)0%bGtj{;zQPqCv7qc6bKgd#I8 zItYy8ij4+_>Z?DjAk%m8IE|zg|Dq$d+uQe|_QR;XH8rz22#!#Q3D|7y1O`+Xe6M)bhseUSOUt$)`P68|WPk>EtKXWJ${ zUyq0sJMmJ3Ql7q(SC6SSUuEFH(kjO-a{hfezlRKivMtoNiGY$x4b^11gFHS|NW+?% zi5p+?m=U$DFWyzqgLlo^_a3pd`P|-yqQ} ze1%8J^g8d0=zrBD71WVP{&M`{y54v^#z`IH^J`;K3+wDE;WhxPS7^F8YyXkRdwUCEAttVsymX z3GB1IL>|*L&(>t15xoQbz9ZIvQ96#N*UmHi&=G5^jT5RU-;!!S40369^^^`)KDlXb z*3Ys-Q`JT+I^t_Jjq|47Wej?G=g+=;%auO$Jeir4j_8h9dj? zLaVf;J{x>udb(qeDW@y^krqbP^=gyS}jsq$;;Ul;@5OVH91tJ%u+SEz@$(`G)D{dlezy^ z;>=#qYR5wjAI}HX4*x1_xgBq{zJAc3u?9ijQs_0b0NB6@tbF|hCuzpnNkK6bQ)rBe z%VZ#ZrZ!T=CPKtXLd?Twp8QvT)%wk#js_c(hW^kznBCyh6jj!;#J&9R=r9Y);X zE}^7kgi)r7l_A>=N+iI=B)9OUWN`=R{2t1+TTRB*xSVtK8dF> z3UNYoj|Su)&?&IL5(BbTlEDv!SAUW*Y75~G(Hk=zkmUn*!P%H#unc;+ppYP{A(M|% zx(@%&V-)2~8Qi(;&$YXZONVb+dvetjeSp|7o!v6`F0ocB`(cL`)(1S==)C$EaWC$% zI%4su*$LPpv_YhD`s(FjD421BXNC3*33Z{l32q<2O>`Ne+lEA1w`ut@4S$DURcQ#J zV7Kkh6%?tQazVqU6dc^#F;XI1att-;jORtuRR+$v(P&STw>I%`NZK7K^GL}B+11%a zr)om0n2y^GZeCDgef*(29)wuEI-#cMGFd(lliWsb7+_y=e4G@`c9-3bZfK(PnmIwE zw+jW-;eMAn>gwfLfm~*iCx2095sl^U7rDfFB76B2NmrNw{p`lbK8 z*`nVbZlXA>{U3+ZEk=mvlzwY3N=PneWsmNC5+SQcTlalRl925}&~nE=W=L-!Q*v!! z<#ssg^C5>+{v!QaE`J*J3-)WFAl`}zyZ1|WY{}T?Pl=BGXJG8@0%Mntg{_Qy{ma~N z*IyyHRl4&gGZ@K-`8x#cNdrEm@*XE-jJ-^*8FUJbUqrh;CwoMpCn8hb#eEPsCorB7m=>~CZKZ7h*l z_@1@LmN*=^!Z7QEoq6eu3o-%0Z^7+oVd+*`j2$~vsrSZwgq74-`6^RV2!bQ(3`%Rt zp0p;6J?U^j$fbCQg}D)LFuCfCky&R$jAKrmK4RTMsnFA06jaY%&WxVgRt2I52s<-G zgYS`(pplvKLWlQ-7UJ4Ia!?f%fJvmfkv~04fWR z;$_w->a9H3(fyn)JlMQ)%Wl{c;F=((*GV_C?2v3vB{LAZqPWN@#-sanoeal?$cM1~ zY6vSWTAIz04RMJ;Vw60*L07t&oCxX#Rq|v7T^*p_b(~!#Rhy4YOz*5)Q0e&KNJG;p zbT@gQ7JpdV0cDq@iGgjkJZBKWi)jSB3?NFgX+B7&Px8@au5EMygTujStbKrrKbJau zl8=n7wVxvZQ6`1|#z4 zAY5~7e96Ejl--Mjfc;*(ne)k2oKcZZzWy(7jDPe*9ysbI%T2{~Ixf}kbn10#VaD<+ zVW}w+l!GuWe`X|i3Jsc)k@%5LCnG?W27iObT7)W0j{KT&k1&6hU->Zx9BxvDHD(Ns z1^b{X1AG@y?c+xrg;rg>`8Xe@Js^x^)IKr0a9@g+e!wXYa0$IuYeGe7mZ>o=*U&7g z*V^x=@nx|Gb-O9^4T{s#XB1E849%&^oZ|YKs=O@asaf-}UmPIC(JV0|;7$E$UVou- z+&dO!Lln7+d&fy0#z0(+2%%D7J_TypM{0B;%TsxyAqRLCzfG^Wc9WGy!MWs663H%r zJr59e_x$^`U+nU8l(e388gXp3<0Qx?%-1Q)Dkofl2i8cdroVN4BQZXC$gl zaxz6Y7puL0`ZEd9cUG8b{P{YbMt|u5NDdm*F{ja%anNdB-=Pi}c}6tV#qd;WFricf zv@=K%VfYbEbRpnzhD32A8cFM_wGl|op^&ZxO9))(DpuPD)HX^Kv6$lR|;!L9(K$-nFdSU z$@+u>c34|WoFvvhv0zin-&EGe&DL!JQZHq$h9wbF3L@prGR*KcsHJoX5az}tn*Shv zP$Id{;nCYV^idUyCn%1-=9~r)Vq)b(KMAq=6lr8`3enj5+kgH)kAK=tmjbx{;lRZL zEzbEV9mX7N%~OQc&NA`0|NL(;wkcOY80JfP8hcS%E74scQ{3pv3WpA^g7~Ik;-|VR z4P$_dxI#x|KMKKZ$E19 z_6NJ|-FvYL4l)Q6N)ocu)_?Poc>(NDtDU?4pR>Ev?Ak^mq|GUdDb|4`>AqT>kf&DW zFq5$kCV!dCTqYD;h0XDAQ>6W}IO)rSlha$@w4Q{ui9mGgs()3klFPWb)(L%lsf=`j z>2;D$>`_VNm30Mlv-l_S+KDI{adhZ+2dARj#SBN$Y%-h|yy}M9{cQhv*bm39?}rEK z$F=T6?JXJCD%TgmdfJb6F$wJ63(jGsmP=(7P#2PnW|dw%Uz(ccP*;F`(!x|roH}9( zS(Nh`?os{ihJPi~*a<8x38)wMp~BNfks7TL4{1?2uv0~BhTUPMFDJ9?5>q0DThW-2 zh|cTOm(J$tO*82K;J^|t+4ITVWi`p(c8>O+?|*l2bnyK2{JWPgULBtwKAppA8uZ=E zgC{SJjt-tb-9J5i@%;SshvS3u!>1=AD#pWfD%LjEs(+9C`uYi(ydW99wiZh76*LzDiGzqYbG#&roVq&MvLjKX-kEU}ZBXYt>HU3W1yi zVa8H~C4cjX{)Z;lzA~jZgEsPP!Vv2DK948Y>99XZxSJX{U=5l)V_;o|4Sjm{6=W2Bps%u$lf9@BeJ=pZgO#edgGuhe-lUOSQcO*t|!T$1KU&bzBMAV5Wn**zAVi1VSHI^4&%$Hy&WMNMK7j< zOn+Yp7+gmxv4Z;kSf!JeshZR$N*Z2-uA%m4ZQmNkJ>p_jbatY6s4z1nGCJAy)hq^V zAb|=PrgJZXhj2DwInXEc9nO75<~;(CYgwg=+-@}D1l(zM6{rZZ^*P5xLq* zLkc!!0(Tc7UOgs@^sJcXBV;r#as@Z^X`2A~5T)`A)ve@mlnosfbSe=#bBGo8+w(|E z&*oy3C6q5nc+sdX#pl{=Y3g>(K?x8YMR*p!-=V+Ywpn6M&dU`q`s-6 z{XEYifN@}<4YD;DQ&yq^5k{I#qgzodZU z98)ddsQMy{_gz*eQL=|AP*O9Dg&GXWev9oKy*tZ$g3fD@NDXlp((;+_o8{WE z*1RHT#!_tr5m0sQ)u5bi)pRu^szNlXOrW$>;}zMUsz+W|v}EaFSJq?+w}1bXB(i8f z%SZ9>W*?{L77epp7sX74&fvTjAJ2ww_MiRb_Kg8g6Ayn19>Eg@_a(%l z9-+VZg2!=*_R7ObfF>>J7{PYTtMiD<=z!~+t299d#d&MO@dNVpxeR5P7e$Of@Hu3! zl&~u4Q^Q*K)Gpmw%QSMSCd9hN%#y4z|xZpt`U01CxEth15w`7fhud@{OaU zj6cS9#A|qAEugSuLvD%J>}~i$Mm^(+4_daRH-2Gv%|EyoSUcCXR~?fi-RZy7B(+*C z(-Sw_C;J3t?gixutnvW5{=cuBZC-`+T53Dq&bwt{k8H=e?E-3OAAeA@7JcL)k8XXE zK7$3>XKf4Ylcm|^(ljkb`mcAoS?lD7=P!;=4o{??X(4Ar4eKH|@4^4xKRSMPz$8EA zfb2i}3!Gx56L{xqa?Ly$^@qvyF=H_r@}e$IuJhRt&M`RRnr8$fk4KWvyw>2b#t{O# zDKGGue1>4)?CNZ_)PI!?G-ti?`s{2qd{p;-`y9;-=1=i3?Z?yPB?8eJTN{tsdMeUv zdbUdQzDFE~PU`9be9Ze4EOD$irPxEhqI@i48Uxod-E2EsMCOL#{o+~(L}WK90K{SkTUqk*6|D1V=|s(ez0S`!Ypw0FDN z>gY;m3J*JMfk7y5RNreW(~r|;XnF&JiK(%g<^4ntBOM6-rKKFX`Vsy!>BoDNe7yQi zO{~`<+#^NLxzL%lCcN|fcZWK8cTart^I?B)wMR+Gzao$*{<2`AAK|FCTS<`K>t{V6 zvD&lWkpKKh%YR_r8IkAN$&zj*(&5bIMe7NW1x;tg8b!0!YGHl9%_j*KE9*bWhqxhb zViNjRrxaR`p?r&{d+o0@FH7jJZz(8pul*4(Pw}d=y+lL^NZRt%Ip6hc*H;9PDcD71 zofmO}>}%8E%@Y|fDky1V^n3=Xi>a?wMc7n5Ib*8R1e2LDX(SE~){qh@Hie@KSIoFZr3gE2|? zXvprFNublfw}xR@r8DDn4Ks)LDOLX@>9tO-^U2f#5Fbx+q=g7}@ViOusatBMoYP_c zKp`NKP=8Q9foH9C*l%G&G23fz=pPT^C4MnzbXV%|ZrzopWunHnhkdcflSG?R!ktP0 zz_sS` z|Au(Pn2|GSQtW;6^K?4g155b$kqYW%Zh(+^pGCb_=U7N#7{;Lih@wU5nzmhxo z&oU^vyTVUIW3|*^v$@CycR0DnyDu_2wnWA{{6LSJZd*^yk9dW9W`9gSG^@G%r^(=K zC4Xa6b+K7tfm>Ysz6Ckkgz>x0SuxqXOtZ}-dn?B8fUymT<4jk`*4Qr3U?zlasi>bg zlj3?QR;~5);N;26!(#v*nW7!2$2L9Aq2f02IPE24F-=AYsiW8h*4#W;FW3HM!U~*< zoEp?IU0Ya@HVy+Wc`SRuQCV)t2$Ouv;(sY&Uv*U}(aVRx!qKmkC|IutYCYL?3D(pO1Lb$brB)Td5Sn4Y;pCBe67j3@aOJ(HP6!6@J6DSzh?+Ko7S zf*9xQ+J6_P(~$9^inWW#JABalS7?WQLs=!V8;CsJl?~Bd8KmUDbRRTDR5}8pyTUh$ z`zrUP=1QRX(|JGMdaTPZ7c!9Ph-&X3FE{*B5wry>P%b)eOH7Zk3z=zxTT#425bit0 zy%c*^Q5$9=oY_*rY;kWoBY)1p-|0)_Gw+Y3#%UcaXE&%mhYlL|`uU5~11VHQD*myk z3TqXO{hy?8AHl&f5u;f##T>c`x^zjHMk(+k@HtgWq;fLjNeW@YGO=1BMp?kn3`gE@ zoG8aS>ii|_ktA?fhMk~PqRx&kfbzKwicsVR$PcN_Y0A=e%po+5wSOO9x1&dKG&uYD z;m1h-``!Zo-rD}Sx>hn-dKp! zahThTJJ*ViduiX2h|WZ{XYSEuNm0=3*(x30TYf9=JocB!d;j}n2toH-X+sh?4_i{6gz)X~}9 z6HGxGpKa!~s>L8_^C~AnkB*L_eqVh5eP=Z46v(JZANHV^UfKa2fAsAKYIu0`-6Tm= zMM9|+2klyVOlPnqMbGo+$vgPk>TE?83AG&M*X5vJ^Squ(ja)A{C3YijYzio=;7nUDMhv+{FF;Ef97?8h#p5_2 z${Hi@Z@u|WNs;ple==Ij=FiDO^+Hd89dEX9%*n5N zRJJk0z?l411j+kO1hdPmW=egqC&^h38vfx^u@-D>jZ_tye?(|{_`_6YapuO`xAu;- z`c*fVRja*KVQB_i?ykHlbXI7nTw$GG6^u3XU$@V6ar=mQEEr$K0K6|NMqzi00t!&n zA-ElnhY2c2@x*khx&SGwu?mZD`zx`UifD*MF3%Dk-n~1|9{+kZJu6ScYAWY}tefR$ zhyA8ifz?@JfAgIWg*y=2)l6hRZO+tF&pCJp{7RaEFbCr=3 z$Uht8@$7U?CpX9Oq(~a(!wvCzk_^r~N=*S|n>D(s7Ne^~wE5-Iql%RZ9?S49^GI5I z&RYh5=N)EjVA9{~?M8KlM64!UrNwNMLR&NUEwe$Te+Xdh2jr)OuESDl{S~DckhG^G z?=8xPJ2}_kGi23^4()mC;62L!VI1;O*ZZ+_y-_-@$tW^1Yo*+l6Ss9Gep`5}lh(bL z!m@VhrI7W@xl4%&l6dQElS&C7AULU+vG;>D83h*&2{IgyTewxFR~ybmSscUp*=80V zJ*yWCf2;K8Bm5aF@)JG#)D_<*5dC|eW&)CQRqOTwvB9Pz%BvRq*tHw2I<^6qwLQ&A zx_AdDDr$P!Ryo2p8eRMMqH(kNT=!Nkal@rfxPzND5wY0nKluU0su-Y=WPMYbNhvl* zNP@wE*!bC!)a>1HGL5-sSh?w*))M@& zg)|9w5cV=W&&lkB_biK$?lRIkt(B}pYl2DyS_?xuSk*LHRwoYG=d=yMQQCd;M+!5s ze>8mShNX_@P8486(iK#8ORe$~M;6_yQBb0wEbLiq0{dH)A}EQ2<@SAnFgU0a4C=a+ z#@SN+NDdKu^Uy7U_SFE)1hOB)K91z*NL^=$xA#2O>TJ4tYe9EK)lB>T`_ZTt4B9L z5=i&S(an>5G>Wr+3oof%CaF?EwmtE0d73c|i?%n8)+PM5F5frxCsZ#{XicV!4<3DP z#BM&!!aOH2k<~g^$E7g$sGd4x!X#>Ux3XFJUJW^$^y|yyisbFJA797OPy5kdf7;Qb z*7?8Ojn3|VWBn4H-R*W;@`tmZw>LhnuK9=~ZUvYl?@lknkN8zg@QB1pt1p$-03`~S z9G|0j+L06j%8fI<)OgvqFux;yC+c0X+@ng7q;ka%JU6oR_RnX|$CCt!p&ehJl>w5L z+dLyPt8XeyJUMKyw2bCmd-UArf4$IfLtKNLP_{rKOW%QM;BK)+BmXD{Gy;ba2d|-$ z)2S?RmN!Ibk9Zu@=gXDSfYsX`T%HhLkP~QDB$GO2jOEDSBnFlnxKwpznV(PatGCdS z-v?C~{AZc>wW;4cJ#|^I%Z^HKX@kDBhwYWOVbv+EMJW11Z0+~^jWzyce{DlLS;EVq zs&QI#XFxTgLHV2y2h9o*`J;rHg=uT~+rk}G&~X=3Wui3SSu=5b!alf`<8-T(dEi|S zdBg#NEHPqoqLgi%*5vGo=Lw=w?RKm!{f)O0wlTq>qCYXDVU7XIh)#1+t~3YM zVjV*UgZDMfuBgO0YiGoBf0KTKQoRA2Pt|Fc^L$mkJGY_|zu`m&1GljLG!BEv?QXq)wF>>r>MY=2Mxs1pAJ< zjkWW0j7zf1&sv6`h@DX{l}~ ze2!~&p{%t;rjlaeg{;tet4=Dt7Ceo9&*)8kG`ybBL(3L9rx%{3)|L!Q6Hwz%2~Vlr zX?YEqh-AY}knfSwL7U>4BEHPu!h=)ESsc)^W6E{zFIMGrxgj}{8ryAPzPt+&=?*7x zkGTp`V4?~7{S-fke`zG|)2Y~^&H^X~$k8I*HFM-|=#pve3m~VhOah+>ny#cY4==qi zVw%uJ3)XF^fK4w))U^(|412e2vbkl8u4-D+&uPN0w&d5(h`2e*z8qQq`=rTavYE51-0h zn=rSDY3_gO1PU_y;1yzd@BTkbxKwKBTS2RfSheZVjO}5M)6RI8+3*lk4|;yk}RI2 z`EsyYaM&PIX0MONwJOAE)y2S)b3Q9#6#hftg}tK{6_xUV10Pg;O{o2~LTqic+if6h zskSKBqh1QRD{}z^+$Dv=)y~7q?zuqGc^>Q~2~~T!f0rht_VsPQ_cpmpMqxeq%!Z%Y zI8aAx+uPd{ID*yQ(7nCA>exDm7W=C@rAYU3#C%PNu1k^Ttt0dVF8t+D-Y03=GLs=Z za!r*YYsh*r%{8rPh&4XVYvSXaAmTgoug?O?7|lAREv1_4R2IJ9%>qWHRcYDuvLkq5 z+G{#Le}VLjTGfG6CRb+`lp~f3&B|9QBI4EPDoat52Tu!eDoKKOZk^Uuv6IsEId_B1 z=_4Bdp4gMm{vgCWB-OX0V@l|q?{)AcIYPZ{H!a%&7 zLH!ZpWqDK$P!Ow)*Q0oPeb(uGJIwP*gPYhCf0}+%+!b5Rs;mSC*(-Mi%d+r0D*lVD z5T~dtCqAgaLZoci`wy{ZlGEtG2QP_({>B6{x2Tev*xM6p2fRV?)_9VWE!wS@vcaVZ z9Knf!j2LDar%JooKbXa zT5|xN?I!KE>Wyu#S*rhGyPSA^wMY@@fntyf!sesq)XbN4OAjT-Ie8?JC`%X|e@8=e ze*M99xws;La;MhbsOnSNKyBL&N}2t1kGZz418ph|-Q9PU-oDBMG-uO==bXF9f=*}d zCS&2XGN{898Ux<2ut#vY$XDv2d%u1@KRkC{27XGtRjB+P6-j^=^=SNthq$CO;qPND z|AE(Vv9+tN1g(k0f9u1F`rzgZ z{kfBqdt7WqrnY$G-hq;~RXqb4wu3Zf>TQrSvqZl}=5-#~A7^Rr4cyU_skoY@{p751 z=dbuJqTeF=O|{LnX`C^gHSWk7G)^$S)6D#S&+DZr+iVw5ykoF@CP%kwuZr23Z>rb8 zyyH=`E!QDJ*2FtBobgAre_h2OiKnv(?YP8y7O7{d`D4rBN4aZg@angSf734~6T(`; zqGT7bz&GYmWIxj7)bOM)s2IRm<4!Dpi0B7JpU>lyXNT?@Qtq~>H%tSIFA=vYuLv9p zQ93wl+%XU{%Cs&YsL!~%j=x`YP3W`69Zsm@Z<b+w-6`ag$bBNIC%x+o26TA$s8dt*3(!{731Unp_dHi!gfz1T)x0;H5xyPd zE&?d+3lWvlY{4a?a#;k@VED-_imGfDk+`ThDQML)a!SuJ$fR@GTVWHn4h?9Q4uZeD zI`5TCR8w|t1SZNHf4A1Z7kP$;PG}EU=Trg4?R-TTI@G~PR^yvN`J@}38y zp_lA-OZ7#XF6Rtl#|*-aeBxD2uMljiL#?X%QgQ&;P258hR@QZ*{6jtiHiB}udDVAc zyaQ^0DhDIye_+7ZrzEwqRD}mmu5+a4qGH)(C$u;ZZA*t$u#2^$j%d}b->BeO%$(QP zA0uDOAfKRUb3n?mS=)w}8Nb*N(}apII(QqV`-kL4U-awi#1jtZ=H9|vTH>)$*tk30 zWQDM1L^6QX4YaVn!z;=O=7boK2N_RE$B24)Kj~A_e+Wu*Mj@RF3`!iGH={)YGK9*M zWYwLDY&V$3l1MK(9zP}2VbT}Z$#5KIwgHK&VTt_Sr4d-hXV`i2im^U)R?>GuMeovn zg1tM;XEjSGz2>OGYbBzS&g~kXdldHU4%f2oL>2R9B zmn=EIf4O$ACUM_(qphz~vwBaBQ1QFGJNZ^$U)PucHt!ekkl4Z`7$-bxp2~&52PzSPn8H$@B*q6^Q&Y%hFCn~zW>x_E4>kJ87vJxSZCD%K3!;#km!0y2 zKlRv$p|ETah4_0tdY`i7)!VNc{JF?ZB-UE#2~b^+nh>U|t*MUen2|TK0 z`rtOH10sU}$0Bu%&2hfE3VTH|fhDsoIe=$S~X%~E1qeQcP@H&52h~8{MiDqb2GHo6y#4;lQ zp#=*O`?EtNde zl6un}!m6*$MJj+bSf13{hjB2_!PM?ferz{7?MwKk>uA2!8lif5#46#(^r6 zqGmkOpJ>H;scY1=`V-BnFpR7+LLwMkh%ai{#}+XLF0Vy=Xpx1(d(An7w{JsudjY~b zHsOc&9xO!n;k^gVZdL=^#v88wZW(*56%v<8mJCvb3R+)3LH+g1beK;09_ApEA|Mg% z;{LzuHLor%>#i4lSo4kRe+3uuFtyu&EJ}27IpgcJC~$+bS0A2|UT-$x%U|E>yxE{; z8B_e9(js-}%97;pw@d=JK5D6|OwwBX5aa6@$z#Y%An)xS6MP}XszPMR6yhBvR7{F# z!I_%aTkt*|%|>EO=4#*|w45a+THyjq)PW1(NGwCSb_rAxk-Fn2^|Ly#qTf^{i;#ALHCgMSLSjUODX2)Ur{A`^++F#m7P(*< z;9g9eNwAd;s$LeJ2U`TH%_GDv=h~@=o`vQha*|zDja|Q`)#Bjm)x*ag2?K}l^l<{v zxCwmU&{^TwORS+Xe>{a#s!xVmkkX6@Q2>-2AHX{v@}7OVL=4lV|t4t}LW8#1AbIq*Gm zQ}Yk5(`CUVEJ3{w>1&Azl=7*NGLrccyH53bJjwer_O7mUf3wwc?#HG5F5PT3lohhd z^@85Bwh>G~5vW7%hrWe%m(QpT*6Vrm)g#WT=*JB!O(a-PpfneybzKX!vZiLVHkfJA z*ds4ss3H`}HAwn_Nvi&Y7hTbu6S4Fq!Z(ry!Z*r0*Dfnp7o9;V{Yp_3d*X$j^*2r;;m^mej+S)-WIn1B-pB+BkM@Bnw{QdsPK~+AOqZm%6_?BB=sdjG8 z;XyuGCYJXz?{+X$fO!`}Qj}jbQm~AoJ~m~$-2~oMapE=ARZ6?piX3;N#sei)bTyUW zQee@ae;yn^d-223!SmAv7add-?vZ5ZE6Hi-}N9v;soW1t*9h(G-CnQYX<4)~w}a$D~sgP5*e=X>(SMSwkZySHIb z_^OUYU9cPdWWEL`J|KOVxbQjJg)wj$+aD!#f3@brYrq#+KKqb^qR5-%=3PGNFFYyI zY38jCNrzvizxA%Wg?bGnyoF0ZU>iX8!M)BI`cY$9*@m_EoYOQ}U~o=LS_fw&a;67(q6dJ}_Aw|Oo$;l*KUGf_Sop(q~vK&b9~KBUCO zCUDHeA2D>FqmT}=0^1K)CgmNhk3_mo!r*fb1am=D+!<=*wM z)8xDBw0F(uAv$U!NF}|vpe&-h7@98mV`&KGeSl7Tak3f}bs?)l^l~szv1Si$f9;}l zEz2-kC!+N}V`>7Sf`ay@1l4?7jv3rg<=Cnh(T)4N=w=USv-o!<-|fN84>?kA_ldYp zudb23w`?qvs3P`@)LpyX>>)bAoJG1Ssc8zW3ed$S>BX}`-O%!z;w$O5^I&arSi1y! z1)b$SEUTM6vd~B5W~82;2HVx>f284!97Q2fMm#lE%XQ&gTkXmaQp%3X>tunDCJCZo zrj>v=Duc$KGThDdTo$sE+O9os-E50k2#PFf3EZld&c_W zD?lzqKN-e1g)XLQYu>;QQw@-Awnd!u0MN9ODO83TJL?$WDNYg)QzwEqe~=Cg9}dNA z%oV&;V|fOL!WOYuSq?=ZH7s5ZL6e073GXx_<`lWtJdANY*wevxQZzQ}vY0A$w^2Z% z^o&dCzaox6UUcxyvGIeKaQF@rk0TW@l4uk*IZP-F)#cjKio)ySguD^;KTqPZyO;Wn0)i-OG2M3M`)uPNXFZ1OhpZM zkx+WTE=u@I-nRO*RYiK<55-)|;(VInS7lk2)-H-d)JNJ}M)GR$e;8H?5sR^1s&Gkb zkW1%?_PG_^DHhmDAI!j^#G()40{^sETY+xWIn~pvB8>U)eV0sW0uW@ZV9Di-7JBvj z)j`Q2Ss!&JzsH+3hK+BjShtjbv1h@2Xg#>`4RIM4X^$@~Bn&RD^LMPgEY_s8n{7$E zB9#eap8RThFkR@1e|j|KtS_oSa=D+}oEc$=x0&6w!t5R|Kw*>sX`dFTaTWny-Y*~T=r~#Ie4KN#5|{=Fbd*ehHaAB^=_79D7M`8c zPZJ{L)YZz8su@>)rfDQOX?8hGd$JP{qYJnmrKEXrIoaeFe>%wg;pqI4PA(GhjC8hI z?bh}M&lu;`;v%=I{1SQ$ji3OiQl%Y%jbTHwMwtSH1vGif$?_0R-VrsVeu{#7(szaZ zoJeW^$P`-Wp|o&!MO@Ap>~@(5PUFM)eHv;yV5dlFG0fg`^QcG$H!lOqQ>lRjlpl20 z)=F@tzRlCVe^IB{sGvm-FWt@K9Ce+frlZQTxKS%!DhIh&+*tI_o8v8j^0;lbx4ERO zyl-{qL}&RgmDY?AN~9i^eM+1eAD?$Kc^YJ&Xy=Nx<&Vai*kkhw*LPd9=}{fm0z>FH zn+Zl6!FN>AQN|hhy?q17INGXS3B3wYHsHjPA-RmU|R;S307*ay^}ni_YdI|JE{UYl~8r!51K( z6`R}bt%p&2H)?M=+sA;fj@_=@>8_~i3#uc3N+!5uxNYpRcB^f@Wd#kc=XL#z1vzuce{EQjd@mo$u;mS3d1f$k=q~h&S-E~f zH6PlnTb@IN$V$hFnIcsKQlXPtOz6;$z4lEG9G>jPV2i;dABp&FoDM1Sv$p;iZzxk$ zm`s29!0KB|2`C&uZI72fUh`@0k4$_IO$CKW$dShMP>Ii%>5!7$aJ*md#%&A^hf)Ez ze{=+UWGYvdy8z`bp@4@p?{|=hZhAeu*${u6#gl0=!9NiYnZfxn^cs;bm(~@k>Qj>L ztadn!4w-qA%c%r6^5a2Jqtv zdQ4=zPpT2p(Tz1Kpw#r8`RGpkNm7w+-1FqQtF0Bn#e-i#O zi;GQyx1`VCDekBQKvbq9 zi-u=Ks;^+DL<12yN4h3|5p!y>D;>LKu|Q{VtIzwzbuK`LIoVJVShT~p&egQ!NO7aI zMWingb3+)M6n9hQX85aqK~Blse`F0`Xps=dsL?^rTB&Y?cIZ-d{-g%m*#D_nuA+D8 z+ptsyPthoOq644Tnum=@7%)<4Fo_~cS2N#&s%JRi`bMRw1Z+c9!0+{wQGb|BA9I*% zLzO8!xkmj+nFs*I?&cNxLlvJvJS)u>-$zc;ov#OpMho^?7$@%ukP$I>t2 z=T+Xnw`}4hnKss>h=%g#`n=)~CD4_p%^dJOVLrdz>}g5xmfuS;ZtmAk$wf8(=lS&c zY&d)|IT($nH;q7%Nr#Qxf2xZX6%x`22DCG33+u0tj>?ZcaZu|2$ z;z@C0PdwQD{H?g+oY)hOzQ9ldf*oVCZn-^O>Ft(8G|p$w2vp0Gk~KoUHZfDCIok`#*sJ zChx6;C4jc0j)H!*RJV!YrgEE>EQ|IV;QD&Xf+1!BS|9!4p`-S_&h_xDG4j4P_ai$) z+=xH5Wd3~kaV9(~_Q%LZmQQs3Jr(C+&({KV2i1Q70==s&e?8a|PvEQrQNRx1Jv1&^ z4Y5@?N12D7#nP5%<@I_PoD{!vtE}`S{gc@x7?BTW|1(T`Y9f9XtLH653IKl^B5&^q zcV}761gnCnNphBfhJW}}tOXleGYC%#QbS%FjmvlD#@nm*F0}epH zL}N7ts`@Ljnu=(MMJ~@09^SoMF-y9(!Ioe*gqv~>(%`<OVG*)sc5-t^Ws(8zgGLF#WK#Q>o|UcYxtoO3B_Y>MDJHbc}zJJ;M~(mtmZFV+4X z@lu9y1gz&li+{M1qVj%xV@Xi*XM9Y`A*o+@r?ubj(=SD1OHRZpwe@14UNlnJ4=}D9 zA}#tm;`gkd`G@Ffe1n>}_HMB$w@&jDx||!9RJYcwnI5TER^0G<@|ynKRrv+vaQTNl z@fsgPk3Q>kM#Rl=F~8gtiRysWPfpk$Vx0yC70)P!@33%TR1P< zKJ2HiVWRYrHXno@+V+6bL!<0_k3yFbasU5jOOuab7;u%MtI8IZlziL?2PUF~Kz zLQdP@{pDRg_LS2Bw|}rMAm?ZM?(yhJ*B0YdtOcuhotLd6?2s)P9z+%n^{VPz2kHt=CU=N_lnFZYHvZsz_i?7 zGF+#HkrmBhAwjwUj_C)sNHcXIqGxF_-B+JBn}4C3uFgy@(jr@fH=6=z5+e=DUqlKJ zWtv@es)}n_7oj^&ZnmejRexL|jn*B2J@3zR@(CDljX+F=Db3hHH^;XSaC zrGFk&R!z$7`^rgaKu8W%0*Ff6f|6B`e-t5>mPMi*r5iFa_v?L3nCS!<;KO{Ge zHU4O=df&1}sJb`2(T-x>b$Jbh?yYiCU4M1BppBJ==jAvN4e~Alz|9tq)A(wGwC1t_ zM9ziWe^=xMDQh#HVTHvli;9X|ID}NyU2%h_H^W;Cb{k)-n#NbgPIDSxiO8Z{)nY_v zd!d5fw6fF)YfkuQ>sSYLhktFI##e>>^CqZ7IWt%H_3Jfz?bfRGs*h#;#ou60;C}<8 zRh=Z$Nt*aRZuFxzXH%6@RWgaF(Una~V~E#%eSqZosnvfKF{S?6Bv|?N$VOMwfT@j| z*9|*glwT~L%hC}dh-K}WoL>|^qzH!_5^H)M)(}y}2zcT~9gi>7tW;ng+)t}_S7-=} zk#X&3{o|UTqams<2c%#{_KT=DnbXUdOyu`$p5W1@R!? zwpAYPmlW0AUMUUO>67{~GJRfMs-FsC*Rd3Ynm$_DpKNrXWuuT-1nM%q0-AJ=`-|z> zY*BT;Y{8xoWyrQ25?U9=NVLRv`P5yI(g44cxT{j(o;jPzRdw98t95L3SASq7I6CV0 zzyE$TDkz(o{?esNHzi9mks%r!gp{!)PC12t0NzCKN)1j16k9D7z4$bpKoXo4n}5h^$3VxWP%FFZ3<$D@b?Ea-kyjrY4`Qk;OB{D_MMmMZ zA797OPy5kd+R>xd`M=za&hCC={Suws?RH!8hqIrzH$JYe`MIFD6=Z{QGh5DQ;3cy$(RdX8-L`WRS1e^)I1|$ z+;%#K@FHSTc*Bnp2FOJ#YO=?T?M(;)6)+ljY$)JS2$Keh|D7!gQ3c^6T8G6eSII#J+R{hfe0^ z@`r$3)lnUTO0xtj(tnn)A!G`Ws01AgO=;n-g4eHz)a|VAZVv|O8`wN%?_VjEdZRVc z9>R)XoZ z>2PEM^^}z+yV04;YoltH(GQiWkBdd+cm^qL0snxSmpA2t) zSFx0VJ!8B^b6S!W&nnRm3wcJIN$?nbxE~9DHdkNmZ7?(n@8qUX)Hb^ z{h*#g-TKH$xsH*4CCTh03skrSQ8hAu0)+yp5|#+&bbo?A=Ps)DF<4bJRnSg>6_!co zYrJO_7LDLptk{Gyp$|F0iiMY_!nF}PnDk1}hUQ4{6fdeygx3Rl7_c7(TK^bUHcA7o z3|)3?pAK7Q6*wVYOF>dZXaO^))lHAj_uhypQZPv(+ywo8il4(YlK1Hppoov%4B_8M z=&?w5Lw~mt@0*f;^7Dpo58v>aDn2cSyN1lXK<@dW+{F@=N-E;H7o6wUoGlX9 zT9vX;jQD<$$(x2rj8N}IB3&H@TCO|LUD<#3ms>=K2I62tL9O*1F<3M6*BH$gjdhj! z*+L<&pL=|Ak2&i^LfWguFBBUsw#}&C4+Ni9g_gyrceR4^8#o0+~7tXQ|0c2 z+Mur>iRI!S_r6GY?B16Sj@|pULu2_o85Vs_-aZHnWMZz?f5mH>6XixqqgO zd18%)wl(pww#Rh3=P40%+=)>@)*|3d!c}DC+Pj{DRq63Ft}eRsJ-FkVu9hW17$ul; zBPK(Ewh!nKRFqGt3?Qx!9CqgPlfl}RbtEl=8%FnCS)g-k4|2wovZ6EhNJ=+P-O_SZ z`?)o3xI&GarGMEvHO`=@c0_qp4Sy;TzuI^`il^6SozAzzJfAeUiA}3|jJPYdn##c$ z4qBI6jZHdxpTF#6eeI-0Doh$w8HQI5!(OVePpRym|ASxpr^ynxSplAR8Ll+Wp?iuPX}Ls+o zxPYfnHU%C4YavHwPf%Ir>Y9vNqkICvAy|1yW02?7VhR+pERD$*49I{O2*xglhRfNg zsqV{M`FCC?CgExXy#NuM4|=?Tu~VchwmBfDs zHF!z<_hdoLr1kC`+$8?{c46!!jbjP?B+bpj7)t8Pk~m81JCgXVXleBy>ky?!4pQfi zc!9hms9P+(S~%o^=(Mjyj=S<5Jek8}D$3~}sV+!-wJCKu)5fjC=1Myoy1RaNL+P*0 zIuw#t;O3I$H$m1)8h;Tc8pdkS&ARbFrPwvM)&Ki{1SjEe8|53j3dT_>h)`!V zpSF5ZmP|^wL;!O3yPC0=(g{dhTgRP^#VP1%(ESg6D{U0!E`L%Xah%l5GEZ8+oBB%K}LE zIQO?uHGL!~z<;%`af}_6;ImC_7i?>bAz_gOq|1mF9zp65W!o~hi7ftgVrCPs~Zo#m#u9^IuBhwyza){$h1HsXik1o|jmx6)fU> zXeHr}bpG*D>2{qls+%p4bh@Gt3K?Eyl`T(Q_>$SXYkKoS+SX;oWGyzyQ+4~nmardp zG#a9Wb$|JkRt(_cPGvgzPoXb;V!GTO4x$wSh7#}kZ}CAP8T#UbE_#uJmA`%};l>%`B z97LON*&TrD#64)l;CC|I=1SliIH1=!zqLQAzb%E zk#V(3O=uSjS6kHMU-aa-il!#Y_$c`SvnJ<@N*0K3yerN@cUkw`Ez!uOi?7Ds1~Mhs zF{8WeJHju1*>o7~?a*n9+*Ojj5Dd-l`j_g$t?#qX+6Vi#lVCNc(z0k|xsqWvJlNhB zTOD~xYW(1@e^-{u+}jsj2`OF;690nNrhh~u*Z|3z>l51?33L8=hyL>p{pTGz=MDvO zO?g#akk4sMC1q7sxU!<|rz&G@726{pmJJ+Eq(u=b;w>}KF=4kVV>f$6_2C1V#7Y^; z{?*Zx)Be|By7=mwpPlgm60zHEcUL}&=!K3oK1wE6MumAXp(q>P3R`Gid97EqTPy2kn;!)izuRuW_CyS&`GO=xgFpr^oFD>wTm8ypm zg8n+;qV3rHYLk8trvQLhS4;3Ru`UvP&qw%!*k=?z4z}Fw@?=_%9_-3TeB!JpkJLxj z8S?(vYV$iZ{Db!~jJw*(abTjgTz^YrX?ID}i?+sevyw5!l~pWJfm56IXKeB>LI0K# z7LGNckjyYhvwU3mrD|8W{BNCzqbxfE2n;HR!LQV>k|97mg~ci#)0|o6Nw%gA^LLUz z1Q!m6x1YQX*UVJ)dRiUuUSsIK5WU zpSIZ&NMNp$ZsihU#C}CwMY#_qJWvXk`9NOlIfWO$F%>@Kt=6cB9Bfi)$&%T-45lrc zyeWBa68EhU=_o~&;569rbbkbl=-UL!!lkkFwgf_;DQrqkuOz2Jkw64%?tVOxy?ksUttS*_rOY$F=@AXc?H<*P>T+!6I$@T5bTP=AHcO=4R)53giHGk|Sk>X9U8`u=` zGX4Tx@Uv5KA0F(6CK$K=7wCeQ^oo1%C@>3_K(SOezJ2lX;K}~U>A}-Q*ChZ7Q75+I z$PQE9(WTJo934T2gJIKnPJJ{kN0Rfni;3MSH-A}-Snc|*$PbKWw_r!$8_}aKYP!Nu zALWlw)@mKO-)y(HccQJWsJ(@_$YoKC+71-2tBHox}8 zMo#~uFiFw^LkTprR3jxWigZwKDE4*OFTI!cKd&%vvTnBiy~wlMiuJW*ECF9GcXwsA z=v^nHxVzF3-G7zq>2zFlHaGdVmQk5oF~t$}@{xR2Y;L!=9!BlmsJ-PVY6j7D>~`f2 zR8QHc?8u*z2@n(9_ExKn|Fhn*5|OSr8&qY!3b4^Gx2tCmi8MKbkT zimFCI`D=4i%;}O8pR4;}E~`0|w%gnHqxN>x-l`_1?ti!Wq#n#8<=rQ>6d~1CjLu`= zwPYZeR!q0cGHa1+}YsV7bk;zG7h2)Xt36Mwh&pn;#DeaD%ch_ymo;FU)60ujeW zdX*)8>hCO@PG+Rf(P$*eo6%)HOnc%kY7-`tv(p&(h&EO5NmP#a}1W4M6EOpeb%37GaBE(Hj33jV8Jzv zO60aCTqI>^cRz_Hb}#IgTT_H88?VPJY=2EyFsnX)R2qEjGoyP=D@-?OmUYWk)}F zKh85COJ%NOO!SYK@%8oQBGd5W!|)_n8jfr>r_bgB6HugCW1MboBMza|bFbqyJ@4g3W1I$vfK0SFooP(nx%Y|P z8Rl0FBsD>ZqDSeD*!IYX#xTDkLodBvO*CsHKZYhMOjI$fVSZIZR5QfJZn>vh+wIme zJLg`-ym_6gCKF#4jp$x*jCaJn?SGmLsBapJTQ0Eu-v3C9X#G6`_{jsTucJHS{rbB7 zv~~}_$DzS4d`}TIh3>Wg(C+jx>PVui%1ysOkH;x>bF4pwG=4|yw6^YT?LOMRzq_;h z@X>=uJKH-C@7>?Ne{W~!;m-DhN4xFqhY#;`L8w`_I}X@3LR$F8Jj zE%Cj&{I}TZ*rL!h&xd@!WkexH<}!8|Qt!JNNjcUR>4@%U^^0`g;oB=&PNuL{P+Reb z!_m3a+xP6bK^0i^K(O#rMq%r13+hM1Zeyl727v!v3qJbz z7w#8+`*f0Cs$3V_x_T4j6{T&MLtBj ze%3eTw81AZjb%8_#W=;A|L=c_hGbl=R*PFnr~|WMGFdBBLG#9T>%rE;?T7lMJm>is zq?wGGLKBB!XM%}sL%jk|t^k`iYMSqH9LGL$i$kX#So}{p^ z7Bw^*JL0a8_v9V1<%zoXiTF0bGBFRPps;{~_B01_Rnx)Y_xy}K9Q-$X}#SW-ae%Ill_bAYf@}g6= zO4+$5LtrEm`hVTY1)HjZO7;!E3nJgASJy({h(yGW2ka+3f)eXDI$xDiv)KltmfvPbbYc02dY2Vs zdp93i(gndaaOp#UFkBw-hq~%J=8v;FNU;cp=59tttuEP)*tls#2{v5;q+@W3^vZ!+ znMz{}u4hPPR zW2G~RWN%~>qb*6ZnNIH>$g-0`EJ1Hd#_1;mPh4TD@F820OGjYTVh=H`MY3T|W=A0h zcAFyl8Xt93k4=Ucz1tAW5?(RhZqkHEHa#-z;D77=$rZr3YO3u%N)ulNQS*%%M%Ahe z1Y|Swg*CvZiW?2%o{9(v@NWK=>D&F4eViod7N8u;4$8(SQ)Niam|+n6{kJfE_e;9R z6UrX&eo4))A%*LE%_ix14K@+*-?)8mq0h5IFYbzxx_d`#m8?YbRqp#uv1v?_4Mpyb z*ner)sk*%svKhi~vz%vmk=vlPn{2hA&bD@vM@sy7u%nu2IkE?g%>=1o8!wre*VkWY zGr41-?yRrlo_qG}s89%aX;@|hr#zg@G)ewDftUeUoOJeV!0{Y42?COfHzzEV0 z8>4|7m?3~(Ow!^FHKAl2v_TMI>(r=eQ-4O?;SF_4>qwBJI6&(vxtzo$wFz^zb#}pA(#b ziTD;uQGOXur^6(gCIv+^KweDxSBdCBAF;(47$4GJlA#b5QbeSMV=q8zyNSjZ#y|Dq z@d&1QPG(4KbAA1UJo)I!Ywk)v@6BMgru8~&DBpKK?-eaFi?{O0)h2F%V!D}T{p5Y? zdO8|@YHAP5^W+@A+qkZ32-K8=;eW&5%@liubIY9CCuU-;yN4ZJWe=C*-qD9$R#Jj0 zqWly3UfAenjyH$*P_aSF50~a7xlXbI;oi;`Ga5fFDESuTrNSesav#*b<6E=qUp98= z+V`prhGx>cnKW}1H-$8T(WX<@FFH8q+FCMB2RBOiC^p1%`xAgZuu{Bh&wu&IDLOK@ zzD16IfS%otC;jv3B+d$UYLUB%A1f8_+*R?;2=?_D;kTO<7VkA`%IHL_6h$W ze#8hQkRfrbqJ{>s05cPmFP^rNb%Zz;qpI)Hm~42K#X&aw&-T2(oqy)jfn#9;nbu&E zB-?2_Y9Ca189R5Tqu}3fr=06IDlk%EPc`8(G6jJvgX6|4dMo ziIvuL%@mrIElbn7nj2ue$5Wv*y#eQ8cSU|VkTnTA;%8|4jilK+KZk5{e*Uo|ex@Nc zKk{|POn(%oS)=JN>whOf0bYk}SeK`LpwfXDCRwAnDO&O5>TOf}tJtxKJjIUrM@*xY?;qo-|;eEy1v|HzErNir1Ad8?G3>` zOfA{il(1+>C`;8Y)P~dNWlyL@eZ3`tVfwhigJeldD~RM#Z-3+DbyuRo{ng4weVz2) z(6%yG(!mgMeLOn#8>9;UjSR*cBAx(UB@#Mt7@yvB)`m+5>b=+KqA?TG^&gG9D`zCZ zrnn%)zq*^(JLK+VVdmfT5G$c)iAW+M%YIv)V9Q<`q6j*J?utx)*@1V6Os}Rbj$d2* z*=z0N+J=;xlz)@xXZ_7bI#AqPg@;e^YJH)qe^|_F&u3eX6OdU-IuMHCAXR;L<@_8R z=KQ?7BFD=N=kw`g(y(;Su)5o+W%V?c(9D!`mX#_gkyT+4W!AeE^5~4Q zwm!Wc)5U|_IOYqSGRi=!EHaj)K$@48FJgz2sT!3Dz< zadvC}IjDm&#LRB6^rGc4RyTxg@0Sry{GSo_?cZ!oj4s`avBJ&SJOIZlJnHVyd%D)wx^-2V$~;ho(j zCwsReT!(sin$>Ft#Mantd-e*WzXv+bSTd%wOtahfwCJ;?V?Pv2@zR4v@y# ziv8jB^A~1w4?5a^@8AZ<@e~e_@TAL+PVtcq2RN1=xvf$b@N`7SH@mVig35sBAmdSh z!hh6DV}!oUJci;MIva5+#G3xno@bhf>F|MznF4&D>mtivaMd-uLIv#8A> zCtYmqn#1mYYPbMFJlrm<6@(hy!D+ghBuUX!O-ox%M?PO4r<+?3)uA~vqd!E#rb!YH zePHJX5>l`Axwfm6I7Py}+LWdt0u=aHmw$XGsXZKKLaJCGMq9qAtdUq8(d>D$&rt8x z?*AzrTlmgmBiz5{ZBNA?JK|^6s5uSZOZy#jV6@=+Yv?t8oW^bRntB?RUPF$EulKfE zTic&F0)_ZJ@1<;)KIZ_LWi+#eX;>p5<>vf+Fax^o{9GwFai-kDgglVHA}tktfPYR5 z(@XXCag5yNtS99|nO?h4Po-krPkUrufBE9Yso0}$8t3N-yE#8^Qbo7n+oaKilLzxo zHj}3>o}8RNJ$#7*L-=eHaGShWs6?ViRR1B($mDhuPu}$NcbOQb*_)yxUJv8TWO&w? zP2kIXcKG}c=PwV$p5XZ2aXL&I2!G(~zHYq!vD-a6yW8w`&$`_Pdq{uZ+1z~nW0QX6 zn_Fpl@^qb3GmTOI9JA4(0l5Z2$>1pGW3Z1L_ZCy^kz*9(r+eb{85o$#d(of)Z3rF^ z-jfR{_Jr(43$+%{Q8%%XWW5|Y`1iUiv*{p$M#dO|Vz0ZBUS(7(s%iMjNPo_ykTca9 zpsX2c+{#vL24Z@Gw((_)l8qHO%K9aYq7{!(44`3mUW-9=;nQmsO7y5tI|Or45Fpy} z4|su_vSOY3kL+U@j@m=5$<;8wY;;%FTcf_i#_(S{0CPe{{_YClG}26ru@_OjAVWH= z{qGK*pPtaS<^_(TS45;_qJMAR*<^S=icx>jIs*+XCpjB1d(qcsdFd=nFiA95nhdQD zLJ9SBIINtOpx>G#5DwlZ=hM7_!_sWU#rZfd()ae7Z~;lZcqCi9+u1kb$w9oHO@?QB zF|A(eZZfl>Z7BBiw9}cjQ0y!8g9KNg)K{cAnS7?WS0uR?X1vsbWPcN_(VKocX-J+y zx)!d#w3wdfZYCte`MtW0tkEZE#m~_Mw*)K}7mBg3n5EvWoQ`M*3 zv5o@ti~l8Fn$dO)?`J|srIP`L3d?+oogY=)NHR_J_8m> z{0zIb+}iN$EH{}SKu3HK&u{|72L!#)`TS7*K@=h7srCOY37tZQ`7}x{CwtahLodYjR4iGpLTK}G>8F4;1G)>b7MK2yFVw{dC ziYVCc^MqbPT{HT-HAzU*#(XpNZnxVtYZBTXAH=`@Jev$Zel0$TpB<_n@r&v4M`y)C z`=rdH-k}H+-+#u^p3B3fubUg<|6}jnx7tXu^wIx+PZ47?g+wdG)n%J5sv84#F=cF; zOV!jMPmz*RkmFRQDl-MfhTrOUIK9?+pz|jEBxmhQTr*MqyAu)BY>`}Pf0fx?g@#=p2vwIw;CX16Su2;7!@NN6?xe+-fHW|n!#0CqW~l0j zB6bI8#q){-)-bhU;k*_i%O2*6c}S)s22m|V8KogEP$-jqd+Xw_jd>ZC6?pzpAzLjm zzsx^@=O6h4F$dP5yv4=;5+N&~ViTB_gMZFpGl2GzVLK8=-5d+*auLfhVT5hSVF5|I z9|5LSuehM&c6;YPH~02m@6faDPG_oo=EE>enH*hfG8FYk?Rdk6l6$?(gw?M0-J0cM z9TzZP#kjj1#Qpge{I&wWHASGu8JwB0Qx3;nC`}EEr-Mp}P3%Z0BgbKqKw?m5-haG3 z+F^aAQY`Dp;h@CO;&Lm@urr`!hA4a-S%e3!a!SdWf2$Xb3iIk^$#@8mjz_r0cl#}8 zGunT{8f+UmFys)0DpfKB8-)M7maLCMyY0{>z#+_X_c;1r)b=mR6fzg zTY3X=`Bac?6c**U2*QsTp=tcBV?}wF`V}-Pd30rK4bJK=D6_z>+S-5U;fJ>5(HXJp zDOD5~kQ7P5@8}8#l>m9SQEKavY+#U6vQkl1#_1pri!vXhQfPP5$KS$apMPu(`$<&3 z06$ZD)@Z(yFsyvQJW5K>S^ljF`9;j}tJEGfQ4@>G4_TghKaE z-o2Z1<-&&eYojR>@$S+lV_(UAUa9!qoFQg5e6qI*zRr!$`~zivxAS^`=RmwXezOHe z?BSQG$7_urK(2puFf*rzYf6Oz&)B|Dy0s*JwDn$K00(P8|OuhP6m5NrFMd@a~G|T82)uk zsYm9s=tVdDunkh27Ds9zWxr_f*MNQ(eJGo4`iB3r+ixQ24fy_pw||)1CW4(0qcH97 zQ#SCGqdc07QR-P5>^G;AQxX=X7PHc0PNPw?0FFyKJ*iPb7ZhIPkwYHJtux`7CZS$p zvv}Nhj*59C%BvBDG3(+G<=)c`nVP%_Cg2PBXKTJGEjV@xRjcP5Bd^K;PjcrG>yFC^ zzE}yukDKzF&Ca7{+kY`55lMxzBJ}x+5Lvh?XV5&8;aS5+)hD@UX4x$aR3DDYD~0?w z;0Iy=yGW8n{MKXS!Ag7`7UkA?m^bWUXxhmiG$c}hPb|e6v!WtHsw9AE$kgd1zi*E#ST&eYnw<_G>CLNJ_DMt9EgI zLUqwuBFn7nBmn2-&2)9+I#|RgiWqs)KB0$xF?jM=UWS-=DXaN^6fe}_q3%jrrM1R@mEXRTTLuoG=_uVltPP)`} zxo*fG#33{zp!STT^U75-*+ovbW9I(jKl*owEK0>xq z>2u>8Vt@BKk3KEk*nCf)mTwki@x@=lQ5*oU6+{58EUl~r%LG*|f`OQmCoH1J%8&D; zCA=L|J9u=c3E#Q!{n_gt^fzIk6DoPRTMdf+c7q51X zL~xwP*jwASR4)S`2F5I0%K)yIc{U9GqsY=`n}0#FP>6q-6VKk}?i)dpTkQPj&ekyr z@Go=hA=1Fe3c)n|KoIOHuRc2I9L8X7;^N-dcb~uuRc51kebE5{ePuS%@CZmrm|jsu zopkO8B4Bh1f#YYHT*2_i={SM{AJ>vL!kX^^)=iX~FbqU4h8dr5q&+7OlNJ@yn_#UV zDu1$*&h?6m@9+&y#D(pkd`pgNsp45ujwREhWI2>7{v-|(+D&6{qQ@U~@8G13a!2=~ z@HFrm{9*x~%Ox`|`~i_Z!Z@^3HLsY9lDC^AgyFr47se_TkdKh`sKGdggmUb6Ns*j} zWaMU2TB6xl-AY8V4C3;CV?thEM{7Op3|-p7RD@- zUO~Q33`Rr!?-6Qq@EP6;qMwKRlxKMINBhU>mvI)Vx7l81`3}60Dt|0CUqX&G~0CsPj$AOTRc6}ET}LbK^+*aQRg{w z{Wa4jO4e>Ib89&(SC@B@0FOl2J8#VC)o+iQb;^58Ji=-|Q05Nf0?j6JytoG*el1h( zXv47`r?9+}sEi0k(Z8)_De<8Gyv%R34ZE``f-DzP-!M&6`=|{+J=U)JQ-8%sBxjy2 zGh`OBo1aI$Ebr4G+54E6hAu!3ImEN=A8z4I5-rSke|4IqJb3bF!xlu!gC}Z#9^K$dUfr36_|t~^L%F!vSYcfcb_ti^`V~-FmzlabB4};+CU}#Pk$=i~yO$7?0jv2+ zT;^FBNqbiCMMpO}i#a4jw@n?sjqQyxWcx|f#Yw7)Lq8mdENK{h*&K3f>u4|{)uzYu=w&arEg3$d7Y zwzAPx9-p0;qS0##MSmYDwz7PbQSdZeoJxGSJ_TOk4Dan8iG)5z_m(gA4dZlxkS+vk zoW%JLdjcD)r-@^$&{^~g`!iwc0Ki&NTpoUZY}s6VKT1Vm20vk(Rqe7o0`1D#A->3? z+l19QeIV$7+3Qt-bW}w(Rzo@rf#F%<*()cY>G}%0*|^m4S$}-EGn;i$v_%pRW8j&| za%l7*9L5PCH0c?xzR`J%H1RF>-NhOWuKis&o zff*)A7ip~FDu30gD#^0<}oqw~$HD z<2S_X%68yPCB~%`J!!=WktEs#iWQ;*H{z*uHK4V zd@|pv%0Lk)v1f`RC5f7oLsg{`fD9!0nUs{Q0jEfoTXf4^*&^U|A=aFb+r2A%cTxs5dCRt;eUZh-j`sjUbVzw{4ru ztmEGgB<7@gkN^I{fub{*8#Q5~uvKJi=zqPM;F=6I73#hHS!(?P5wdq`kI!s?dooB< z$}ZC+3;Q0s0q&PPLA0h-f~8BK^ImUQlvy60MWa0Hx4TK!ZTGS~YG1}_Kf5g2X#}|E z5T4PCiuhwhIJKxw128}q<6?j(aC#MF&|Q0M8534y%ny5lcQ(1Ps~vQ#6Pi(WA%EVr zJ#Ul|;V~IJsc1&4&=7eyR}to_vO6|ut7;6C85mw|A@%v*gj~2B5dhf z`LIwjVdj84OQ-q|9n=KS^4#KL2ZO6-a^x|PON5I=_W)+ltIx4?gnyCa`-mU* zwv5jzSD%imf;$;yBv-3)BgR1474OGj3z3$yFDV*Udn%#tD(HPPA0AREA~>cQ^j##I zkEL0e#P7lUT_}D@7CMi_P1Ahf+HQ$c7`*Pe#rzR+G7m?P9Y6PT)4b?#al{*{+upDY z`2$gnmk9A?9fUcA5NOnt$A8h7MZEv;t`;db`ry{LThNqi-*Q!%6`NJa&|q1Hx_g2D z^bq8xvSJxG*zFE%=!h;Fer_ua@ir?0gGa1d&P!%&lTI=aY09R-_FD!E#VX0dbPR<| z8lqRsXv9RYQR9hq9Lkbe`&d=+MdkeBe3L?^&3dnlPh;n!&XbAvKP#PTm?X~UBMggIUWbq&a4V~ez;|{lqi`#E~ zUDF?Y<4@f))5GZ3onu356xg963vhqJ=ZbT(KiqX&~&D(GYQ`4zG$b8n(AILS7r;UE*FF((_Izz2V)v_4PEml$c#} z45!t3wCIG5FWoG%A3HA=C-{jxA?3@#((+eKaNU=|okv%rXv5i3U&+0)@oD*ngV0^i zk<C3pA#QmaLdh$o2t%xiGLS^z=2`416?Mcza6;8r?kUv z$<+0wbM&BnP&)<#+ND&-*0hgnp0~ze`t!53(rU!X(mP%W_bJk9r!KOxxco7WmBn9? zf9=hFzcDRRQT|Ml`LLb*{r8t;m`~N84WVb;|2ip@njhHN-f^pzb+` zmqq_a&4vGB8R(xkzx+N4+LK~#W)LV=$}7Tc$ih^brD%XCl~D`)0*?lqBPg!~PpHX-L_6SP=Xu;owN-Ps&a^cQpSAvrBdaDrGMSG(*upFt3-8ulFZVfQ(k$cyr({+ zjjn{@6hWq&+`01tP=4VF`H3nfNWs|w=L&v8edDq2lyK9plV7E&Ui<9n|I@SnaqXcv z@IWn1%7C)d(k(4khdWTs@<%YnaWD2^F;bBg1c0f@{~Yd70|WU-#sau|?!PC?zmnfi zMSo68^8aE9?ABg}yfO^JhjPimWv^>%Qru!6-7_Wr^JTl=E+O^qiSU&i$=@W~-6OM9 zl$IyPy%OeqJFF52yU{iqD#}rm!!j{K+@0J2u7z;#oI1?wSYN(C(SlA;^9w-!E;JQ- zW!uW3^yCUC&#u$J4Xng*d!@X0h|Py!#{o3*o{|I9JS=y9;KbRZQ(A zv(*yNzL)`4d$CNo8+`JwiNjPD7<>q~9+pq? zRcKHX&5BXQDpFDpZ=({EWjLQ)XMgc6a{hf1)tXdQ*2KVpioxU-G)q=T- z5jY0Z{#KS`x%er98@!5-vSz(l>F~<3F}zCEt3=yBZ(t(n8xcDh9)5IG%zAYPL7YJ) znYjs{`vPLHIO{K3NU)}5poBJ3rACr{bA7d>v^lUw6zZ3kIncQeSZowaBF-^ z-gi>eH%@d`ys)pG=FOR^>!WLm@I ze0;t}$^GWZ6>do959Cv^U~xnW{GjBZU?*$ltflPQ5;K|{@~5V^ipbOPQ&l`u{?}m_ zH0HqDu=Hm!7bDat^@hPm;nP3;sdlh+?@#99cP`RJqh8*+>mN71fnrG8U6p*(w9zvB zt?_J;8Fvi>%4kWU4u9_CD)Y>FI0k+{mWZ=n&dv-c<9~eyjF{;!)*`?7U-dz_RO5cl z9~M~pXG3pW+!GjEP14So1DV%<<)DphU#!X^FShm}BDQAw;l|tg05TAa?dZM7ek=}6 zji_pMg1l=hb#u7@E$}6zJ(!q-l{$Ysj}Tf5H8G zHs9E`t&Z)EZ6_VuwsUj7Q+4n6^H$BOwW{{tU3;%J$1~;7v zE?uF(etQ2|BtUy~J8+;4|3)Bm0;dbpIvj*m#VHHYP`O9{7AIp!IaNO_>L-l5+*ji( zCupI2Dv(m3$>&oo?MbqFzX>ra?4}=Z7dWK&QJUcu`x5E$%%F_=io$`DC52S(L?{$4d_Ro-|Ya6{WIb1@RtX_d#a&QQ1-g zp~FmT>&>R7WfYywcqF&8E}6S?%J1y|ydBO2=l(18CziW1L6>Ppm^4h^R4B(EV>IJw zOPMqim#M=ydl_efvjEoUC{WZDe{AqFqm>volG`F)LjJ0nhf?2e5zoU^V zj8AV5yWNiwLo61)*qa!c*LI4(XU^9A99)}uaw4<-Ereug-kGfiJts0mtMsQG)@*L- z^+fedr#Tw4TOyTVftj@TAd&<>u*H*(V>OtcDazL~U=go0BM9V3RIxC@T8IPiEkcLK znCNDOl2^s4jo4mzN+G>7_nJ{fI*xVnP6{ zK6b>_RaKjd4CY#%Q@s9N%_Kh9@@7Z;r+@xc*lNIv=rkTM7}7 z26Pv)In32p3se(Y53}YoZBu8Z=s;PxG{%{{Z-AV|yiaJTkc1aU#M`nxl-HaDUENS^gH581H7iKwib-$y{v_sVX04VXJOQ82{B|rneDmfMlp%<8I zt92fFANGa(JvLo;p({bub&a^9oqxC(HJ1G)Ki~ zU4ZrQs7l_Nfxa{Cd>6xh!CH);4%TNcl7Z_%|McXl5`gEdY1|mtGl|7K(FmT+%83e^@LSY`w!a+*fEyIZfs(G$Wqa z4JhBV+I1e+T1?}5YN_Yo0rK;tyJoaL7yt$T4Rl6JnWI-jvud{HBptk(KgTYCq@PY& z#Gx}RNz##!K`sFQ1cGZ4t8Cjo`^uAinV(CeY*k~1&ymyS89kTI3fb`oDd&hLs>G5` zu){^kJB;~PasO)HY-FT-f_;SvSXfKzPxn$(%|-%LLm7Q!Q0elmVeS;mH)&!-ybilX%UarWdrxBjG@5kXk0xhm^1kyjb=| zDtlJr1lG+nhex7z6h}xD134LX^k7Yes3#ek75g#90KEjkz?ISwu`RB|kDGtP_ufkP z@htw$9yr>d0kHK&Oy+ZA?Ns(Iy-OqeL9eVf(Y?pQ4qw93SWQZo zI-WUQMtt6SUaskaTJ<7@Bv09#j}B34mIq#Xk~bnrs7`fg*}{WwOwHIUOrZ#5s5h=%m{yx| z^zDpm&_k`f)r@hwW~ZqGn%wF);10(h9{NuV&7f$K#IP*@2~q)U0!kFFcW}0evn5nb z3(Gmw#b%$lcbrp6?+hM11aL`WsE$y&e12xb-I$vGY9UottQl9T59Z=c8zBID)zX>` zd18y{m8HsU{Mfbi37_BgClr$G>Zb%iP+HgEd9SRFp<RF_ccY^B1Nw z_Hd{*Uat1VH~PTjcx-;451bnx=;UpwP(XAt)^+{6mK!jqmJ47A<~ah`eA!8>ygLVU zO=N|upwln^AH~_a3vB)YK%9PwZq@DqP+W0x0`J70Jg8ah16fFj@#n_~Z%8o}fYfx6 zW))S{)S7ZyMdKqH+ALb)?mXI(o)r7a6`34Hbh;i6^)VTJ#r8^$7wX69kRB}o7N>L^ zqDXM?cnt>Gl#8E4sNbOed#Z!=e@6FUnlFI0KK@&A2=sFO3fE_y1Cep}FYWqOD0*;MJShH;6Oy+JzQkD_`YlKjqmor(9;}5K?ns3fsR3j02h~dM!j6p+0h{` z_}TA-cw@RS3J=NWEfaDDGdp>JZ^$9SC(>)E(mvt1(JrV@sVWz>^I-M0r_VO7CIaQspYzAjzVc*j38oXpG0!BA(d-G;YF4e zyk)(@1p%1kFU;pZd>Ey;GNP8uq45lWXG%-#m2_ntX1CzF;3tXZHy6tV#+m|I(QhIl0B5=C-vHE$TetsT89 z2^&4>QtYGQ1EO*3{Nwx<|3tf3S-WYx#5H@*kB;6tT3K0(Y+@W?iM}Zqtepby2w-Jsu|9EVL0ea*jQJRIfC`V91=Do1DW4>JRCH1 z(12}Np$3dm0dqVuAeNmgL9_wTEE+{4Ys)Y))H3N}+W@--Ns92&oNi+BT#V}d8_?>9 zW)WwNuS!7~DR866d!slxE)l?w(PI+FAozJY^=#gT9eBtKp@Ct&&{tx&k#=jk#EyqS zBEArLPafDvb{^;(JLZH{dStUG0HqrGYWr&<5xTFi2c$Aog8Velr%?xBvd4l#J;}yd zKF^9m=j6tZgO=JrG|?FT(8uq7CbQ;qs2x~Zvv9@_WLYA^I^JZ z%lq6r{8zfdi|wk)#~dOrrF((KANtt~|3yY~aH3gQ9W>bB{!H@S1(;?z* zLZs-SI~C`1GoVKRjPz}o=nS}5lRYealQQ#Q4IqWWec&p^VbGWcX%AL#X&}4U#c*jp zyLMv~hqKWOeh`ceAl0E8s=<5cZJ^GS-+(@v5ROB5SlN^y31k7eMk1 z4kKH+y$M06W;GGqeW2mK2nDh3>6tj0*R}ApZeMPtZ#_7GlGybAKcrV875mykh-BP7 z7!k4Z`QJEj+!`15(|Pw<^T!`j7hHLHyd%71zJ6DDye^*=i(Jp<)2|mP8$q1r6qS8G zuLt-!T{7Q5+M$WCWv0%4P1jP>N!t$v&Q&wRJ(y7b4ZnvY1>3H!r47V( zvSNd}a7+#+-{@hNoq?YHV*45KQwc;e-lruZWS<1NMAU(0AW7-nRQc48h*ZMUE*WK1 z^7?+9>}invYRo(?(_ll0W$LFZjtxMQWArs)__4S19x?aD3rw#Ume&!9lVCahnO(vg z5pK>OwF?%K@BU4VP`?*0G@PE#DG`ks{GMPH#H1s2adp|l$GPU?+@uFRLo=AwDuL1t zBHT>HD7U;V+pzWCvg%0Eov(nvS*2qqK`1V{5k*X)$TgL7!hnsY1Ap0pstAzpm&i+V zy&i8&xZl!Lsc1`Bb6-Mzn$Qm=48N1ZLLB;)Gl*d#JNFkm=nO(y;0mtpnVnDWjc*3% zoap`?1r1n4Ql*3%#g$jgy@=ZAQ_HYCOH`@Y zo*y$Sp^YbJ&R)=ztkNf+*$a@*{ICMJaBGS9*g5D$!* z7LdLod8?hy_GVSy_s~Z0@^r!r!Y4>*K;i~BG|p3iV(=$o5DYENmgJ*q?AiW}%66wOwt;J9~-F_v@Ws3d$v$qhtW-nOT)We{TFo z{TL=5+!5b?wuwPij_GCxg8q#7Bs|6eS_WE>EW$~?HpM}fdaU6mf!FIOL;of8Yq>9; z53GD!*`B?Ta0{vte1?a9l!_e4C_a$(Rmq+xr#f`ToLUn<%#P5)FK*tB4GdUVbhR|T z$u&(44ayxHG&!VgC1C&#=5fky3m+dJexEgXS7_c1EHFAT$i`IN?&pBI z!ODR;9kZ$8Y(Bb8e5iOtBifoHlw^p5*qE`5tQl)-DYbU+F_w+rMpIspms&xtZwQ0F zAURl=05~+Ep58#(qsOP92#BcxegIdx{MrPdkkfDkGQTDKeHgGH5OA0SAJ!zfv&j(M zm2hjw2;y7+6CytnN4RnW6fqpYKmflP0v^UN$-#<&AxfkNk{EKF&nB|B*bkC~*$XjP zP(#Nhg=Wn)u#*{~kmG-+*Xse-fH&?1--w3x7pc9md`O|Pk;Dp#*LBZ=K(A$H@6Klf zoQWVc;8Kr62M-{%+A?%w%!mg+;Nplie5!)LiDkpYPEJQv`s9^&TC67?Nlk`JQFS{m znhFp9Fv~Vd=Ma4}Y8M{a2vt65CvWT~0n@m?khU4nL05NjgIB?rB!;oPOk8r3KwsZo z2b8BLjd{^*ORWJ2tm;f10LU_|T08XVb^a_1;L-prfIbZ--Dl|VfGg!+gqLI3uX)MZ z^~;twLi)UOtHFcjMvPkKy92NG=6S8Z-Fh8*dRk5sd*J0T>purx=gxjLRYOKZMzxK8 zJz+!I6^F`U)484o!E|e#my=>*6lCV;{-$0@#KHc+Y*!>!fq<gy)I#R+6Hjl) z^44rNfr+!mI;Wk}G*7$|U+hpY+&dB!^INgx#I;6wPlZSwJFRjYf5r!>7+Bu?foz;e z>c|#%Mj5XiAkzYYp3Z>iVW7Q{@d zs9C$mKgP$FmZ=Goc!j>;iSS8$R|UayUVq9rL}~;_sEVnbr_ZrUcfw^%-Z35eY+iE+lr6L99p|z4%`IaDwq-!*^!e#G$ul>zGpw%svX$_*( zcut|gZY4|dZ*Hw5{3AZWiXkQhA6wXu6lSl$S?g%VV`Ptnd4j>(Gr;4E=1>Xprn{}z zTD8DU%Dc31PqKFR)`5P|&A!u=2<-~vg9t4j3PspZTu8)D{Jq$UhZrZ-nL3fjUF^RD94OeDpvzN3hzUYO7_ z==Vm2()&B!zNe@p(cx>oaXTp8OW_a-*;zeoY32*>F zVL<2qg%L^0W?MuWWQPETJ0`Ik#27R=3?{0npE-CkqZ1V~5#eGA{gwEx@NdvzVQ5EJ zEy}cS)o?*NGN-0vAK4R(($!Fi?L)gG0-wvj5j*6$*y?^99~aSI21n5=Ar5b|?FK^! zpt^a*61d>nbMH`>0H1b@^@dVr&YKC?fD$qD&rR4d1l}Ny@=Fd@4>=J(B-fdij1;ml z!Rce#ajjkJSUtO^!tOI?WHpcqyH(iX^{TAe&%uacj~X`GL zQ^Vj`TUW%1juQJTk0C;3Qy;OS0y!s!r~Br=Xdr?cp$)#p(U%MK;_%8#Pjd+fh+5Di z5TZ#mv2JB2BOJA6P}xQ6Z7Yd}aVC+6B2mY*?`U-CD(6yWJA5IoxP%HMnGO3T*Pl(& zZ6Ja3D=>&klopF;3qLPH=!3W+IMuVVok6bL;~`@%jAX~r&emZZx(iG=!FjO_>h=>-VgExvd|Mi2=X09NCNiuA zA%u3`0#mi&CSK$|!S)6Vu<=rtH*Wm?5kHT5J-+pqif!p-^(Ol;l4)$8{8rSEf8DkG za+!~W9&NR=ro?M6V{Z!;9$z^i|AOZI9?g>)px@J>bJCXYS<9$O+fo4`0-VolZA$Sp zO_(6Fy0Ko-?KfS|*5C@qlY>h3Yv)7q$e|}418J5PR~U`;laBfYxYF+Fc!NfF=!QY9 zqY*;K@{WJtv5;mb@}$xyNB41zB9HHxga788!!PO zrDKp&A8+)JR=8JIddrD#F6F!$*e@s*UrEG;v&8RpDVu>><&*Q8>LGElM7+s&T%~<5 z$w}p^N67HNG%}{30G4h9Lbe2gcEO02EyaAEBNT0+qOu`oAgAW#uHxFg>yJ`)SA1*x ztQ5UzdS>G(SM?OLC08w%o7t9?2B-7RbLa5D5)`~q24&5ik`Py=KirE_4TnP$ofNl& z0q8G}UQj0K|L`s&E?(%tKjFSM8CV#wi33+xr}@T>v(bBix4x$ndcO${Y!sn!d-=;y zl6usCSHFntDRkRkSiD^aX2mnYUA8}*h)}jKySBEukQn2(Z2}ngZ=`o6WDeLWui!_3 znh`znk+h5T4H^c7FFSCyqscsOF;$H(lu-rqNDDv|35>8+%Gn}c7xOo#l@#|1%8VX@ zlyhaiQhjLvrt48Jm8}hizmyY!Qq8oxl8e3fm446)*LaB?LQ@3nsT8enN1Sh#SQknP zHc1;fdr5hg2u{>>b=e{oM{L`U)8Wdt5jqDViNf4>$uQ4`fnGEZ%+e7_dGlAS?n!De8o z&U28Ppe9?lQq*>Pp~s`wTD+ zS|ET4Giq2(2lt4&j8zlZ?y;aEdni&>ruimw+mLt>FRb@51Vx5YqKIaJ%rb}eEI%H( zW5k0ErK>)ZR2CE%(o*K-W~#2p80TEfo`Lm}=<7d-q{#lp_Z=j`U{9fcb3`2Eu*~#1 zslOZ9I6u~{*GHlQ#n8u$#11dl_Dx03?STQekG5i=HK&LSOr=-Nr_p7xVy9Z*OQ3Z> zz=|1u9A1T~P=@&^Dk zaO`zm%}<|xBjrX$DV4MvhO|b7FV5A(!tPZ3EM`#qPpTwPLDD21?v!RMYi4}9Ue*%{ z=VQ;}et_i+{ST)Svio07<j!3U4&Ivf!-mZEh7Gh zozyJMU#dCJD2#Whx;WS_WRZ?v6r0wt@JB*S6V@X%5imnyb2pBh#S?Z8Z)gv)+TIAWuYqcKm($F?YZ4A zYlywdLJKCZb;!}|ohhpq$f3_~DIlvXp45<@cSn#}hYd%K$|>m&J=%a+BMqZF|IaQEEWzS-I-?Ex6n9_exf z@S=u9Q}2{#p*2y7>|>-v_9*r|z5;)0unv~C_FuP({l+SHt=ddoc;r9fW2k`3hw2kv zEs84N?p65zajeMpZ?;ZeapK2F2X4-%{_>-$bb^>-#m;5-QSnXmHcQ>??`4Z7I3C{v z7639t+$YlrCVHc%p|X7RkrGK{R*e0&?#}mM2|CE&lI;)0{>0|Y^afRABkRFV^kVg>)Z$q;*ZO*~sk!2o*T^Tna(7SCUQ-_B z&cU}yRc56r+3O`RjLWm(8p9A!An|+zzYQBJ(H`dOQ<|$O|K(UXs}OyBv2bP17_ZGV z@8;%S<>D2t1(mp5s19ZXw5cXNWu^~O{VTu^*Q!uQ8CKGw-}?<;^cffsu_UA-%rKE>C+R1$6Y9;1tF%0s^G&yjNJD)t!`T(ohF|l?C=$+>dQ1-;hYM}pa zZAi|4cudc5ht>$jmzL$1Yeax=qt5wr(T43TI#5=EJF?W|(^y{IHj>kXLRS#LDku-h zopiEHBru(nnpds$_`4Fx{akoWkRV6G5?SA3!xf&WTn!(LrMO0U%xTYKz-K5L204R0j1 z%cbEH%kCC?GGW2)K&4ka#%KhxNV7iZhWH$^2jD9}^8n1np_47a;{ED34(Lco0A z3N@nY*mlERa6CRc#d05E>r>kM>@+KcC#Dblv{aW%5rr8Au=R9EJY{B2D#u96o{IDs zQ7uuk%6>{@PCow0gU1${Pl|C?Oir#5E$KrJQ*!a&VCdaI6- zA=1Nxp1MXnQC)`d`F$sACU6pnAiF(&Kx`pT2s%6)np9ZRZ^M3EI@4s#L`TR0AAf@# zAXg`U(RTzI(si>NlN$vjN5V}z={_AlvvH_Ph8h#eBZDsCV(BgqdK8bh^^8&cn-P5F-;C^@ zfa?VSCN<+Xvdfv1*{wKpKV2-o6u27$&i&3PIJ7NGECxZxo{hP1H?r2WoMa^xB(=N0 zDpEN)TnYa*s#vvAYPsb|{F-vpwN2u&w-tbw1}VkWa;cev)WqWphi!$O=Yh^h6jJj6 zT$CxZKPlW$c%$kHi?^QeS`EbZLvXP#VI?mmR_5_yFdEA-tC$PtEO2_h?xNw)bvYyf zEUx})O;!|LuzQHPEkrTJ4K&%X{X=>GT7A#iXB2(X;ya$kX=^uao%%F;e!F=$CJHpF ztC5-^uV-`7wi~om*G020`#RwD8oaSW?uv3>go|fPdej*3otig3z=(i!`JIe$fu?!J zoE8JIIN$nae`da$S3?5KRxFR|G^UXW@PKm8z`!r!n`Calh_QB^w8$RK%iOXW-{-l- zTe-vC4qQyn?V${EP!#d$aYTl z>HY37_EXc(I}}R>y^6Xi_*Ny~h^A0SMVutWfd8STVCgnc(>H{ihSEV}v}4}@s=8G6 z|KX*8WuQ<}thk}u<&F@GX|dPmaFOmcMEV09l$yCUDVkH>sB)3>-M5~bs+2*>i}+hK zR!d~S;)ntbV-uz`;p|lBz&U3Atp~&l%qtTQIw15(DjdaPBZkrb0 zg}@M?YV#9Q`LJ0g1C;Ok#qks?kHCyiOs?Ns64^yR7vF%oR>BA#$MTyXu!wk$^er5@ zok2E!^~$A-Eijisg8@%T&Aw1NAZ*qFNJu-835mfpQPj{spUE}laEk8KxutC3yb7gr z{oMVw_7&w?hh%Uj@81VN74VSTf#DWwetnqN^qDe!WboI*gD%EX<%RyQDs?O#zZZ{tZ7MJE|ULEezz{pb9bg zt=!*71B;MhFiiY~35Y)(*&7ooj2;Wfm$jl3QrQ`CTG?p)JyV;BNuMvX74h)Sv7U2%7}_gG8}UCER-=#N(iv@ zC^%@}=&*ru!h!xNXTTLQNfl zr(lS#VcGfse7BwfN%((^^h7PeJWUc&lAk|q1-ioe;Rwd(+rOs4N2OEL*zLdZX9C7*-Jz4tNYZO&nevz4oITC<20oz&MoyQrp zA5t6CCWqVUjmkvRCJ;m2W2vxp8hXt_U6DYxJFH>>!T?hn-uSMMB;uT5BBOq(pvVyn zzCX#&Tplg-E&XVss^tU*U%EE|-i4=FP|ExFZUnC^F75D9I#fw;Xi*cimDcjzes3}a z8#}%{NXq=ky^PZWH?Q|4hbb^md*^iC-y|1*x8v?Ojnx<2z0Aa4>apJ;jIU+r+;1SE zaQ7YnHu(kg<7Ml+s&oDN>S+(x`uo=iQpH|dmOF~ch^LA~F5%KTj;6_omDU^Uv7d)| zqQ;s!Vuo8b5uZyxd-R{I52U5QpM94?Sdx1K)TFBOv1CBUq8a0$6_9LG$MNRA+hY5c zPWtz)$^-BUvb*}bv&*I3Ir>9V`)IFbK0po32VNNt?qNc}Q{2e&D8Zq%fDfxuI%Ten zo}-xd84F1%h^?V@9wfuRps^P*j)mFZTK2%iX{~EI0ExGpLb26rMoa$=e1W8m(a10( zj*rNak&b#bo#eiv*Y{&3yS>=Q-}a1s<7YYqzPPEeo+RY&%DGC3FEJF;?oui9SAZ>4 zV_Qa6UC#%qN^8%XvMyg+?5`7K2)``c(aErYU5=F!&P>W)Z z)85xgV2L^R)pn*cv-z)D@}qoWPJr6&@EB(t_CCmP>`cK<*!m4AulUeI%q9ZnO zVm!jhb+Plea($X>OzAmA%1Y$1*Jb@j*>Y|?@rUN5?qY3EEz6v zThQjgRKL4;gY}_CHUrc`Ez0nvKk$FF;U0Vw z_wclvqf>rpA21Fmjoc<J}Kh+<6tP%!dc=WD+@w0pOPd2jA%1uuailfEAoOCv6h%A{jh*lZP&g*=O}-gGI?K#6`qpR||&#R?Xq2l~zGiNsUf@dhPh2}FW*k*Fg0 zbQr?1cXN1l-tSaGGE2}n{ZMcp#zK(aGg6XVoU(>=bmeSB;joj#%NL~d(R)&WaCCeg zGH2ydoKg6&viM^=Bnjx*;tV><-yeq^e_*(#=)krm)Q3F~4d0&)+IUWzJt9K%qHJ~P z{7-Z{*=i%tRq5!0+0;h7c%PRX80f;S>jy+2sE639zUtNG{8l%B_ayE#vm`f+tZ&-9 zKF27g1=OGi9P}Dp$O@vip3OZ0=^(Dy9tx^|78loQeuu@HcWzY^c132(CAamr?}|ay zWUkG3sw>%`!h=(pI$N%xbMc8Rlf6E`>1Nck*a$!&R)BdIVRFIDiZc@k6XX#nQnV+K z!VV>R?Jq~WRuLpa=yWVfL1z$fp`kUAraSy3#kh!+ceCFfS*JEiMEb?iBS$t zl}a>-95V~(j=y%2SQ$FC{SeN(Ky-WmRi;vv z^WbzwmXQTGb6S}VH25Hey2XaWXoMEU|aoB1Hh&P%0L%-im^GS5zJB7q#F zY5b-IvjZn~Ty*g==Y#23Z?yaMNMK`l(?D&@GQ=A8oeXzn)x^&Mu&~Ks)&7}Lk>ugR zMVu0_u^(KUw3<2-ob?WF+{mZMj99~3YXpu-1Svy>1GCZ?5t6ccyX(H1juDQ#{%e#G zF1D>$6i_DUgqb=Oxd$ra)DF*x0*KWf$UpCWr)qTeXEXMq> zI0C6>;1D0qQ+#U65mZ#R%o`lFsYp)Dc%8xkCplqQ3xgSe(?W@MGaxw(XeL8C7nt|b z0()6&iC1*E=*+R%6#Hezk;Ve_tcbOznJP|omA$ZV@(^2P$p7|~;CBCaD60ju`AI9* zb-mLKF;FGS5kw)<4wlZZ_KR}PL3RYZtDd*WrqOuWyjlDCRPR@cTO}@elAZW>a_Cie zcS!rgOPC74tv*48u)n#eCknIZl7qRNpNtp#E^Tiggg`py+@&&ZPjr!wo0l0$7{ibI z@m;6pfe;cifM<$vc#bp5+1PxwnHXI%?q(Q(JrQrZZ^s*S5Vq zfo=CH?*ZtnCnha%bnB+#lIq*3=p(eMJ#b>33#f$T&Rzejp zn5-?L^vn`J6t1+$@yBJt1W*6^W*mC>1tBMKcEk}zT{lRt#@{qJ#Z@FGOM0UM4%Cozi`6+dwjG7A@2j1 zu1d5or+@kF^KxHFrOU|<5fDODl}~$|9y+#}Y1jYeg!a58qHzhMVnxqriT(3Y9`@Y0 zmiR+8Zn20~#7tGVRt>hN$%ug7;dMBTY*Ny%I*wAy)N(sM zyDiDctuW3U;-s9mh1~*d694 zWS4=xuB1>xSz$eH$|ows_5~q{*^HOr_=|rY57i$O@#GL_Q!}*9@Xu>!8s?X16%~SS z?v54mJ)M@wKLZv*^e)S+I+#opGl4G5PzyYAa^{xwp+y34QDwq^#AU+i=w20XOj2TH zPz~IhL9DD)8xJgwkc50MB6tJDT*P#_! z?P2(+q)>V&Z&1EpIT(n{9bG^+s<>`86CEn#&<}OBVq~A4?AY5l!*Za7Czn7Xh(UH( z9Rm@Og7=elL+~?vxZYqZ^C{(D*H24Cf_yE8^{M zMN+CFdKQM+D*<1-0~H8JXKTZ)^?e5QI4H)2*BJ;83>j|*!ze39JWu_&hlM4I;;R_S ztk~nlrQ8vOSDtf#fRwuokM_PXa*nD&v}$ebZb{8wEP%jjW&M@kn3{t~-ZLiZfl=^H z@}>YnL^IDi;OmN)TcW855^SL&tc6tI*GCS7I0vjjc^lsdcIgbjAOKTL{Y@$gQqh19 z(z4;{;}(lKjLafDKn@kiQizajE}>$&kGAxAdTMzqJuk@zi8SZI`W?eEWzg!&vyCz# zJtd%B_~znysA8qMA}O#_n`P@LmO&P!O06qu4r!rF{DzIi zGla#;3Wftn1pZ4x)Uo4(mEt&4j|>H>OPC?Zu%n3>ez1!I^YuQ{^BuI=4Yv;7b%i}U z$x4pzlOep_qIWHo##0ikahZqo66otD%25NPm4w9NMK3y$)_wtKm?*-lfy2)ySa8@ z7cbHHd>zB{5LhF{48E@<|8wcIh+n!4-a+psRuO}lCZi(s^?3U`Ak;SI7fow7(3oqa zX-iM^#4UZ0n>nM6g416!ddK^7bi4F;vB-9*LV48IC{Z-Xm5P}?%u$XUPDW7 z@#zbIOz2s6HX<{*m9X?BsJN!G;^YneCC|q?@AgvUni0S1c~GAhbG-`%<&O@e6U^v z0XN@Oyk~-k_rnb|4n*R)WPC{luu5Lc&`UCA`Eya9pA+*{oe3N`*AwXb{yZ8+@z$~c zt2F&vX*~%)Q_j3K^JYCaZ%~5E3$5hV{Ra3&>N%3?tuvDA26UKAp)85s>vAf>9lmflY|L!&4Nh_Z# z@AZ0K(rn(?rF;LmP$vIJTN?1|+5!^v3{)ilM6trQUW;WR?{C47O0s%H?iBJyaAk(* zIbMG2%{%#rOojd<^A#?+;NgnP=^tCT9?=HVP}&qV^Hix6@<@7h`Sd9ubz*%^(9+f6 zZ}j_)N1_wSZcM2i%==~Sp?79OSxnRPH1NnL&p%}cMR*&ey-erseKLSme|N2_^P37=J>&#j3`RCMnu=K(s5 zp}YBor84V@8MWm_D3bTiTsLoOx@~9b*}*r);HHarld(HodZ0sBqKuFRvyRfllDtF5 z9vVFps-%+Q-z8VTXc+*SXfVqOFUTIB{>sJYL_R)uD#0n$sZKV`Q;*dcr*V%(UC=?8 z3LwHnPf4u?E!@9^k3>pxORR7Lg9EoWgZxTovR_iVmw?8liD^P(j52Fx}~LkIAL<~1A}W~tazjF!Ky<{^sQ_z`PD6Z6F_X1 z%}D_rZ8&{v+S9*vRN`E~*t%&K?C3FrwUWBkO|M%L)xxcuJd@9c`rQ1@TfNKSxeC0 zW5n7X0^fo3Kq6915m|2b0e0v9k{TbPDf#xPLt$`N4=VfHOr>!y02_3LI(t56_0rWk z4_MR1eW3*yIGSKW66;{~sd_?o6Hg*N%T+wu?Fv_S{RtbWDLZo1 zv&5&*zExk|fJClEbDwSG<&RomV%AqT#hJURxW8T-4}F63-qwya)L6d;ng?35beqhFI|a%88fL)p_9>-q2&yycPm zg~#XN&YH#ZczV57d0Mrz-d$5nhbUcEQ0!9n%5(3`pKaY^Vf;EwJu!i)enjqw4c`-2 zLlF&N@4CatHq=?9|C}qGc#S2nymaVJ`lZDaetp1a_I-27H-bKMBeS)i*gkFxAG$+nrxkfSoyZ?xIw|^P zMEh0Yf4?q|1svaWXY6lq#pCx6P5pM?YY0u5WWF~1)!EB_c#nn95Y5g=TO*WC29yVI z-syB}5E0uQKNe>#&$!UMj#nNCmpj_t`XnS((;TKA*aRno4Mw_o0nj8&uyr6rhagLR zi~@-UA5#xO1RHZf~^A-R;YTIfURY* zzRaXuMtqUbZ~PP^Pe6;Ii0Gs^;F18e$P~z5n-iqJ>w-|8I9gjoGs5^Zx{49@@H6q#UyLPqYUhFYDs@ z{l0->zakL63?WQ#XR$@OI)?(Wa3U)S(BXmALJXY)J%V`!bvh<~pixOUJQs%Meu>|F zMQm<5wfyv2?2q#i z(7|1c@1ra6R)d6i0X>{#Qv*B|_e)6Y8o?iNC|q>9YvLA!z$&7nYjH=bPnzZOdJk~D zW9b&Eo`UVW77}2{v$F`PsU;5H?%JjE?!j_jxT6m}p?q|;$t(l9d#h^@N{vbN- zM)|?BN6qe?M}R-smvah8>TkD>5A_^_o*KkS(h`>$e*zo<)0Z}X0wOhs-Z?}~EE1fd zJ9=`32T~XYaQ=m@%N?#rOR(F95ttu#iwX#cw|RqPQKAPXc^-!?aemd!myLe{8-I4g z1V#vVZ_GKqd0f1=3mt~N9+rp#*|(>!#S2+dKkDVUC}G>gNmP_TT&ABi3ziZ+P*F8l z4IUb-#oVVP*a7GUfEOijYAWi96@5QJli9z*&{*+CeRI zfh<`1IkgZ6U=YYG6{;*?+BS*x!P&eE3zDZ3)YHO(I7YMiIiWxv9lZwqkN~uldJ4fl z40%OzNTnbvn7n@08><7&x;Qn`-7MkV9`;WaM7L`eV4t^f^@z%%IEzx$9)IZ>XKCVr z_hXc2cpgZykg1#6Vpp-v@t$nabFe|$?zo;A`HaCYW+s)egTyw>ATd7vEW)9=m{(64 zF}d)~VF`_ZH;>b>EJKjb@URRGqmW)VDj06Qx?-bJ7~P0zOvx<}bj7+DtFrM75Au)( z@6GNOrt|YKk7%Rp?iVc)1Amk9o6RF}7M9T^!p^GaiZmP*=UFKq!=Yt?lLJ=3a8zE| zjEV)SE>*&t!&i4%BUPzlE*INSgikp&=?c%E0U{v6nvMG6hdoG8LabrlHh=QtD70YB zAXN{oC&TiT07;NVn}eQA`o+4~+CLWi&!32I#LCjYx5O|S!mbN1&VR%=Vs+`?k-i`t zMCFy}okzX*#k%N@bF@{^K1KN|8vDMDa+TXpR-V5H0W&p^^<>>yAe?>Cg^kd%F`A5l`Tz7z-ED)sI9TO z;Q4K-f|b@@Cy1dk!+(_U%k#K*ZfQku6iyy$#9pq9wq-%WV2gkL{U0vXgwbX)iTq`m zv!RNrFc2C*x4uFq88@oXer0@Y#dJV>0o5%o3`f&~21c;wk;Js2T?77=!|#tluz}vC z0|mHr+K4z}pUNbvh?L8nRJxEz;~S~V0L@AJlfV0mWUvbJ;eR28J|HXAVF|2cdH?6_ zwc_WCC-ZdP%ZKEdSC2(uQI3mwB~SVMyw2xNZ7vioQ}U>JWywKCr)_8$ls|WngO1pU%satF8ycN)l_A;Q5{0-~ zigm`iYXLZR)PDoL+;&@}VlXe=+|z;nb_zbz2xTmtG#9Yhe17k{4?JDZDpTbt4i#P&jAolro} z;%Qm02;w!mx=SypHRj0TF{dG&CAt#bGo!uuaCh?QXOw4Wh0g!jlJ`qrw ziwLRKv8?opfo8x^7-km{Ryi7j>{W2WZ6u|L6@M^$Ax;nQ;b8OQc3ixN0SP~fG%C?6 zLr0t-9&yq9H5`ldCpgvV6`gf^Nff52<`9$xuI%8}7XWoYNo51$2wG-9+bq#>i0_KY zbD|HUB<_Lx8^--2Ok{@8vY@;a!1Cz<_7HQnTPyopJDa}nt0P@|ee+BUK=K%3^9;Wyh ztW@LJkH=%O8sie67~nol6#o7k`IzbTwFBCel&a1{{?6zv6}^)^3Or(6%Dt zX98v%-hYOdfY%fiIMREtwj|3>egP9hcaS*8z-@+Lb9f_wDw6P$UeUgTCZ_1zJE@kTFQ93yoWhiz=?#pKK-~_;2@3DnRPC2=8wPRlZ;nA=8Qa=KvW2NQ55AxG@?%_gh5I@ zR2R$<0bOz_A(%NdE~E+DP_mjqRg9*Kdw?-fX@(!b1Hl8&S94 z9r~4T4qllu;G6w}w?FJ|?;L!)_|4Hz`#aw*e)DE?Z|7SD-frw>WGfK8BrFPbY(hF; zr}MZq;rg#7mtKbg9Dm1~uLZ=YEG(dKJz$#AKIw&8N>c0ny`7_j-L1n(MX=Y4Ui)G5 z_3rlO(ayHmKiJ*cee=ryW`=tpOq|302w?CK;NCu-6K&bT!p`B*?jDwYxcS5Gn^&@3 ziW`)RH=~bW$4Eb1Uo(MrQqq``phU4sq720M)kP#2Q3zUCLVq}h!b{vNiZNo8B6SLw zS8Sy)fSu6@Y!ytWkHwR<`7lI}N0k)?>e@X^(f34B4-^AdD7nCG$u7dP5S%&UeVSdS z6_vpCm2f%8!6`#q^2=Z@__kJKL;d?GM-1f;vw{75y^G#282$6G;Fge5C%0}~6k`e3 z3ht03`XD6~*MI+Go)NMugY{yM322unXbE1?@Q1X-@|yn2^4^h4mP>w-XYXO}8Pdv_ zK1J3^5@vTBBql$5eDGQpvaffpZ}G^+!f5oX0)V!7LE%7b{b@r_@i_7J&jt+qOOdz$ zHK<}iG&ImlI9o#K$YkunDI_q{saZVzUSEPtV(65QuHvY<~_{O{$(zkcYp z@h8PZhxBdZPgwt25h$8@1i>tUZVN^M@76Dfr52n5@!1)o?knEwuy{|?yl(f5TTU^gblUpfvvp(Gf^K+B?_2f8q2!`%vfO}#l+~4 z?5@!v)_>gGDmnx$HGhN%-$CfRQS(-m?@7IPqlyxB@?lwi=2u4wJ=!^7M*QU5wQPs^CQULsU@Sx^XIZb%M(Jr0>^_TPa5Idpj_p z;uE&E;3N;R?3xjmRM83(9Fsc;%}%=)42Dp9 zksKEjTp0tnG5DFlzEH&33G8+biZu7RvA2m5VUoWS<4UY32sTRe-i8ki&z8GOY5zJB zXQqoiy(>MJqqYiwpde$*8y8BR9bDG}!|$kfFv35h95T0P?RFG#S^{pDUcS>^lTPTE zO@Ak#(ggH8H?usxy9#tA0A-wzqcMJ-CiH=#fr;inmR3<2>1za^d)C>1LMO z#jbas{^e8#s_Bs4#l-F~1f+dhzL^)BZ?=ud-$j(7_~pvY{8y)Q(T7o(_RWHDv$Tv4 z!X&X9uuTNuUpcp)Yr)bpy7deO&YZjR(V~IFv5GfN#(Dg1eLamX8!&dwPCA!I1u*Sx zh~4xedk?pN^9NB;?$PaTaGb{i-fVAni!2$J5quEvx36}NI_Vr-uO7%kxVSbS6zRx# z5#iu;4q>F+YTJnlnU_$`)K$0H^88C@kUdy}qzO0RXO3zv9=# z6A*BJz2Tv>I3Jggz+!u=IYQfNgXLKPml*g&m6sItHok@jdGlc&%Zj5E9^N$^6Idv- z_$b#6x~Mrl63)p{j#Pr!Pfx;(5v%xm*LRKvh7#YndknRy$7>1F?jE!C=QYP|>?yg< ziqB9BU1fG2oxE#*lHmmFPEyJ4a1{2+^%(zu(=v%a*NgKkFO3gCdUTU$hf=Kcrr)uK|vop#xr-_jCNA8x>znatNEH*@*`yJ z1aG^Tjq^#&{oLM?Ee=5GLbK-~KVQ}cq?G}+`3qJE5DxGi%^H1!<0G3w(ZjIywhn)P z_?$hJj}vQ(d|o3P$d%NBI5}(C?9-}|1yBovt>Qui`(b$wgi_SLz&)AviVJ7j4|WcZ zD9iyc9~Kri?VN!$DY1IR#V(bVKB3t^~1V&5ruh_i%&R4H)HJY>TdON`W{nACMGPNU_e?(*uh<>1L+DGb)04hF%0v){`^vR_~T%cJk z^CsDqzKwycGI~`+6-{UVHW=SnKx&LHPC4wV=QBeCbJl@MP)9T1ev! zak*wTA}xMdRQ<5m#IpN$~B2T9z!f-pdT2(RqN1qQO# zgf6tjZd#O4*w<94@=4Ru0UxU}jV#MZ)0Jzdg^`OZ4mlyrqvPab(qGYYRW2stCtL7BtHm?mQAukY^WANlg)eHv*hg!H?%*xjT@$7y@J=f>h1t zuQlfFc3Zc~t3l0G_M2)`R;CmsI=e32Kc1pXKS_CToX59Po$#jl0cc)h3Q;eszaVGu zrbgL9C>0)A1DKd~$N)%qY!?w)ZkopJq)g`OC9>>1D$9gOAy=1w)|dGInfwzmqf~Z3 zh#fl4!+f5C;8{P<#(A;MoWScv1R(sysb~zt55}>L7RGj5fRhyNtsx*En4F-XqYT}r zA@Di@_6I)|x`GIH9zf+~1Nl0Ex3xqz1UL&IU@yz$RJymWM5BPngVRdSZ*cv=3o!o> zi{Io`W!HEKXX-qEqJV_B-;baX{b&%UaTz67B#hJlpS`#1Y9raw2LDPlhbknFQV6ii zE~=XQoBBZNQmbMn+)gFaRAYFbNB~Cy;&x>r@FQysf zkBYM_8bud~3oTMM;XC2*<|wACxI3r6n-cF%{!F3b2y;1-N}}9!RhHtPUQAYQ7B(2n z)rAhDQ-ragOqW)ht72i%f;}C(c!1Ppkzp;$Ga@g4&}9^zkFF4rgl3`~8`y^2v#n6% z0U`YmY9zr4!pbGBNM_#N%Jz;rh$qC-LS>)D#ShaHNukcMWx2_n=;9^Yw3e5jr$eO4 zPbM(uks)oGad1?@L8cT;CFf$fN2UuKwd$b6>uHJRb@@ef2{V9sq{mkU_BU}?Q4)M_ zVgJg1K5_I7dHNHLq$~_~_1ThL5MY7EMm1oB*a?fM+1?rqpp!IKo2DF^g0U|{YTT;% z8O2_n;vqVdCWG+GQ+pg6mh{Pfc#sVpvw>Yz2iDccS5rxM#|?$C2Gn7SIJDXzQ|Ial z7}=UAQt>GA-A^m$)nZyqLpjLelPN$)s16x_NGkzpZY)}D-851A&m_~X6b0pey@qb^ zvWouA<^ht0bTpc2K|MY`KA+}A+Dqi9a=>}YcsMRMkUrRI{1Y|cIL0nWt)MSlP=IlS z{L-h#tfSE6-^3p0A?ApslM9GN(=Rd0?kRQ1QH6CgzmhJdYl*MMs}#L2$c1#^w8Q0p zw#Mu`c7#3be1RDL${~hyZcAM8A3s@@f_ffM44=Wp`0JgKDbfMO2{!I9L`}4mPsigh z1N6Q)+lz3dqpUaaROb>jWj40S?G1F{X;L&KmZXIKx;OB+`MgHqX7aC9r3pa=0gd@% z=fVt4`J2&2!%aKWLCIIjrZ*DYkT(Q>R?N(D-2CJ^ZZKkEsV)y3Ws4XHn>(8JYr{dw zzv~ykek0&CTjWJwXyirs*6;yYLenci98$= zKDSu->%H>1GcEnQ{^q)R+gtGE&%!%v`7e)-dds`@-CY~nkHQ?*J!vTDPRG`NYySiJ zgBFfTA4^%oxIJ*I8)~uPeRjJ$9XHE9qAX6cxWL*!xf1sTos+(xbeGqxq4T{S-+y?q zxuj3hrEhjOKP>*-wyqGs(3|5o9Z2$H*)oIRnFE!3DKMa#| zYF~Z-f&E6C>)$NxM}v4eUfNuL`)28RdbzZ@`thxCF}+jsS{2uh9)cO3pO4mg1kaD2 zcKto-`wzQ*2X{6pjOk;GADMyCzt8tYIi4sD@>g;}`LPxi5q9K9tFx}Shm1$Wn*gpI z_Ia%ZIND0Nmv* z=x@38zlh-@PKJc%Zw+dH_5Cm)qGI=*|Ne?OicEl?6a7<8>9}nW(ENJyVu2Xsq=fb5 z#Rct9{)o;#E&~_yE43;i@#x;o3W;bYOAKHUBMRmr3=XO6+Pyg!2bQn!JVF*ulnHo3 zIVP1mk&}-B>F1Py#kutoUGGHsn5!IFmtohP8GWcN0Ryp49IM8EUXsJ1N#jH6XLDxk zkXQo1z)?G5D6=~TBA|~gN1tf&(xp6L;DTzB9i?5(&aFe8{qoJ2*+WD^TOk4$3`ZaH zJTved<0+L=o{gD_lcJWF33wH*7FjXq%v+WW7@Iv3>wyF$e*fF;r~*X&|A@@;ktw-t&tWbS~>^v2R#Y) zIeePUK3l)4;Ax5l7l8TYa(k4XoWNu?qqNb8*wj#07j89zbn$1O?+93TChM4dDG5&d ztzS)GwWI5G<77C3CDfS!e@tpVzlg|@b>Z)Cm6KY*-ntckZX|Hm13BolDT=1{&`#d> z4aBpIPxO5SK*56EpQ5bMuouqq;04oLU~%Ht;KAu?r>`HGc5{c_AtJBh z?UEes`oW+2T?ZLs{y+c#M}b!bZSs4YjJx;Enkyauu91r??A&lx@IUoLmSnGRxX)elwd?24IRy8#g=lHH%GCcqhM>BmO#X@hZO;%Mq>+m9c1x1M9?8Mg$4+b zl627gDlhnoeyxsu*@y;Sq_~=r#^;~bjo3NI<5L2~6F25SAUBS!e1dLbn%jn1cI>L1 zQ2(UPbD{q>rFAL*Avre&I`Qx);1#~=>Q|A>GWS`5 zcwwnbO1s_eB~LlMuzDtMJ^y>=Rc-V6ZJ2yMt_h zO#aG!68EEtI*P^iLv<4v{Xc4!GDzjsV9jU_%Nol7s9I{AX_ohnOB zo%tG-4(1TszuL6k+a3Z6)wNBz&$uh>2t#WoXV@OSYUw0fVF=+3*g(7(pTL+A0yZOT zthPJtwI#L59wfF+EqNBL!0zxRl%ZaKb3$VnlhlcTpVYrGAXFUk^EEY=5NTId}29v8CG1HvvUwb|x{@0On!Ev`I&n43#) zYj0=omP~c;f0aSooOOY4lt{^Vwqam8!_6Q~>JO?LNW*vYdkjx+;d{TdeMW%F`f7xe zIEYUjR+DPSFQv?%rQg*=8P+pvuF4$5r*FrcPe)O2p8tCGl^Su;sOgaNmVMu4sku4( zLeonYtAcTJ&ee6%KejeiHwv?V{#mf~tJwVL>{Z{Rw6+EsDC$c1!@s*cS|&)skEdL+ zm1v*C5dZ)|1z+S~31N3Nzw^*gUCppniXoy}y`;DBeZ>{cy1`<@|JXJ~K{RKNJPi;a z@qmp+m7z`ejWo3Y_Fl+y%gP!#y7TEt8~tk{BOiP!P{)$Nb~;Kk^(KOUK~+FOZZbO6 z8J?(le>lA2<@<1DMY)BmSK*o^b{5tqB9&5q;HiL>*nUB5*X*bmoL=84_n<`wYj-jw{rHwAu=sK zah2+hB*UB6==N2Z{EjPs6aub@@?wU)W~R-iTF0xR4Ococ$GO(`l10sKu}N{DdXz}d z2XriFc5B)HH`TaWc|idy@u_N<$`k^0wNyXinA@G*gXb^b?C-ufy5-!WmD|qmttaRc zCTX_GdY&P5?sUyFv6bbEsHn4b&e?&nE*vcj2+uZRf<7psxMJUbz6LKzS(K<=?-OJR z)tV9Z3Wb`K z5DD|&G*QPD->S@ikhX!633C)9G~rt9zK?Sz>Y=M~oTx#3O5q!YwvNJ-Naj&(9aR+1 zfW#}%eMtH;*3Bp$#|#Ooj?xq+C&XnWoEO35m{Crz-5LzQu!EFFO86N}`#>E;W=}MV zbFm!r28FEyhPrF@oa|+lpn8}dpFp6vRw#`N z395q?0qYBoO?kcMYm0Rp7p4qJVHZREF=Xk|WRL%$&nvnNtiHFmd} z)ZAUL7e7QvmX1c)p3+gc72M_zvXm?rjs5LUX?(gIf1q1L6Sca**_!4|awt#B z2v1snGL+-AWS7iAIM&=>E}jxuV40?y!>~6(`hP7%<|M_2oM8B4(AJNT5BChaWuwsl z`e?bu(h}jR`O3BOs37y$g~Ea32u9Q6`j21}>9HE5QJyRn1{>d#HcZ!~TlHz#Om^Xk zGb`*n^V;Yo-B(Wx8u8D2JDZCQKtjoO$ibk0r-v~f&==h0 zh0$n+YDHGZ3W>SV6%X{^W&$JnbZ{mkzcx`H4|IAC=j(HNj)|-9E${-tLpZmb2WFjc zMd_Va7exdB*nKA+<&gVGz2w?!owcum&KiAz6V%^Zh?0R<>Jc(?*H<;5E7Sn{K7Yo4 z%dceG-=Ck+ddZH?!sO@2ou3b)tWQQ5uQb1!E)94>(53!UPJT=??wQl5_W?8t`dCNN z$DLVEDJhE@AU)RNFdeKNO$LGAxEX}EePVMKdxxQQYCxi zx7zvL2XM7>ixG5~oj-XLouM#m&2cDyeO#(a!}Se)5fW+0vdO2H27XL>spXXmsaGQ( zMK1AQ+JEE;0+?8;;@LU1a69odLCRyZDbxV_@Dv-KHmx2qe9;8dpSfz-H1SrMd9kG~ zqm#2VJW@=BPv%CGOJ2xY9-*bsvXe=fAS)K%ce7CyI zk?AFH`;dfn2cmNVCDEl%VbMU$4}ENNcAq>ap>YxN+)9domFc=WQn$BYgS;uV+!Umo z-%?}GoafR{2{NJO9~4nIRyA9p?$CcV8I)C_nUnQt2k+K4m49~l^3?%q^%ibENlQww zH#p8QYcHTNd!h3c9uKMK5B@)Yy$;Y@&`LnhQv-UwBG7YG0eXc0k~+|H5A~i=33^qf zpy#RurV*_gl-qIC1HUi)*s2JoB}Ywg8{_g?Rd7pdb)i?QF!ahQLtQuKs}1EEx+{G0 z_3F>Qo^$${-nu8C|8X)}<`nGJDH6T%L1-Elb)v3K|1hK)Z}IDYz!Woi&r$l9>rOCF*{sO z&!Me&>`Wqfyq!N^X1l*k!_iSH2FznKTTbjBFDi=Y>I4*hRxXUGb>7EwdyG@_*eX5x z72fos*0#nk3PIC_Vi3j^HRXQMPoyN<;c5zo z@<7VDMm&f8N*n4>IUWKyD>c8#n0fW3W1rCiclgc?xPY@S4I)kn2TOGIQoLA=!q2#B zH>v!dPDZM*SeLAS{iU&$T=AM{mQ?56t%^0!8k&4H2Z&;KP;)-rmUvqQXr{{J9vn~b z4F`e*Ni(t9Cf?x)wp>jFY4{ey0$R)$m|e^O6Jkq*v?etszH}JOddV8v+D^wOu|}oy zu1}mjDWF*{=2e5!Ng26b@@~7MuzyZ8uoMCp_s^pOevWm2yrT==%ju|y0l8&wQOnD! z@v!qnOFhPa(DNo;>2v@sk_|56JZ8-QUh+VHJNq-GgYrskc_hvw3)U(UobOXDVuUA- zRtF#EA(};oq)m}oUIvRC#m6`nO`qn92F%^^Y@?s$$~uDBj}h9eLBuTmsl4NJTwBDj zy;8_ag0Me-1{ELT@1${dYw68($4vEpb^S`_ySrd+m3Gf8ete%<;gu_Q7QPBf!yK%` z#Nom^`uT&zKUE*IfXe$(5@vDQ{4C#`0iqQu5?I2_9w9Or<437D~w!>b_7gR68J3{%TCrID|J zJPFwrWiWp9LD~!w$RZs@1QE) zb&|ycgq-6lNc5y=?L4}2`9XkK3Oy^$ytMzCWP)xyh=P-=Add%;`^NOtBkurwt4Fzp zx@J^=b@ytA$nZkV{J@{&Fwe@@U8&(T9^iXW?8lj(DA1zSb#WGj zqv8ye1xf0unf?$8gM|yg`+Sa*emIey`_6p3lqhtvmoV3RoGV~Fv3J*5kiaJ{QcA+l z#yF6WwZ?>zF4Znz7|c1iLja@dEWC(ZWOdAc4ltpaG!fst-uWv5RsIcgNz{NZ(hYcQ z5#8%AQ*g21(4n9Up+u89Z@`uZB|c83M01#v4M`5tJz-9x(26LbnV~5*r_t+u)&21m zCA>H%6oNUNj?qilm&^n1E-qnwd9?P0USv(@dn#R9m-E+jEuUn-2-c)9`bd7g&$ot` zIjI5+e+-h+xvw7Hu5%CMK$l6xDhK*6sC*>z#_oYq7hJi+PWlp$y#ULfMA9PJEoXP- zp(p|FdOAt*fn*z{9eELEG5sN{tJEbdZeQdOz_K83yKmP~J9xR*Y0_NcG4QJ^n`zq$ z9AmD%rsxI$TlxcXZ6q0pBVY-KUORL+I0`YM8Ci{qdDvfbe?*I!iSWt7N#cW$5u#_kvp8c9#uCqnKt% zE+hbp4?91u5JMteuDvBjir^_i&#%>sl`RSFd(Vi-Y@2A&Qpc9X{Y4_t)oD16vFs)p zf4FNY2^NhvPNoGxSQlA1faLYJZ-tMu>ArUh(B*{ijw!6DuoRug^i&f6g}Z2ZY|O5e z=k`wuZV=vC2PIt~2VsQD@V6nhaEfV^=(`D)$5U-j2gTmf=~L zA%dqI83v+oYejCU!)JFbY{zVvMMCvVZA1*X@wU|dHvV(4)l%EtgO)njdh-k+18I_{ zS$-BzO2zcGo(vIS{Ij3Hw5Tm5gs8Q@ya1>-2OJ6ky{(USr<2nxMP!1pKg|016@;{$ zj1m*VbP9^dR9vNi?Pd*Go3HmV(Q#zvqY>K0#6XuXs{$2VFlQ{~G4Y)_>RE1&<|osu z(%Q%JT3+ToKr*bQCg26{vy8QLC{||3$%?joQOQX9(wdRXX@(_p2|ZQsh6Yi+Gc_}A zGx|pANknO<$flz!HBH=J;pb=!g6izbm!PWx7Jt;&yw7<-x8*#=uZV2CM95`t;SwwUBnmD=id7Xu3DeljIO^%u19gI!L?YX^oo|<+&mpJ`1d*dXvl!!hAe|%*1Ep9c z59KD}V^~)Y%kpn5A{jyn4oX-UNHIs|g5?6TfpR*ERv&e^=4I)qrTVz}3QkzT7G-0~ zXECbc47L*ZS5Zc;Mf&btn+9sp zf%~(@{4`6)-hk6$=p~E%8=dQv6uR1Juff#Wen|garT;#r|E@QgNog_)`(j-T$$6t2 zmL|th2w3!n*Yv(S_QCb*(six3SUvB`X@`hJUIM#8Ubo zy=*N0tO7+{XsNX(;D+mvhMPbNRx8SFS#mj%#Dy;C&a7~282J1$#);Ng>|dB{DIh4T zU{qk)s*mb}pRBe08fkI5e}~A-LhY7XZ#ET0WS`({u3h52g>TeJ7KP{9aqGP5t2@8y zwd{-ypD%d!+XULi81e4-I)B+!8>)6!^%iF3VL_LB)cHbXKwmhm6V&2BVYP3bxI&;S z0Ribq*ZQW~%D6$6azi~OXI@CzbXsc!>UbS9EalaC;lwa$UBm-&zLAoM^~O4$J+K{h zmg78fQvM7lAL+912}*Z#MWd3QQX>ok-hhDTbp!B1oH0!@SrCHoI)6)f4X;$9Mv9Ul znXm|xSc?xbGVB3IiQHo3qCuopJ+F@VvzUfY^fBic>?L1;v1by6g_|DlIVgC71?G>Qr#9SCAY0?WyRk4ltXM{$Tx0JtO^{ z3FyrT#5fu%?DF*Ra~bBPkvH8`!xkd?tfrSK2nM!(xe27<00Kr z952phP20<=(|%M7>+eXy4RyR&sk(BOS;l**Spf)}Xj$2K)cK-G?Ns_D4ONaBh)Ek? zAaNeM7d+u4Lv`cJXeP{4?SYJO(vN1 zGQXAJ){>A+!ceX;#1!TUnodySBX|U~q2s6!ksiQb4 z-0w+MczRmStqlkdxgyDBd=kh@IG{}E7oYO=V=zUSbQWQ`d$gDQumU81XzQsVPViD0ne5D>|KF!hPDFQobjK#zf8$MD-+#gbo$9AhJGc$M0_UQ0PF3w;u)By7;v|iC19(UWq0kQEfo%b{(BHW4`6-b@f zB?D5NpSeat!88=$TBi}MNRW#;i7vyD#AE1A<=>d368ErSI>~PYO3}zia@<;?2TauS zI62=?Zwc@~221Q=GzK4@qe~sg|7jyE;$)F3jMC_bQsejg+BTg0UbhK-Lrnc??8P0KK zAgpl<1TNc_8l4C+IeW@c!Eih|MSqx{IFZFO5qfMKQw>^=Yw(*v88FXav46b0yS2Ow zCx0nd=JP>w{^$SozbgM7JJBS}fF<3t=PZn(0rU8 z>~H(Ssu6>JL#!ZYy!G45utA><7^K@j;Px3;nb8A3`Lp`cNWStx|I>XNC)Irdx|CD< zGw`K=nV_44Md+uqD?iugZ-2|nW|l)2b_zS+z0S%x* zPNx!z1`$6x-lRcv8Yh%_+=fZN1!cdO=57&loB+0Sn$H5;Kw@TDc7Oa4<9a*s^G`nD zv*EsEqm<#k=CA)iJ$*Km z@#yO2DZDKx7x`ugQ>nLb5N5wjk@f2!UBTFX5oK2}vQ~hu2H-jt?w%?tla}Or1gBJi zRha`QSUWPJ9Iha0EPotEl@0Q-9)Srcy8QleE~8l~n5Aj)lmAyNdmksYj?8@sKy zY8{MPF{Q;rI3Mvvxht%$xwqkhK5@EK+B0JdOr2MIe=gj({!bYfUz-l?yMszq4Ri$)?Fn;ZXhB2L?xs zLT#Uuv9uOAa+IEs@624|^wz>x%a){4KK7ODO-2{^;BVcJrj%)o%bAU83LsiHet(Ny zXq`!T;2Fr?^Kgp@$)Dd7H4x0EJwBb!A7(qV(2tR2p5mGTsM!> zbaWmUE^Beaxjr^)L%?)fYITj1QL5SQz2rr78SqQ6P-OWs4RLS5ED{Y4AMhpiGtWZZ zmN%}yHvG%(`=~!fG@rB9wc?-}FOx_y8h-$S_z2g;N3Hm0RuWERFoJ)C z$y#Ua;eTlfzrB{A_xbOs5AdD8rp)b5)rWUERjKg$>e1Tz#>1~S9)5khQx#$h$0#LL z8BzF0oR8%_aoYou4#Yev=)OaN6y|<@ZJu4bcaLkjF z`e#*fUH(K*VbV%^3$GIB1!;x>=q;#S&`!Xl^fZ2tZR7H}YA={RrHYGkYxO=yxEK7V-AXYHAl57enU?U@h!53;-6dcVxU zLh^>T;0z!Awb-6I@PJjUvX2HHuay=JV0-x-X^_Yit*+He8-B8mZH ztP1kBeEv6C4v_$j2i)#wdfkw5d?$z7j0$soZCpn+4zg&%iR#Ugqm2vN=c<84NJx15 zX%ZDkg0_L*#LI^*PsxsxFdiuQBqf1`Vt+(zz^4Q*2pU1#^oFoDmX|3m#l#m!SjvH# zN<60&g^LYAFSat`8pBbZB1RbY2#7)0@xcF`N?1Z>Ab^lLa1rI~QYxeUAV)N2{AbSQ z+uz#WwkV3FfuSfo`DWcc`d}{++h8vQ9zGrwMC>yX$jwkwI@ODpM~V%MMS2-#1ApoT zcLD#xYw4_z#6UNk1R;b>XNZVg=Y2ZIKfN^Lwv|PKHbHlB{WGPldp=d2#9pM;^m0a# zL@pLPpkgPk8(G|ulbe1b>BS5np+}53pJSdf4%pX&!AB80H=rpH=!PC1GkVgF%o5Mh zewdv{1qa{?SOUEsam;*7K zM9WT;pBE`Wx&!q(2KAEa7SlnTmN~Em@lfbonpIeHjtb>jP(KJ1lkcXnK;p(xOwhPV zFWKFq?%;?6MV94>+B(?7Mx%hN(8I~#;69&z;&*g8l#lyP(0Taj{sHr8cz@sn?^;_w zQVX{wa7=RDd2IprZ+DB9kQs{YSBHnYFOGgb*gf2P36yV2C;safZ@w5ee_!9sxBd@% zgYS%shO=r`7C-pCy#@XxfBtL$%E~N!coGfc1RL2M_Y?i2jAu*jQjDHkhC?Pz0gic( z25u1@huos*P2{S(jvbbu@_)pgT%Ni8?b6i!NhU}8&%X74K#`lKXOz}D(AMW|kiV6v z0;l=r<`Nsxm)^BMbjh&cjVt}qQZKU@3~eL#St`GAf*L2{0j^kNxo5;gQpG@~SC`~q zRnI?XPj|Q&YWL{+hDfSis|g&&`8f(P-<&=*s4*NWal#o*Uvr3SnSV_O0xr=S9yDHp;YsE zoJ`->+UfplNzPl6vYPH?nW<~(-9LVT#XcJ{JzH;K(V5QPf?9gpe)~>c3nEOTEp4lB zk+}(6i+44SoCoIQ#(z3h&ygk}05WkgHCSXEgDyC!_0d~?dLuB(YL>dJGeJ$ehC)u+ z5+$(e?NZg2(Y?MkKvS+Vs+;=>cS_*p(X(iv5};pNaO>IaemA3C$^yWb1AmY5Y~1IF z-={!TY1ey6I08%|h4cv={&NJsAjk(H#&k_Sol-pg#7n6l&3_6eGwGZ7@>ziB4ijUb z%{40FU^m{pdGls}UoQL2KTJuw#o7NYclEo^Kk}Vp^-w5s)G0^_Sh;pN3T`GQFgWaG z4FMrmgdRze6y>|7J3X*@IXM`|o*sc_%yDF@HKs)5GEn5Eq*l@iVCs3WG|+w$UF!5H z2J4S5t6j1A34enr?LW6KoFPS*NHoCN*7iq~AkLP8@XlZ}>%ta{O2 z=QXpaqUy>|78e^3sH6I6^Bw!7`*@AN3I;0IU6lre5*&v~mqT^!0L{q%SBJ zn0DJsNesq^XtNWOkW1am(8#Hp6;0q1^=rCt{602O`9FW#dL~tA){6ep%;6^VieP^~ z*xC6~sHmKueyf%5Oo6v7oZnRn7zok`sfuH~J}$jXLpeE>jRIgrA)#1krE{S3D=KHa zte>i|<+_rdX-kR;+^Dba5$hhQ+PtcXv;700vbUdjR@CaJ(e!Fsr32QPzp=Cjx08X|Zw^|K%^pc22V*OyG?y97o;m7P5{h zZDB(wYdFuWF5#8XDGD-nEBr1D5~-FcEEDMA=$rZLRZ& z`u(o}d&S=x5>_VJ3MVw9Atl_~5Bth2?kEEJ$tHg-o;p#sP~DMhsC*Vq0c6oK`c62R z0LnAWt4bT?7jX79QhEv55K}NPl_}9ckjoDMn$Hl4c(3qbu`qPA7I3eE{LCt83-SbB z=UG0(*SLG}S)jkkoG!at&3jbAbnu}-w{D6xSh0p z#CU(*Lnp`mFrYMN$-a}Z@cZG2UA=GbmIYb8y;U35D%vMB3f1QGoR;IT-@m=bvbOX* zcP0E?s$unHoiJ#>-tk11{FqdiAcXrfyk)5*jyrY$(W_ETZbDi>2%yFodEVMQP+U#K zIkp}=WDM{oFb;D{q%R@sFwhy_N!0Q(ahZRf5*|10Ve)c1E;NfKSiapd1TwC-CYRB@ z|IrHc(hPUWUB|gYhg0w+gMq`#rN3l1EnPPqcOwQ4JSF56Gw}rZlyQHxPj0(XPuy@j zga)X0pi2wJdRajn3!sjrS6km)?ftuf;V>v71}^Gb?F=;OH@?UX9{@1Z9s>Yk5fE z=e2!B_XI>-FC`pHIPwaw;0a>6qP%}*5qkro6(f!)U~yjWC~3}4g$HTQVU_02fKSn)moLH^n?K&M`YFbMRUW=Cdp!;8$yetu);iHIU#xY$SbGWNG+_^{ zFV-G?m+->^a(|g-2?z!vD{KUTaS#c*ui{I5S-@bwnKEpiqtW?FXLK|K*^9!f{`|YG z-c+IYn>AIi7X#$j##CV=(4BpW-TT>F^IiKxc^{Ol7A?@8@g#V=j<0NY-omZ|ph87Gb4pNWPN7P?N3}I0;D23X*XJEKGTAb0yCus*U@Q-$ z0tgu?6qmEezLR&UwSEL8YlmtONf=uX5H_;4y-iBgv2R0j&Nnpjq;y55+%eoDnf{qV z=PX97xLC9^)D8$~r*ac$mxCT07qaZ=USim+C31`;g4$HxaH{|KAN)L5uL%F!22S)6 z4%IK$2Y*O9V6m*2_>cdgc%<<=3ktKGYW&#bRlrje8m&1P(fDI<|g(OHi>7(`%6? ze4py3V^%jMjx`39XgpS9Q;KgL#aR?*D!ok9Kz|MncJ^6)coHSyh_<)9jKJ0D+Q0^p z4WjDx(+2)(R_Ooy-~JC{di<+%G0y1;ZBY7$?N>dcVfI2`CUo3@ zA`7`AxH7O^PAk@S2$Lbd3&$89lAt+>&Jcs+p`TfvC?`BXBdQ6pIL83*1H+W5c+JTM zg@0e{e+CNEb$hLNOr+F|z5LXK*OK|Ka&M%1Pto-`mqvm+XO?V^(q}Gs>))eRcH+E0 z&2wMfiIM?*ksd{&!sQ9kHjfg((U>60%TNScgK`b9WmRl_WJyTI`!2xUo=(|9=bH-A_ll+}L3v0SC(ZiIEns9yc^_H1}S*p+eP zw9G_2AfWsK5HzRJXk;b{rKYGsPP1vb$v32>3F@C%EJ~N+%pA@Cw$XYhLmhw%;_HoP|jQ z7&@U*zr7{+7Io*@g@j{0PhT%R)Q^>Q!4Aau2>5`{>{Y}tI8DN$2!U>aT$1y=rQh&kZ<}bVFpOcO7<&vfM%TSp4yEx=x71gX3LHGf^6gp>RX z>r#k%Pa~p@OF-%%UbhKRB2gTiRX&c*5n?kOK9HGLB@v;Y9| zd#A^0MI8shAiD~(X>!bFQvmPeV5OujqU9CgyL+7?qp+MYX~H@U+hYOH$aLEpm1Lkl zvqWWac2&1X#?)Dqd0BmkqkoOxV}BDyM%;locMA7fEJAkZp1B~)L<}kUDkzfSY!#zI z4xrzG8l;yA9a-=|@-Zu^H&-SV$ENGdSinT7I6*&Yp|^ErYd?hlbOY3)^j=F%#E{Lj z$Z7Dfz(vbzsl5X@(vi=ovS<{M%0;z=dlK_ZIMigSbr4IgYo}B#HXqGZJ;~nC_(rtbi7> zyv+Iw(LNJ^wwGIEUw>EHtRVv)H=+b!BIHoegkz*+jYduc+AdsVYHtUsNe0u9&*Bbg ziScuG2JS|$th{3lL*yQw@6g(a6LoA$9YZqVo-B8aK7Tp;AYi?Jz28P$9=V-tL~&kh zsKwRx!w3KKfB8QbSJ&3sj~}n#J-8DHAU6glhOZ7AIsTP7LVw(-ouLt6S1R~L!DM3g zByNcuLPXYq%}urBovA<{rWfW*wy1CWK8Fv1tJ=?{(sGj_!vTT+S%e9n)_89q015f| zRBgKL=jYQlRhQ@SuhFv;zX){!zdw;eqm-$gKsVo^SO6@M%*BghB0DVlC~s-+PX$+zUH zaXkA=)xT^i353Z=Ulcb(cXtJxQX1EO$7g2LSE(_r>+K_G3NQlhIUzMl(SQWZY>a z!4&r^%)&zVb?$^qr)jr^$VT{iL{Mb4Wj2YS@qZJidj5!;-DhqrWLUM=7ye)b53qtm zhri__C!&hHt)7ybhXQ*{T_#{4mLYA`GVv_Lp3bRN!6ZwEwBGRL4q^Dc>JX+|&a@OM zym2^&8}-L>Q+=z#VcJ;l0J`m3MehqlE%AGyWvNY7q+qvBhHevmRA-M*D4BIyLj>ui z>3=|y77eE{sJ~0Lrz=ZT^dD)QsPi}(Y~n}`lOk3P-h$2u;Lkf~Qe0fGr+CmynmFWp zy+ypE?S9}Ue$C?HSjsn8*FPYS2ASvj|*A1sp#hE6)p^b%|?nG*HutQA>8~ z%|Lj(RsPYOO0W0xHWEn14vnt1=!IlW=#Qo_SP0wVMVzHfOvBJWghoP6VPifKtAEV> z3q$v_@Bw$wxaS{Pm9oFb(WUP{InZY@C&cH;x)}l6&XzxC?a_v}ZNR=PJ=3dQeECT?} z|CM;`T!P98rEJbfK_;py#$ll>6JeUR1DO@AUdbQ>k)YAWCM zUdAZT{J#M8oPrbpW=5NM+5y8!c+hrm$)#Y*HUF@FK20;Yc|Uqei}g*?gN(TXU4Vh~S6e5-(Q@4v-=zf*y6 zy$8%Z|7|w>&RZoDK7v=NHzIV-*RDW`o{jNPpR%}!f*+tC0{a`Rgo`YM@-}I+&GOJS^5zD{L550`&;>_C z0ep-8ssO%rm{ZWxMd^y#q_8U86}_BCqe_3I6Mti6cj+q1m#}Q~CoS}n_*6AayFns_ zj4buOdFzC{=YMUDDV{|Ig(i~dUL>eYmc20cbZ#N3L2K?npLZj;ZV^ESAhN(i-SN173D=Jd4qlYf++-n4*oCm`OcQ#Ss?KL;fQ zMD#eYd64^?Fr}yQ2)W08NsF@2wq&YT4Gp35?OIow4K!1SgRn(yPG`8+k&ORz6b_Ly zj~&W!GM=eIa(`1FXr$+Xhu;a{Ni+341+Wewu@)(gAPMSn!W5X|lj-A4c#l|3NG;*STtov= zTrHYCB5v->=;SO-&o^pMol0-AX>yXL=UPYaB|t|SYXkY)1N;>gQP$YUMXpG*E48T> zi)3A35N8+RC}zR|X>5@w zO@B7k_l__u;$nmZi{3&dI+5eLT}}%+DyZ;c?J!kE8ne*0HToSL@g|Nc6~K83-!dW< zFe98aev}6PnzQ7?6C~7}M>tdpahwLPvRIXup9H~DDn}kA2UJ|uXXG;6%-}IYM<9W&jJ`Y zr5P4pQj3I}C-fZ?oc!W8#I}YRash93el69z1=V}$Q}4pEK1AUJmLx-N6VUBxWd@mh zc}%ZV9wL!3|Gc+JBP*1&7iI2CWjM`Q>m09ld?&GOUzvC576Z+~&2ME}W@Urj=6_w{ zSpbj)xfWI~<7ALt<|{y$4Qz`6D~wD=Kor#X%=}Kt_Z8~*&j{vr*~4!i#yz*zyZ~-D zQ>PTVZPV-P>A~l)%d;RXvN*b+Jx?}d6GCJmBucEiZMBtzqpM$$lR?JJaHPYQTZ+*a z*$-e87>-q?;jc?z<^X8}D&j`~bAOQZ4RP16NT@$r`@+OeUjQc`ITXQFIt_-YIh^QK zWG1iys&43ZK*zu7Oyl)FfS~^Ex!QSxyqA2O=Je04$wUcEV@q|fV78^Ka3U~aU?^J9 zdwMwG<5s7m=)F$bkPN-o`v8_C?F~7YqtifOjpXJ9V=sN);=|65D*#U+hJTxQjGPX2 z3Dl8f_>Ib=NWEp$M<7*<hB;~*ECK2? z9D{u_3Dj!9pOFmII{&kXvN4C|3cQyXH1u>5`2cQ4#OxzWIxoWhxql+eS?v=04EY?* z-4#0c4mKB7aQt2ndxoByIe+ZbOz3bbI4z>E+0gk!{p94k(=Ruir9wzb7*Yg(LP zYq635Ga~uep_3s%8c8e17>`;h%ShOIFfjL2$q4yK7dhglOWh?^HDTod7?`r+v4 zKt=EQ2;c#Z0kQ$bAKrJ^-qZdRYlFKonPy0II2P~)dDFE6izj7p~ShC zOd1}B^OJZjQoN?SR)58se8UQrSI9SA5eO6m;=tB2qWtCbRFRQ~?|`a7S$RN4QcjrZ zakHiJRQI(%iXl+)co5a!3nl!FzksinSZ=OJp+(k97QNp#)gqMUL#o3`|BQQ>MZwDx zG7^4Ji$AyVSt`JMI>+Y{3@4S?6%2!3=FvbM%Yr%9$1U$6mQv{_ zy78BP^DI5bd}6ug=WDMn`51`$0 z`n|cA%WcH`?OsT58{njgxlqB*zh_YJX*_I4M8M?ohAt(63+Ky8AihymQhdC-3L9Fu z+0v8&)-pw6eSer2k9HU`o|K#%d^=QT!#-@$Ki50<-(S(crEQvV-QvOe8@>yfJ&4B} z>R|PaYVbKoAsHyw;KNYk!}6R;JNV+GbQ17(G<%hAWSFK6561WyZ5~TbH&VLIit*;0 z_HpQ>OxcxBYraX~mfH9vcB*m6AywD%lZ05X)w>cs;eUe~loPRmR(lst*D@%|M={sw zb}iH6XSQ2`j{Q)Ej@7UBDJ9i$l`7TQ*t(K)bEIqZP1UMYt7ZE(x9ph@tjk*;@LC5t zeijwMliI_yJ;_&(#ebz5&?*_7JdlGWASI|h#-T)%0;7=xKQu|9W+7fVia71fy8xN^ zV?yt%J%0eo2iAsOjDYT$Q%=r}nnMQ_8BC28z;Z?OauQ~Fr2e)0@g_a(-)(Fp(PaYzgrEvhEjG2WZR^*Hxqoe%#qF&VN-B@=gEqH4+db+fj#2;> zftv$967HzhviCGg$Hum2l#me%A$Td%*NgGDI`l%+ef|f%7IKVm9o0k zfPV!p1sTh%xpJ1xXj4wC8yXbBau8*}`3i?o^NShn9noPcjbVk?e++)~V?F>!h6|9p zC@ykeyDlw~8hJBQdMuVa*8jN##h*(qK-_Pt#?2C;$y<{=NY1=#WE`}Cw(hcXaVBH6 z?MGogwRM66t-w)j$Bi_1!3&+qM|jQ0&3|@xI;Otr?Jx@O*jGnC{GIyh?K;LYba$B4 z-B8DiH8X&9QqzF9C*2mR<5KJBX4qdsyzy}vJVlMnf^hj-10Ga!i9@WoU26X#)lZXR zYNI$I#ou5fWCI~C5*Ux*1bB>$gf9jn9lR6&s;xL;=+ZTHLzlc@)SXz19hBL8k(F9hO>!wJ}*e1GjZP~m9k^K$5Ft1&rZc`}?8vx+7Mx3)?6I2HKDXu0nn$mrw`%r!s8h#M2N+YrRelkj7enQB4c0Qfl zdPH9DV-!_a0DfpM49dk7_NiQ1s|_7S1NB2F#IhK@^t7Nx^$&+X>^`T!Vt>A8z3T4H zF57*++qGrwC!S<6Vxq6r&XZRjt}YEwV0;|XPAQ_8PH#+vvnT!gFq|63Kg&Peg~6kX zd2u(MY-Gr8pAuKwzU87z-lF$~YK+78@fg!=dng8kZk!A;_5S@-zlhNtQ^(iK?C7QP zPD5qa@6AosIg1_FRJonH2!BL|fv*J37^}og(MhKbOV7~ySTw1{4xB7d)mtj`P9Wky zOQg9vVrP<#%)C5P+CoYW(XcPAvo!3VkvVOb@8k3~-4%&{dcCg@38-bgf4F!Di4O1h zc?Xz~tE%+lnz~kNGdKU5hh)XTM0K$q0T8wi`BJ2vM$L1-&VUJ z@Is-<$BE2!M9wLKnPD#?uw*zpUnp+$5TNU_wam)*oqX&Z!dcHBz*k;}89j+E-HB@3 z;pK0o;CTyJZ!zs7a)as#AU~({?kEcf5dtF6QDUYi6SiG1Sbwi4Lwld*-vE3((rPBemr6E{Z8??o{@C_%?$SYJQFd6Ji2Y>X`b4C%?vbPUf>hdh^pK<0& zl6s=4C3}xNEM~#88pK2tuuFKeS?HY!qzT_9j0LSi*dri@E-?IYfxu8cCuyS@xM-e@ zG8e7$rc#ECt;r^4sx6c?vm4Q}g?uBZ7!HS7gq%edJ(jYl0tbKavisS1@Y|xnuk>~A z52@p2Sbz7mU=?uf4(>Vy8ZL>|ueT5ndJ7w>w=n-L&WFDQ8Uwo)yr1?4AA1Xu)Z1Hd zjED;xHoCpHK!z!PrL)OQO%!ojK1%r*^cpFZ+56NlAY2LYn%F27_ru(8;`jbC1xiP8 zg;%cX2OmwWy;2`7pLI3f#J!8t+wt7jRuD$*Er0&g6e1d{u*l+mO&b>RxuW;zqm;6r zmX~Kl#t__d*WYnY^Si{4Z zxTo@-8iUT;^gAoA!z zTYuljvz?{_62GdFC;xOIc#P z?XmHlA^|lL!~Po=3^Rf4aWvnaU4$yGJ^} z>i39Ux?7OZJxISBi8owRB}e*4`QK=;H-BlczpSyjlQRwM5^Cs;d&$^ti;dg~_{``c zyJSlt%t4^G1{ZOTsQww@pDqt9DW>iw)0NBqGpzR4`*VU!DQ(rQgQ$W%^0pZ%P$13R zlNE+){(PDjX)g)+^>dOsdJ8rRQcACsKX9Qo!2=5VkaAJb3Y;x73f6uHReJp3WPde$ z*m)eB_SaT}2VW1u;Oj?UN5R)$J^uQ^>FQTsJsg~JqpYk86pyj#7wI6Ko{T)?E3MWa zIG`G?1-_}F-;!h+j=Fbk%c~|Wy6Ko@5Rh`BqmB#q+A%B%TUqN9rl0)7X_fYz2$ z20%&-j`J(&Vm`{0d_2QU)dYdXxo3{ypE9ha(efJGawSnpSRVzda&-iguoh;mX7dt%KS zyIZg(cZ03J9|oPy>Z5~}`D^vTGr|+G$b+7N@V*rzL zn&oFP44J0v`d3a_8zD;(asVfuna`8mDxZf)Wy>P=x|e|B0wWt!(Prcp=WqU zx(I#K9g;@3Mk6(yoMxB4;sP`jdJ2(BG)-|XmM?xkR3tL9_rv^5mj>ek9|6OcCgTE7 z0V$Vv;{s6uCzr|N0w4i}m+IpJE&&Ud8RP;k0h5i>O=cP z|F50Mfm#P=>97Xlov*!MyAFah(f%?^lOY`**OztW0xbcxm!stZA}pt; zFzZvM8brxioD*2WwfZTHc@;bYqTUq|ztX4Yg)J_Nmu@`tHLj0Oorah3R(QN(dvZ0WfkqCOUoh{O5DTpyCWx9qX zg;GK+y9#rr)L#OYm*K6`-~+@K;>4ctN^Wq>w6`v$QPS$6%4ELn+TIB?NeeY%#b@)j z`Tb6Y*d4O_ZWKSMr7^g-j%bZ2(AtJ^Eq?}e!~S;W{`sU- zee?Eim6 z@e11WjVKVdj~bPBMmJITB?Z7rMr?kS6yba6I22q~iv*Ox+<)|);7o7aw5-FRX)p=C z%+|tCxZ^_YyYW1A1rEZY4%5>4$4pkAvA}`3Lj&DA7h|X~uMVG!i=>z6eOF#5Br?mAEiNMe%dw>W(PV<2XMqhrop@apIK%`gj4052CS;osi4?=ZlBjoc#3suK; zm2W%ngB5G0PwjMJ7Xzq)v_+Zjm6rA?|6MPF%II__X`vf{_0FqH4D*s!QXY(*=;A2K z3-?!P#(#~WkwkOb;vO5C8D}5OuBtatn4!gW`j`0}NcH_VfraN4LjKWC!nF3+>UBDr zjw8;hfGHkkplfy9krZQWOUavL_Mem?0Z3*rDeuRZhrI*`GR#Mf z(>NLpT55@cRhK~i3p*E&EnU%T*$7BFX_yEfbDVJYdC?23zda_rIFUYL#R5dr++IZg zt=H301y-<7T3$(XEJ-GbBPggC3j}^@b}T({R^3u>L0zkV{GyiHdqp(P-@a4V>VwD& z3V#I*;}Pi~;O>o!m#30F)>3A}IDu2;^vEpA;Xp%%WEEoXPNQ-B`wWKDXC4ra;>JZ= z(&g?pHYK!RFF-?E%AGZ2I6Hw~n1HOL2ebL7e3Q4el2X!6rrCD<(UAo;$k5{jR8>CagIXZ;L0wCOwih~~3&iVO~$`vLnWv|?IYKk!pz0pm|2s;bGrRuWN0Fn{YU zOA7WCJSO!dD6bCnvDtREB6{W<#LOd#*&IQO}A?7s|p{{TWIQq=zJ6X zefN(l_nKFR*Y5g#v|GwjCPBgoMu zK*Rh?a}5;3jdB`cao;zrsBR&=Il{l!>>qq{;=l70SK%-(!aNRXsT#Zjv}KX;rJF!@ zmsc4`=ifmGx~KDiddnj%a01IQ;cR4Pu}wP zIvF1Bb-dgQE>XT!qEx5d@qbc4?99@`)vwo_$2bROKJ->Ecff2_Tgng-N)IXR(<>2C zoK<`gQ2+#jtGVo2XKg*`JP10gN1e_F{omicinN~f__o{a>OL5yfVqK9mZe7L_Q_HC>sziXJ@X6r@lytRr6Q6h=@s)1dw(vbPkVPQnHB0t z2d_k&A7n8SBFGBEO9M5)6yPr#k%rt{%>f`ATd8-l3tmL;i-T|&J&%)fu5|}FyqKTI zlg-sm=Sw?4_=;&#NOqAQi4RjY86U)``4s=Y6O6#Iv#nssA#NxZU&vs!VQ7*+qag;( zc0;8u1a+8~8e=an`F|R0Os%bL<`FGu6h1uIfbj{F3ggqNdiG?6n)u%R=orKhJQd;gngp#em!(z!x;F; zx9^(x{E%7gK9KlCI=2WtgP$<}`f8`6Vmix_Iz9pM2q*2ho8cJa62q2X)WW)+P7@Al z2EyPLaG=au%Jo@7(2@mKV{ zRAavIDPKM9r+oGeboRv69sGB_Wtw6B#1A#&|9|KIPDxd9u>!qG4wO3-u*N)E@06rI z-$sG_>8$AQVGMGc5};2Xw2zwJ0BxRG)>P4XXI(v=apNNVl?_k+m*LW0F&kMl2`3yy z+MFFDeK8K4^3|wlw=u*-bA}F(MW)C+A%#*R$&K`rU|)whs}vRS+)pgIc7A{ld^`#J z6@R>KA8H8Emvl-}#<)meD3r^~3@pC8wSpwPBpRj#GHV8GMy41a6AT^>{xQw*Od61; zDJ(f01%!_iI>gb`xNI13I*-DkI*HBzJ1N4&Ee*dGjESaQ@{3a-Nt_IIM=5+M2m26n zo3tpz1SuwYj+he4rb60@kVpesuqY^k*?;ub1B#R(r}kZl1ZAuPJQSoSlk@sLU=RnY zf%x@#*#d~ni$Z1=wE3%4DTX>S=5Tn>l3U10FcSWhpCuP(Ar z2Ryp(F3oHgScUexAmt64OH`g#|}58dP5f@$r!kAmJ?uo&o0De}$t77kY5=nt)jANn0fyi5)q?x0SvjVXdDuEIe%KnA$=UL{0^DSs#x8l%GNc$u5|cSePq!Dx9B5ys+wGAhekv$Onx43@yxaflPy z-I!w)0k4T~%Cm_U8CVMdi8LDu;HE-XDc>X%b)>oA!j`3@TySeyegfZ8uooy32C`Ma zQLdFVBFNO&YL~Hh=23Z=oRXUc4(GcD`9`kTE$${jzZ2C9>wnZ5X3RZEyX?y|>Ap;& zEBP)!;2U!!T`xH@T%A=UY;1{^3I_vqTv}j6A5&(JA-6CQ+v*u@6GV7A#Uy$pruV^H z>T5tWho4NraLkyW6mP({WB~X(>3)z}Sta{jRKS+G5$iZbnI|Sq;MoyoX$Nh%gy!G_ z(QVa?I=_{MoqxJpGvbu*ORo^HiMCPVPolH%BBqp2`9c@)#RbQ{MLZglB-KWU%>W0+ zBSLI-JQH5nm4IKCAbCgO4K>y(H9S$th22}6SD0>_RODd&P5GHQNm1g_nhjwqK^^mK zlxkzS%VWDoN@Z>erlT@xUdS$zdnCmVt#&$oe`<-CN`EuJ?fE(bwbp4rbQ+`2bG15@ zS$pWc&?#dTBQ95ItE!x#;NyqwwNk-(N*Ahpz1ChYRWZsGH(BYUqcYJfKK!a&!cmXt z9S_O{96bmH9zO2a=O4W}m~|M`Ohb7C>HmG0F+~sCoz|=&U&Tn?X80brSG^w3dm*if zxs!a$34go&8|QuF+T-@>ZQl6!Vf&GW?B@Tyb7rd!)BBwpis#coAJ0DB!z>G#;sWt> z2)P0XY@+T$g-2w~anc`6g^Yqxu}RqxJ*Re8AFGrd!r|x=Rt25C$e3|V)N=xb$*)}o z|IdI9tsq1d=F=)`lQ z>&X>e(QZbf$&@dvQg&9{@ds>>hz17v(m3Xwc6=z}N+a63UV3-=$Y6TU8g|ar01=O{ z41cWizcA0AOT>u@P9kdVHtW}4xbmWsnRu}{%cA>g(yn1W3`IJr*@Mm{VpHja38WIC zAH4-}k5e51a7-1$OnTI4>4i*#Wg|M?{HqUe?6Vc%4g4QB=5+#anUPJg?J zpe$3~)pKVF>H8D+#&KM-DKzgQ_-%7C61B}aqf}|Z86EG%^9Ij5N2*Lo>e%b`F*|gu zwPL~%`LIR0yt4+`w`^podaj#d)*>)`-9TIIr1bM3CWft(E48|Y%RHjP^x?`l%#2|y z0Y)kZ7$F%6*epvdg{IG@H^TX5E`RypCWRp`&-M1H2$)@scIs@#4E0RRfxB@DYLqpj z@~)e?AMsi@Ke8{$kv_1RO_IdRH&uQa11eJ(%ID3rd*{M7=bijeeWWW0P-_r#Fg$ZV zq{Uz-;fN7)dkf#FlPn6)-8+S8>#=TYKN^5$HBiqWy}ah~bnJ6d&Ta8gM}JzRej)T= zmc*-TM!O`@z-!o2rIoJb`f{Oy#jY0T=e-5zN+d$k*U>68?{$RkDxj6M!E@yksymFT zUSx~VlIfLMVmGKEF5<933-Ae?PM`mPu4NmD$k+wq)FcCzm!(5!>~1wT95#g6JOzY4 zZ2*gP@}%1o9GZS9O+w%nI)6YRxm?;05R7F|8#I{i&EVk@LGmEVnk}E1faJ(&7DX#X zMgcso9_z5BIV_SEfzhF=^rygpqc1O84m{?2^C|F_mxToi8U5-Eu**1-3$WZUK0S01 z;gIy%7JT}+BsGzZ98!cIDs+^ZP)@(nazZ)lS%3vKcyB*q>E|;nvVTi}=nxU!&IFo2 zu28^;b9)AUK5u{l#O6i|Cuw#xGSOx1VNFCE@){+r19D_M%4>E`QO~UsK zy8jv*r93Z{f#u~9`>MrlY*sKRaA`LX=zWz)kIiUyKzSuBFMpT(Vf6%it`};Or4)>w z3@roTPcRFPr=ubU2%*z|JDm}@YFo97fL|Kth7E8A*PUv3YvEl0ZG!q&BPUdG;PH#NheAvWy5IgFGxN107vA zP&0T`kwnWSz0N1`Iq~@#^4`(~g{>6WvT<@Me6RIh-$&G=%a9U89F}D!7IvsSLSJ5S zETP{2Eo#AXf-EmTDv^Q+=L5mz3O%xWAF6)%tN{i@YJbiL6oq*kv1{*B#1|4>R$`Ta zylcKE9*?5|&Kf#(i5rsQ6BET;Zh?t#!gR^)*$i7{>tip388WAI5Zb%|bt6$V1nsz1 zl(elryp)@O8(j3w+gOs-I1V_o1c#It!yG4cGoIppE3$1o&*&uq=_Kzgo z(o@1GHj?pFp^^;^HSTckWFRAJ2C|94p>_ z#DA?dK8Xg{VjN3Hu|l}siR%#@^LZq4Uusd({Q?WrI)n3Z(h7S=35yN5cun>1fN5akf5BIT&QHZe|~fKsKD34#;ZmGo_H zN;{=D#CiM4sU5cdr>3zupX@uDxoIbBNz@^r#z?MJ4L^!}Ai*w3*xD@;61bAYa(_AH zOC5xNkc*ZjZDozu_JflS6iM5bq#V#+keyx+;DW@vcmLbg{=xHIetK88=BH1JY;-t% z=>YMRyt@4z`uc>~SfpOF*2g=meIK9oiD^hTL^4zokIX2n-g*?u+s_{eA;oh?;>F9O zU6HJk8kEnZE`s2gK`C0pC1leIY<~zMi4nx4CIdDEl={0NupUpmLGzsK!1JWQbV{eq(@(sUM=zWIxJD8Y8Gc zXS?Xj^L#ni>@DDZ^cq1y5pPzlPJev6c=`{kA7=;Be^~pt z^yTqy5lO$Gg437n{{k3)$>3FPq*aZ!rGi&k3=FEcy>&vA*b#mRuM7!9nkbHSSZ0;y#xe4%JzIwJ6KMy`8csRC_zr zMbC@30TS_s>zhM0*E`p2fjpdCV*3YMHy}j(&O~5Ut@>U_>O2N6_YXr>r{BWe*gi|s zJgVA7?yV1fdVzaUwRrj=VlF4S*oI!e-0E;d+kWSVZ?_l1M zVT_z7x!OK>1@ez^njyI=8DLkOtG$<=0m~p?2xBqP`u0J8w90z?$rN#9k}t;IUNlv9 zeH39ay$N-rG$IyW@AW5_Pe+J_lj^P= z4{@0JS^EF6_paMSps;lxR}2oh|y9sH(*(geag4 zph!_>_UK=K`vLa;yU(Na=y%Br^ede4%{kW%K;027Tu z7}1ZNF$f$XZZ;Epp2own7AX9iL)PlzoTs@l%iZJ+rdYJ$;oLejNeWnQk5>=bObRnw z#aI7)b13n*BpSKJqIAey$ZGWPhH%p~H_)CW2)RGUlAq?e6HcbpEY<`7SU{)0rIntj z-96PZpyaa}f9w`gIL#p_9NFt^8RW<_7yGRwaz&COZxz{lI%~e#h=nt{a3O*{sMYwL zirbq>$Z)5pA}Wi(BM!0ai2HNz*+2L6&YM3KEhw3veYPA#=J(wIx1ZPlp4|zDx{66z zXEA#?1Zk!9E(=rXAn_1UPe-H zx7=teG3$j`Katu{LDXc?X zP)g0Nf7z9EImWQGHfGN9_DisktxI;uEG;TS?DDA@9dDpJZm2q@w=TYG&G{v}VN(;B zAUhpi*|&?cT~#IP$!ev@PQXybFf<;=3Y$(~N=^4qPv+A?jPLC!b2>Gd3cB7&HFrzZ znGgMbE4w1#xF4A2uGf1YtQyAS^UZ~w~XUI%GNch10|zuBNeJ({WrGHvOfiii2> ze;xJPkN*;VJdQpdy!!ady^jy~K0f&$n_e+G8`KL~kb}a^UdE|9dbRtd_dXsD3q9od zkr_~jQ1DL2Er%SjY48I=zIr&S|~f6equI#0c5xU>Bs*&6R3?h{&6$c@MN*cEI- zurc9h@RQ{v?pri}Ia0Q_+Zr3LQPWxrWn_*IjL;Vd|4Wym&oSE@yAPOBaf+8kGE6c) zM=rW({Nkr3HaN-v8q0N6dX5%MRfScC+@G}Vfn_ZahvZLe<#U1 z%KW`gk6)L1AZr{xI;J#|ZEdP;TRa7;LcVf39>+!UPBfzXmqTu~DBD+T@vcfz?PutyPam30hwC|>l)VCHCp7r|P5(!6^%mVl%=I^j^@tTzVJ z@()`G&pC7}8rE11Nv1X+I*tc$f89IL{Tw(9a2+S%Zv7<^KDutcr^NLSo9#3F4c+K? zX0a~ZjG8arOnwumwHY*tFmuS>n6VD^EI66#pF+Rb9$RF1dzKr0-I!aO_?yGF^o?7H zb4g5frTP=_UPrn(Uum|<7tU?nBQ~1N;qS=`#3?AaOYpI>NvL>9NAm7We}Y_4!XIcm z@{+LAq#jSE`6qa5?a|qBK!y2aFdKmYwJD@Eq zh}(8^eXyt6?OrJ{qQz7f3|`ATsEj#IGelT1+okr z0W%~KaQ%aSh5)X1IkA6KmY36b)7) zmMs+v_BOF=f6Qkuj%=1!;}|~RcTXmHbpuE4qaw)xN=pHlW`Hi#g5XGCH8C{ZQyd#i zMW3rD_vlxWDG4pw2!K?Z;s`>>mY|X*%;F0AT`jm0L=a}PA|2(#93w#x*N-tN_lEakyBgriWKg% zt(d33H^n@C;EH)>i!nZYi^_S1a_*s=XDH{M0D#+ah_e$GOYKWEc>9t#6yX7>)Ity7 z2zjGkf1X#+yL(I&GlirLVcj7H!_*Uf?&>7#D(B@oZ1ifLN&2j7mpgs zVtjdwH0tQnPpREiu5?D>>zR{i4h!5IylIF6-9=a{i4~e>slRR2OvgBk~jc(-<+j>+myLSE2z? zfntDnFvae2`e``Gi-y{Y`VVFq2smwU;9+cB<=)J+ELg_kNEo@uaB|ybHNm>ZluSD$ z@=D$`or#IVq!9qr%*?);LDJn}x6`08i0H}HmH{-cbvfjakD0R3!pK{{>o!WlzINXn ze_}_7$1m1EV1c#w%PBUks+&q-h|ix}1N#12!e5aNbqSrLzpochz6hDMJAlgy%A)p_ z%H$!)?jyp>LM*#-V94?w=UBn#d2z1E@v6C!Yo-*fc2#Ywn$(T0c{cXHeEn#XF4o4A zJuk?K-CCmT)y*|7$GFR0sVJh$nxVg*f8H-*uUlyKT69=HanZ!U?=1Z3Ew5) zEXqYLFCkR#@>gGRb)(L_{AU(3{ZPl5z@0T2oG>H|6(W8Afj##LaQn;GkAh(lr~WYg z<22EL<7!FIpCtY9mrtMn@aQiuPbe1oUtXS2(qlbPUrHDhb$0Un=}9xq$?KD+f06)V zJPFW3wShaC#AI5?{_i{zUd)51eCm@t#lMIeYH62kIEtmN$j5guC9y}LvEXkN0a6_% zRU*pGnc*NC0=*g9MNiJeqae&AK^R;aNOzLB01ao7=GSWfaGzgEc)z395ecQ}NC>1+ zPEN_gZL9=XRnLC?j0SL{4&!SDe>-z^rS(PX*$^Ob#$=MRy*Sn3Y3*yWA!`gk)xF4l zIF^XPT+9fNxKTvlYLI7liHC!^Br<`=IfunQ#hX`;^Sl^P>~uN!CKHukWiaxzSTcMo zkgzfwwAg8SVOt&-7{o_KqL~RHT{kf7N1Dv|Woe87v7`|RM%&SGjIhu(f2j_*FW~`A zwKtDzp@07=4@CnD>!0)%Qj$;*;3Vd_!kofiPF&3zVucu}N|bIvvcB}o<{Yo=$J z<=z-4GCysbnJ&p_trW4DX@=Sx(%RsQpHt@Tn?rS@YGKsDURFiYo1zI`H8tBUzxi{W z6pnr4+tL`3$f#^C!zLQ;e@Fg}$WXmDoFBQ{6i|Z7(X_(CivruwsLpV*nYvFIR&i)x z;hGq;Y+sJIFUN_LQ*&83_y=&wp36pUL9O05T>>96iPLf$jR&xhj5OCj)YTo9AU9zrOz$&*#AS8{8QSqYHrie`$CiaP3i*f9L5%Qh8njcRW7; zBxDc#3xLOn@V`gVZU;=haQaS5U8uOcC{^6U@pXE~i!{qRe|aI*@w>0Ser|mF(t`({>y2PUc+RU-{4|VDkCB0cQWhY%es3~_|=b%JD_8ip&;>%R}=v!JbgP! z^FkN$;mLQZpW-@3e=q1fybi+bg0&Z4W`B&KkO<~QsXG{(5>X4jZ%nXtC%Hot@wnBi zBb?EiKgW6&KhP|mX2NCesl$U;r&*w-+pD{AA3i=ZJh$_IdHnnUS1B)C7n@DWC_+GdClw{{cY{Tz(Yea6P>Q!7`s3M=@ z?toX%0cT?Yf5V(k3o2rL36xBkiV7Klm=|ZPu|!n1L$H-ZES-z z3}%08i%`B$s`QkE<^pgES+B%-C-;?Wnw_n!EC*I!tomu30Lv+6jLAYzau?DfO#q#g zsx#To+ud&WtfS7(^ZvAyKj06ABG0-PKc*C73Mf_je=T+U?BuJ1=g*z-zxqsQpn zB<^3tL%PsGCfv^_;C0W+qQ70~F_sGsQe0;u>QK48wFO--3dEqsr4Bxy(d4~LKzPs* z@o7U8J-IFw`l=AHG8r4zK%z>ff#vq2X_5{iS<(!_gJOd;N7Qm1q}pUmKnUgOqG=~1 zoVd6Yf7m_fFKH;Ea9q{j|JVNxbfSa2Uq<7Sn2~KirDS%qFh8qH#~JW zoz}r~i6V27MSv;PWTsEmK|vlvP!TbeGj$ood0bU7uA+*_9G$8TzKOK37#q%onfwD0 zgy{qbTga8=SE(KhwK`$pE#uJiM|zC&b|3%&QCVH5+CnIHxosj@hzTwYgmLB&L>`Ug zf6*|D6<@dcYugvI*}Vao42yVxL3y7Vr(8-?-3gdV(A;F@dGFPLxijp#-zog6je?^kIvIrePJvxAVjU)J)hLFKV)JwMMOKp1W z$3DX$h&u}v`Klmu$#RtEM8vn1E{YsMR=r;8bh2HA3F|8WNjPV%xeVrj;fym##%j$X zBNOjuWKvQwzxDBS;Au!V+aGLag7^55WJA0&ZL8hDxRE|#BUW`DTGmZaABN`<$#iQCf58XBoNak8 zB;B;>RS{<;0vp=~c^GXLW4I$|`*IO6F!^P3W;u@YW6@x8{U;YwiY`xoconj`f%eH` zS&5TEpC@l|xyE#zz5M|}?SR-vTTSV#Nctmz79i+HkwhnE%^NN8+1nqE>k-en0j_@r z3Ed0{w-4q9=FMhTJ!4pWe>4xFEE3=s5`x#typ6diu{c)0)qRSqz+%?d9O?j^m0aGo zwm2rs$=A=3z(h>-Ko}r!-!tfFgnqyzLZbJnGm_0$XY8&{GI@TZHXhx3w5bplC@zw` zROgWRnM(m*Ts;F`-KNu%9c@Ix>({|C9mbRKMzBf*o7pQ5#O-1g+I31A9LaBQ{WJ=@(kZVOf+A6 z#tC=<#zKv=JR@r|f4cA0Ea{N?`pDj=)S;MD@FKt6&(3KcV z3S7Q8REmxQXvh>ygv~)U<2w^pkda%Q#e)Iu#W;P2lFt5Mjn9KI;NH_QHTwb(6XZEs zAZI3z?JD7#-w;fD#3V`&NSFea^ZSiCH^>=zaAZEhvCiX5f5ecKyp8|{heZnCGsaRR zY6UAVrl`E<_I+h4=P~7i*@{JZEnqu_LGe$ zX^Eg@A#E}Sf1Q&15$FgP2Vul#cGZq=l}}7$nlkEf0~WS+Rwf?fiF#pS)i@0XmeLRd zXi<0pN@S#At~J)6gCZEM)TY^4UCXSWI0s0QmN|~HwJBs`lYztQzOtzQYz_T*7w~v>a zz(uf>6+caYpFxqZJYSGuY7IM2U`dd~X*5c75f}Z@_0sK|k$2PHQc~;t(YvLVMk~Wq8SvX=|pEd-l~cb&(Ah<5GU#Nl53!u9L;)yS7GC-`~pyR zO=8X&UG3w1pi?2R7PEetcFfG!7${1~wd?b9L~{e8z95^ieYjVGYZ~<-V*PO-Ia<`T znHd{R<6+{+qs&;KS?<(B!?~e=p(iDmw^8COe;>!`bu`eGd|hgfv}U7uq!$#)2u37~ z$<85B@tXQ z989Ys$kc~mVrY%_ru_@;j#-n)1c!_$#>UbuY-U3XzvciIhzK=-n*awSrFNMN%$~`( zf9XpGPV*)f+<8By@EW|%mz&tuY-o~1GF9hOQrI!&V3@waP}3cNoT<_{BV$Qp6GuVM zOe{kxT8;7|dFSR>cnLP+h$O~o73r2fk{>?@5oK`eNe>x~(ujlJ`TUza9j>>*sEOWbHdqw9^j5=cbE3ho8!^||?3bfY8R}r-3fe?I z3uka?X@mMWvDVUhiB>Ky0j;IjWfF&)e3qCfc!uU}!Pf%9;4h0P$p-rEa+IMxe;>I@ zO?%N5;Ae?93T&?qkd7r4#tpa)kCcT^Vk}@UUU9!4dFNVm2_e1d-QtVa!t8Vw>_2`S z9G;NiPs?B!i}(tsZwsr(xK?10Eis#^pqfv}W@dA@+j^uQs@!qSM!7~PyI&n0_}3k8 zMOB`JcB$*moV>wx$C9a95DqW)f2z5XC1lX;H!w%kvDMqwp3OBY%QLV25P%9#rGh-t zkY%-gbDOnnA+-2hfV?^SNIFSfJbHijsl*7Uf8!eDt|(F5?@x=kf4$^xpPQ3-JmMtb zc~Y@uu(k4Op_%QsUMJFsrkPZzLHQuSSk%BpnFB&uyE|CRes_b@z=?AjfBCR&6|sJ| zX;?kyyjI0!nfHkSG4Q_P2PVNk<4cGvgIgDh2b0FJf$9E|5@Wb{ahN&2z zjPl*IO|0Ilc&IM)wRgJkAx5XgM8hz9Ii{jL7o98=^|f{f6aYFGyA>mdfND&}^}u-T z7MjAQ2B#lt81^E#1nDK^e-(`^G?QL1O{zSDc7W;g7muRwOyIOpmFNOo2ydEYn8dj` z8_mElnYxvqnr`@HuSg}y6($%LC$WnLI*peUm9*uuLK3n!btx335MF>}9VV6(IqBu3 zzqX1u(>Ss(=TOIyjoZAiaWiuXyW%PMB#d%DCK|xa!`LNRzw(k1e?lTq5P7+i!sK9< z4I{p@VUGw);4M||wc1vSqNwaNO)IVMM%igZ9D;tofF-B30~y5SsF%mZfH9I;A!cQcJF?TLf%I=XNn^nYiMB5^35+`_-_w%&Fy0LLw70KI9;BHk+Q}`|e zVmuxg4I6BrX?t^!xveeBtt=j^RUL0 z&}!=Lf8tp=e|r7^tdea}rxv=e6ZmfOswFWED>#do;s8@*Qa1S%{i@NIvO-h<`yp{tHrrE0#|?u#QuKOYPIo~N0G=-udYd7!DoEz5GQjaaZk=cdGB zwNX5(oNwh&TzEbMR;}HFjYU!`lqDh)@PfW5p1109f9(&g&KC6{Oif28+qn^Fh>Or* zt=^mn+(K3{48`_9Uy`9dTmOjVsGUI*BP1SXIV8fWth9g7x|8uaOs&Hc18H88Odd{) zHf4~8c8H9(@x2dyXu7gO_SBmex3u{_YvgPp(TNZthu8l0rggBFs*DrhEl(+vy*_h+ z6}p!wf4pHnCXbL>OJva`K!?I$;aVU&*KF3=Rn5zVy1&40tav}6X+dHXv_$Gq+Y{M7BmTfs5oo>l{nB_e~#4DmKO0|VZ9a!1eWWHD`9(nVJy?zxi;q_B+0Q zYxzazcg4%f>@sVsoL8^6;;hQ62lXHf_ec(Z%M~XP;IAW78iyoWvJWQr_UvK;EnWL6 ze>1AERV(%Kk>bs0)JO`#H!p)mqTX2T+p4wr8Oc7(s_}%nIYr>AMTc31SvPM?yM0~V zs!b2`QtQ1}QUgMRM*ua?$4S3jwT?z^CM+--HZQ%!D>@G?ewW68o$trDJ?^E<+mcL^ z-~O0IE^Xu6mocng5>lftJyW*oT3#Xof8Hz4Rh8>PZm{m!e^)x> zrF=h|SG;{KwpO?{nIn>@f%SY}tv7x?zc=>1R4~Nw5%$h%6$JUb3eXGp&Crq(@p#*W zQ}Zhc^7)n6_m;DR(@k9eRkg+s{^ynWqF(M3%9u)!N9*I!t3~ zZq02?FCmCy8cJpj$s`4PvT9Fff0n|%b)S{@*}F%AG+d%gm(&$%Ub7HysauifRX3+0u@EJqHULjq%MN2++WbX zP-(kLeJ+bJu(Mj&7QV>HbIVn#@H3fPHVK7i)spE7q;1i5u2mD{LOn0+irf~vNrO&N%P@SHTkK{v5i9Qdvo>3z62R9ZQ&z za%HI!{nUKx(;1WR4dbSaJFg9z2@gBrIyyDi8gqb>mOYIxG}%V*f31=<70KnI3yNvg z!Xm7U4T+4FTKS0@YmQ*D-fO{;_G6{hMo#-Pa(nBIL9D{XW`R4Fti`5xYTKZAk$zZk zjwOqA8R-5j8k%Oo9-7FKC3`uH`NgB8uP4fU2qn;FVX^i3^26fiG4)twA}w_OYSinb zG$lYTLYlp7(KuRNe>)D85^fiMvh7zl`Jw6Vm1{#LslLdT2t-?l5;ePqG`0J2e z0{g2vuE*r`3=?iqZ;(5z+kI-(S?Fs0&`QOf1N*5is`oqsVk%>`LxA&a&n&?g zT+qh`-(g2RC}Wk%XBQF9Vb~5kbWE7R0hASo(!7n7F9)jga?S3c!pKy(?XnV+8MH>p zM?)nAJ$euse>3h|)Yn!BQA+b($$P2Xja1;~ptE6;-Bu{N(i#iAFu2;f&cCH)^@T>r zP~_3E?6|enTQ7wMj?k#&U1M20i^f}5I-{^~b-Pcd2?S06;Q3qE>y<#2nZHRqp0|v- zuc*C!e_j5@+{!1b9^h#6btvrHPw(skX{P0K6IF=$f5Zkx*zH=;EQfAHHK;P7-SLmN zu7~pyiDrXga&Raw*i4MH`yQP%hK;v2I9+~GSj4t)C0Nr+vkKa__-YlHEJ5)CFK0Hg z#f)2_Tt8dO<=a+e)77pTaARMs##+vxL-y7IISE$;#JXs#qy8w*OTAiEjl66pmrfK+ z8|kHrf9td5Ti!1tD{UFlAg8qxF(T5S8mKP=_q`R@T}$?MO=wW7QOUkX&9jP_q2Udx zUs9jdsI#HZ`obx(f(qzrx11$WqmoA67E_|2GOLwZtsXyHsKKg>vtgmy%kzu(WSg%{ zF{^RTHrw{Ray;5$zc*NDb1b_eR%}6g3E`3Nf2t2`HI`rEuDX_`9USr|;7t4&gJJ5S}sTOSG*8M^`^~fFd9?oideJ2lfCG(8}S&DP3_RJ`V zf0bpG_%@+cPgzoAG)h+=rurELvAXGMR`nD#>BBT&W>Kt-!p9knfHdh+f0$OxE{knY z>FbPk#Djrk6qUrJNV0x1S)eDK)s(r#k&W75AWadd*dvo5u=z6zl=s|xRx@+!ZHLTG z!BgLG&4$k2YN85)Cg@g;m{n4^**q}Ye?|*f`}Cfb+d{&6CA@UAO4e>cx%J)^2SwGZ z=Z_R?yxs@{FY|u&yHdicWgUCV*O%J9=K}WiUbkJs4Fy_l5w|tBU6UpwF`D*n)rOWr zoTAM+!Zzmbw)NFZ2V-w}mBA*mP4b*Y%|QWqsxDkPf0H5y ztO7y6uimox$bDgQb^;ta&uHqO**F!Qm-kgt@0Cm^LDniKlmWK z+89vWc4N=5$Ea=ZdYfmTP*Q-n9NxAybIJ=hpft?rG3|ANBs^rA$)T@rImjeET15^| z!4+z`ti&l4yGzTKFV#UJeu=aqE8`3e?3qdd#Do# z#+)c*Gb50Z_~4DlaNNrKccEp_W>?9P1=OSv5+FaH>C4|~c*qBy&K>e6_c~+!x&?Mt z*)GEkI>{~~_Wg(Jym39{&?y3e>yV|y8~a-hRA?i17JO?5vlHriB=qR4ybv}g> zg(Dg6`CMG5rUvMQog}Dve}SS60vC1y!yX1kanT1mCeWyRF)L7^Z9pwZVW$nIg#xgJ zk^MM0aG?ngsZ6B*QG0AbJy08fSpl+oc1EE}8-WQClOD@~VEic9K{_2K87H0>fG`ev z;zv=;BIO5Ou)0%6cRnE7Y5_#8}# zT;L69kQZ13^G~wgCvio?tFr<9l-1Q9J%hk_7RSw4rR>%y7iWv2TztH!j#;rO&Me$# zJt_rCd_iFY7Zf`?yu{g}@DeLm(To~#HZN+#(v>U|2SR9^e;@V1h5(TKOVu?ij>FmF zI1URYc|imQd(yRqU8qM{fPKdjotYgk;jArQLM>dvHfr^`s6{<&#y>b~kAGk>9U0-D zqt+}gd}dICv*m&sEUsZ@Y=TA&l(L)=hhV9t&>Cm}^_>A0thm*+%u=sY2Z z*ULB!Drg0~e`f-0f$k0Zt~vHio+HAqY%O~}GQDGne8?<{siuI?xsaAG7wJ?TA8el- zwZp_Os9;W@RSQTR;833&19W;B8a@Y5+EGGoxr2^gmdv&zLc4O?5uleUe(9jFHAb=( z&)Gw6Cb1zXuM09j0&pX4JdoRVq5H{1w?{#Ckb?=re|KS17%DFqYk!ySr33waeoRz#rv13*+Llr<1uZ)LPP)o&s1Wg2~@gC zS9Z1_H&*2id<5l4TtmK?Mbi_(FA@yesv(>J>(LH%obLYKCykpK;hb2!KbEQX!;qa<7SE-ir_y;iiyBUqoV+raGs>8fe~c`Q$YYUJ~P{Odr3A;ZGgTufB>xs9v4Kq znY7B^&4zC4od8t+EZDBd7n2JVT{v(9w!~$bf06b@(tEh`IN?*rjJw+44YKX_$2M() zO%J2BJ`0_OztX}8$n)h#oO18>V5n?&zfQJ$ZJ}-1RB9u73x!=qVhPyac>xYid`auJ;*5Y(awQfOeaG37X zJ2p=D>7C8)%-FqzxaG(0wNZP!r`a8=VEJ2TzRt#*)3LfaoL{2((T;8iIzFz5gdFt3XIb?2aK{j{;3rj?D!Q>+k>efA={ooDaKhXZufo|F{27k`eL{w|bzanSMK= z*evNaI*m4@h;w$XuPBx_dT^!ne}!MdlVqT-G)MM8Brh33+hat^3o18)!w*vJp=pQue;B-;;Pa`<}Not^md9+GC(&5A}5ues9lhtb1YVGDkR#KAB7!J zwau!zzk@$N9hX=Ne_%{$w`KZD0-8`YUumE+G>Zz>sWe4wh|~0%Y--M@Db-2? z9+WNxXFA4;gFgLj>mVLXYy4O#ZIG%EYQ9sBu4Fw#cuLVfLQj^^i}i6wz^L zOT?-Nv>jb=&FM8CH^GQM!0yI^hW;nq;Lw*jDn;XOb+tf5H|NzAFR^3{$WN?5GvHov zG<;B$0mnYk>44U0r43c}6|($d+7ls$d&j2F?(a5@oFw%0f4RXM(hy2!^1hQ7Vs`lS zZH&R+lhHH?RAx-9h>SQ}3O#e0rJ9(07P+ae7#4-Wt>FP@BOl`P=yIoTh<>WO1KdwL-t3Jb*jo{rT*up3AHNK&^{Cp5! zZ!{|1>?m&*e^5tWVC_iexa@aob%9N_JbpNS!7cc|&F}?l_B}_i#tr#VTf!r3(O~XA z_@^Aqmdy=2D7UfQU)aMdkGA2t%6RO~DUdZjrCLvm1a>+Z$TIwi*#OBSN;ud8x)QPn z5BJpLG%icS<6G8(D?iQ1!a`VC+?VFE3Zzt{pj>+3e-UQ8#~_RGYb$g)O_|zmZJpp$ z-`mmEHS-+# zBnRS~t!Lfot`-H_Jd=XER z3yp{jI!1^A=$a~BObT5EWr{6~Rb-J6g!Yr{e~G7Z0d~O~=yrh_rDz6vpwf7n^+z2w zPKHJmQ1;_gNBOj(Wy0(ubleUZjZ1&&T~?E_oYICUrWq||(^-^U)^rUpW91lg{Zz*p zF0QmWV25o5@mTRih9ccXo;Y=6AI7-&#FZMyxZ4lNmQ&O_63~!u$Ow|DD+Zb~t@gaQ ze{-^>hcg^6b1TiT8@fuEGfgt1i?7_FWrafK1}YcOm(yx8C56y9w!G=ji0GSgA1e<4F8eLEzgOlEnw?sffYdMgeZ| z1ey6YNh-}bXH`utD=f(Stq>Y!DnSBqD5{v)BrOpvLKn}VX4%TbSXi;HNItDw(SxqC zBv?39%&RADBr(UI>}z{6nzNaOe+Q`J%3B&$G(}|U2JcJ>+oHBZ#GW`}zxhBGWU^#ak^ihZk zorF%3>@%CleN3#OJuXzJv!z16*P#<+<2o%BdtoKZIT;<9knZHka{jH)=IC!#Sbf zCByuN#G*wm!R8--owC%8j^1Jn!l2)R5$%$l{v(hS1)AbX$X2KS7>0HRO1kvd>6rE; zw?s%h+VDU+Q@2wOjtN_Vf4hG)IV(d->(`iAWpPpD-r6dmap{ta!D^znK&C~qs)kTa z7E|{$`(0N(3B*{WIuR9u2(cWa;hinr)9jP3dIk6t-b7A9>E}RckE$;$$B8^juHt%nJ(t~m^kaN>v%3-Y=Ju}h|ucGwF zr>UE)d*m=7V3Hk-)m6@y4H%M%UIKi+jERZ=#o`T!W#sI1eKuYfMlkLv=2jVfT)lY$ zoQ1Q>a`FZg3pD6{e@GKzc5R!|^7M{5nZ%M?L{1W0ec$lp_~Q{w3y_5zqsF?0y0C8C zq!YDcpl#$XQ3nkFmH-}=ysIW)MlSWAOaZ2CVw7$CYG8%wy`q+zEH;!|-N3u-KzNsv z8<7~}w&*^koUiotRbC+UxvYYYw}3hnv36Q^)Fli`ys5QIe;NIRTIN!B8l%+i`$va6 z9f6oL=pmi?3`#RW7WqCQ-k907;hMnN!3xwV_S)<`=i41sIXZ^r8(+prN>-fy#t`iR z2bikc70s>JnO;G`rc-GBX=$c#c@x1YddES^`Ob%8TwrS>j8O4#Sm3;23samm#M8=I zInyO3&(dq(e*vb*ucB06>NN0yiAfIFtYVN8x5C;zYPv!7bXJ9q@APbue9_ZmhI2%2 z);8L!0Lci*B5NF1{gE)nrV6nz4aH2t2plME|)KTX! z79`Dnf0chI!Aa}%7;$ae^x)E?V`lM~b)?2q!|9ewETbn0GqJ4rngE?SNNPev$%+Zh zG`4L*wz*&{l4UtPwvBE-)vWJ>V=G%-nA~QFNOWjdpu`TZ-{}_nEO|@Y9A*MR5FBTI zRkq;wpoQ)RW67a!RN;|D@jREkAaXF75^D%;f2=v{7A^WfmDV$&1KV6UncOMoM{gwfmmJn!=2q9LL?vL1_%I9EWL1+B)%h64{tuRnAFiYs=d87zrR*z^N;^AriKZFX+avv7oGbxU!-qGQlHnkz~I4GQjp<8y^PqieAwD*@nJW~ zc|-WJ*kw4DDi5U&!~~|PF>eNhe+-}MD#^r7bPUOZh`lWhZrMb>Ig6N#P>VKT+w$qo zV6$o55+ox_mnBVIK9{^y&aAnYdTwL*LgQX<;3|e#T)-mJ76b<)KA=9W&i=HOX|zxtQ zB@g3DF3;#XiG+n!OLaD^Mx}J4Bjy1VrwB-4Y@8d5ph4L7#HgH&rx6>xHB9h=o1Rs_ zI&Hvd_8i9Q=Q-@>>E2}kS*%sR&6THV3>9ojK`)wC%poh^$X}9`e;;LRT06^Cj!sYp z0jillJAOPg1VGYR)@uG8%XyHk%)e9nzyu?Bl6WQHe#N)T-n3G2&%7sg04GS@>g`F$ z4-|P`vCoe&gmfax;LbQ0P+fdKvzND;de_?kZI?G<-dilp8;O=NIj4!0ddZx^st~L= zv?kS@b7}hf|N7sve=be*snKfhkZ2XNG~6L3$z@(S(^r<*!(5DSP&}~J2;vBHru%kx z`-4!uM!a519%2yauq?wIMz#ALEZ7PoMzn6^Fcv655qWYyyzJ6n9B$XZ@X#o`okF@* z$Qjzlb;yzRA1uR!qf+exU1;#srIk>IQ}_El!fRlCpD(M(e*kkCll=oEX(SLlG3Tx9 z9zO^FjdMNRXl({7zC0*QX{{6?`MJ!K0b0yipsur4H4f|rMqj>stQ_Ujbf88sX~?AA zs~Z$j&#vOqh|a0m=K3P%muq(>G@qrYatopyzI`68wM?XV=dG5#pzk#kA+|H}Ec(8L zw2CF7p$6fGf4mka7Q;s1wY)Q)EGH~Cc%we{docseImBiRff{Rnx+d(a8}*y-I^TWw zow`xKb-%v*?qlU8d*mnc+Oo>M~bM^+a3?Et)^s?tkxXWTnHbd4|I0Ogz1nn}cqiOu_x)c}79-Xk}n|B<#YY&mB zpW$STe+S};M>b*}MzVhjvXZQJ209l6T;<4|5r;_qNJ?Q6o@c)bl^>?y6VEu)tStLt zj|>s{1Y+6`)?TdGoJFX^5g|K6PS1=5sX=u-F3s`8-aO0@0adzw*|=}=H;ij)i_t3d zq&WkvfqqnT1$)r7XRgs*8ovQ7Eab#hjIT`4e=7`mnv+bO8>~1_eSW+*yo!uBVVB9Hqco|kepp(M?XQHZnb z-q^cZZOr{HA2I?>fqNX8dDeydG_b}qECbL02e%lo3DGDnCgjx4ES1~#54+yom9e+{ zf2(V9E&~-_cpIa7Zx1l*#?nYeHMBo6BP+HuHRB|>_rppA=Zf;*}c?@=~nr zEQcrqN?=cTpKrO>_1XIx9U_`7M#Lb7(8mY`XMOdwM8x!JbWM|Hrq$f9#>rbjnKb+m z&zQOE6G&U~4y;xTf2vI03G-i$rWGv==L3^CvTo<;{vHHL3$(O6 zPtM-Z+7S@xFlthFPhovu%T$>`piYn9&{UxMb*CqGHBfYR-DB=}8SB{=kzB7*L0MU8grPNSw1SS@*lvNL!A~ z+tVp~m3`2)_?g_!cY)^*A!9Wrm@t1SHb(2udi};Z}CIxg4~O=1L$%bLip{He>JOvOpdnQHXf8 ztnb1ydFMDWv}CV&Gk9KHINb*WT0Sra6HnMSU^dUfhrC-1U8p?7A&W8u!#ZL&KMWvS zi2L3EXe)F%$usto2@Uo?f4mC>cfK~d%iy#*Z-wh{um>^)j9j(|uFdsr4ptjmm4Ptl z=K>{V=4cUE8__6Bnr5T4!2xwZ2wf!{(8eKB8pN#*|BTy3LjnvoZlSql%|ckKD;+{k z!wjC6`v6~POxm0$ofj65p2_&gLtN`vKQj+{O@J(c%ZxjSKjZ%}fAF=LVHp0Iq1kwq zkTX+_o{(cl8q>`XDfL@8yo<8c$?~NDauFm)xX4&p#=hRVRywu_b2@yB?al&)`-IWp zgy|G^mCc&ulQm=@+tC4ha|xZBye_U)EKFsH=jO>Jd=$6XsL^Zw{Kk$N{8?N=Cv7%H z)5O&Ch2gPbuh7swe`=nust=Q8pxjsl;IK@Xzc=QynO7T8An{0C2Hy>)lTI>QhmH&V zow)|WYpK+a)1*&`iiLq-Vb0G&m&Df$>~`R1_TBL(mR1_be0^h(C(*Ozv_0L^wr$(C zrfv7MZT#A{ZQHhO+qT`?|F^sE!^VrP4|Ss|qarG9W!|`zdCo}&^@;l1%@s&#dLZk_ zYgP!l$Vmwv8zsyUQ#Sx~Q?%$bEuzrx!I<@ggYGAIgopM?fJPobE@?|S_GTfF5V8zi zwAz{%F@>aNNwexAk0I|i6^A#7`oEVSQ}&FAn!Qb=&}lCJ_cc7x0pN(SNm{9)rAA6}UDtCuKVU+N`Fc80b4-Zb$e>sWMvqxXg+I{YBl|WjavwHcONpfsL;Ge80R*{|!Soh0z!;`mElO z?0pC9HxQcRPYBR#YOS6jiCR8+pVnICqX#a|ew?}XfXderhTtjVyBZ@u$KW@OY396U zvdc%Rw}N>9G9tqq%l_cG%mCM#!n~*hJz3Habm)Xy`<6dxWyFS>u;kHXw{|$KAen3X zq|Etsp{#YY^t=t2%<4b>kxGo9@RLyaL<_zkLP$*Y@u~(zC<-b*g@dB0VkJ!w=z=tf zs795TOnQEvfyRJ?vIkdDB7nrVnE*rZSt5=s#64^Pz^lUG?N)<*M<+4_{3f4rF~U?7 zd#^8CB=}yt{k+3y@u-CKXf!MHkICy0fYHcV#0cHSqRln)6GytB8?6_K>cd3cC`i)S z?1_qcQFrzFP&k0(<;1~iT5Y_Mi<%tXY?%6m`;zr2VpzWF-Fzcek^9^7hX7Qf*_gBP@eX62GhMsCnz0j~IP)L~ zV4u*XyV~^hn!Hq=7+4oxI&)ILyz{ekKpxkhN|Q~+m)vS3I8bPcvs^)!?%QTyMYKcO z8_&CGqeu0>`AFa~P8gwA`GbN?XM{w=-WLhuXQ7{lA(;PhGp29Cwh2j-kA~W$An^KU zK-2+bNgifds84>nCNpf{<-I4&|0WU`;B;Ll?SVx#nOD<=3D^|A;XFdhP>mP*v5k%2`&C+5tYP48KYOUUP(cF$_Ik`C2De zes2D6mNeZ~#{@|5FXUr>rvpb}9av#|r7TB|01Heqydl}WT$x-`mg>Es*X7n<00Qkj zuwgt0yb$}wEbWeJpl}HC(eeJiWKU@yq<;IebYGBAelN|lkdIS`gSFa$>S9Q2fM1J; zvC#he0;n9UJat4`G$tzqcE7)3kF2vvX+!RbD2xw@UE929-@g*ih?@%z0{E$=XJ`=X zv?0U8Cq8PO4V#!+W|PTkqX(8`0Oi$TGV#AtvmDTxWoEk>lN`%`HLGxV$I{Gq1haEs z(A!T;=3tLDiJI|B9#0DOo>lclU7lA?ZI$+Zoz!q5wYAeD*<$>GZnv+hmeV06+shPC zo<_hO-67(Fqf>^CC}>f)=KPSLD*btlkhJ!7z{$P0wli{&?>qBa*E>*&fQ~L=J2M^b}}Oc>{@hE z4z>D>UMBP0sWYG@df!KYUaD)l%Ai^*vL}#9`BZvNlEy597%1>UlSXJu{y)G#Linn{%^Uh~8NR0o zmTtwMJzroWWse9!0N9O)IDBmw+bTG)`Z(6xLcsNEy4!881$KJ2?$}bj9099)u7B9g?+9Ld--m%Kykg0!^v@piV2r*r&p`HS zRvu$G{7F;q>O|H&v6dsQ4^V%pry4G?om;6vf_EHQz@fauURqp2hs-%v!eiV)l_6S7 zC{?LD!V(sUhyj!3Kj41959+YdZ1ocWS0V9b;)rCr%3m4UOt&CEdzCL|mco*Pf3F;v zdo}4Dy|2K%Fk!DK4Q~#H~P2;e3wJ+Xh3Eh78o>+LFkX)p-c7xD;}ld$ZmE1AeF#{+g-uuJSB# z$Gp0Xy5oO#GG{bQV#so>EhZBqc^Dm|7xy;O0AgMPZp<=nYN-4{rZ9#c`Izsj&>iN{ z_zFa`N*w5i)d(S?2uZ4&UlfbqxbNegNA0DU!ZJcZybh&E_Q#j|##B8knzb3X8td;ak#{2u-?b>lj z0A|6gd^YCgSp$=;x-$FB!e;p?Vrq2ukdM1=W6}ZIF$A)nCjgNX{t6c9Is!Q_pX8%X zyAZRjaRjExcLYI{P;T7vGlomy`=b!H{MUN0V(G31;Ik|fGLELm@^Yno^km(k@f$-b zC#BE^FcF?%wOR5JMu%L4$(Z|>zo?Y4fWA@$3qe>YF6_GrKN>P50YJEvo)fuSbteU? z^>FOJF6|}}fikhpRj|Rm!2PlMdg{pBb;0oROF`lXQEBnnZ0K6s^HotfP2|Q%W);H` zoRnH-{Y>Hr>&X85lAy$tBw|>I>N8HuemA#*n0Hw;B{BkCfuhYGOEFRoQWaofz_Tj* zSKQ*J!U_^OvLM8x?QmF;jHLk~XcXxZhOh1W`aV_*C2M@R;SeiNA9P>y!4pDAWqRx1 z^|2%l*7Vdh4_U^jsvnkAZ*bbcXsIAYO4e#)Kq-1tw%*hPddvd!5q!!XdJpzRdRR?XVnWqa$tfML+;1tr~`UvE3}BXvw%;lgO1CbQ7-K9CEtTqLY( z&;;le=BrguV%V#xlydWm0#GI`LIlcD`y^3)u_er1tWoEA@=W_r@EQbhvOAFJ5|_wt zrO%thtPY?|9k1cS9{hA%MesP?ZcI?yb>$f|bWnXLLpS=uR0jSR+G3B)0HSx&#Lzko zcRe3xk&sH|^`Byo3b(5za$HmqPx}C#<6>^gIOt59pA*X%6I^lU{Dp$UBrt1)Flynh zpaDmw6%dV`@JNCc%kl{a6;ntAvy0Q$F0;^LFYw;Sfi$xNm=pUfZ*&xHOTegGN<)4e z<2ZqIMHSmjlHR#EkVF;_fHnVJy>h{78M$5W7rE$*Y>1czyD8U$yb#H*x>@azI6;aI z2!eXil9t?w&T%XL9MttRm2qash!_+f56f3y445!7*i(XC*yx2sG;OsGRu z6O(oQ)XpU1zo)Vbfvg;(3&f){@%Uh19#iyE<;a7yf7mc;#AhTA01e}xO#7UMr}U-x zf)JaBaR7w;=f@ulN`vldAGY;6v~T3Ie%nDq@)4rdP3)NfqaWBWd~WDjKlcIsXalJ} z3kbrqVH!3k*$RHXNcNEHsvDM=4}zMkJ*4Q#Uvf zMjiNm4SNI`&Pd%kU|9;L&lFvFURi3qV<$>h({cXkbLfwge=!}cGiys^n}V~cKP)=C z+sAj7S4>nOB#PnwPeKlDrvnh~<5vYiyPA)``p3rAB#9!nyZtjE7%^S&fC8A^CTM4s zJL^a@ufM~A;$&#+lC~1Yrq3QX%8}EzoHf<n)!;LzykanT$Lv58>?k5&Ze582xpbu==QLq z_}2j=CN3sJq##`GN{A4(JN~tGQL?zw+S_p)em4&7Qx$^)z7oCt!WFxR`I&24gakm) zIi}?!4pSr#P(g<^mPztQG*0i0If|gnS4NJJRzHHf(ht&DQ38J)^Mp6zAo7i%N}@g| zU}h(p!%wEf$9$x1;_c0k=M5h*V041KOL}GL0ELytm0BF0m@zaYy~ZC_QJO^`u2vUm` zRFzfkuU=u5T3s27v5^(7wwCl_+Jo!lML|^jrYQOl#Fz4wzb+S zQ4Y{H0BDf~6{>8MtOYf`29*;_W{rFy<((Pb;vxBTuezfgQ_QMPS-u_b z48@H~VDt*eR@DLYM~T4-ygAk=6hvnQfyc0uWneLtRWOv-OzI>S71g^981ajg}%n#f2S3>HCgj=fVfOFJJ%U2t4p*`1z@sKGawIMLC_L= z19suua@H)pifo~mr@*Nzt1`#{9~yFKnGPN~F~L8zgRq9*IH*v@Ua0Z$p<(8ut^yJz zArg!PV2HU?r#@ILZWoVQB*8XXBTJ92>-f*2)$kL@BIZv z%Neo;!E8(thZAvkS&Qo6wCiwD>#KO8fTU1m*fGdyCbI>f3-z6n?n1E$d?}pQb3>(R z8}&vw4*w{wiA3wunMcK|^CJJ5JRJkdx+c|~!4geMhCe*h1R%$>1}&;iArXLy^7P;g z8bJF`Q?p|{%GOW}U52sMEp)`hmjK=1SJuC__T-0QyL|AvI^SL~DAtn+>yE3xJ9wT7 z#O&VJ&1Aipwo*G3(XqniJc0>9@v*Y4Zl$GmgL`C+xvL3vZsAj?I zGFSPW2mON)N(M_+xv+3~4wU6)Y`SR*^q?1w-|1K*cg&Th^l{w}6x<-<+q{f?f^KtrDab%QUY3 zfDkq{%q{obR00+r+2V!^a&?`Qd!HE&Q4U&hU8LjJx0fEW?0@UW-K(3cuaX^&t1*gE z!|~NR%S`B6_c_TSRWN-HS zB2}_kfNPsCTf&SNc)9CAJ}urH59o7y>Pp*mG0>u~tzNL^ikGrbk8?d}2V*xhoVjhv zyxsjy67Q!8oKz+v8?KVcE4y^X%-W9lajuRhT^2YY_-fsg@|{MRkBtzoDo1r0sdwDR z^s_=(&DIEm&RwUYo#h$xb{CJ&=H+YW>&@>2z;m|q_LZZ=+~!X+0_Wi*`=@)mUkESc zr{|%2t??AsyNhN+_b|KKQ`+t8R83^_I%yBjd*ioH1!EJ&d3$b8SEwEU$2$u zxqsXPko)%0-|~92vtK+;%ZF{_*%3L`a+`-+3wi zKmWhKmyw|V7Oy-jU1Ve7cv;J=K6GZdyd2&5yun*+Q+hFIMTAd zsqa^}zDaQ<(Pw&5I^TWtvH^NEQAvi34PXqYw$}<9q?Eq%-S{aXgFt(8DOo(p5@5N7Eb$GM)u43(Y z$!BKM)RYtN@Ne(^ljGvU85Y}2_UBW?j@93Bt99OcjC)g+P_?0AJCYNLS86NaNB`gy z_DrE7m7M6=r#q8@V<^@f8ez0R)u)4^84!ntkhLq504oh8AYX;$gqq`Q`F-$xdRSMH z7~0fEzTL#ZMIqGs`IjNWcFfKfeGlpBdln>bE~a8cBeR=cd4Q^Bzq&i$Pi-@HspU`R z=6b6O-aB0?p@pwx#<5_7K{lC2r%;?%ZkakBE zO4c*d0)`;H3bfN%n6`Z=oL-9(>?&XnMKwyMM?GSn0M--|lG}!{VLPy22zN?EM{h9N zfoujI;lvCT(FCHHsftz^qk-`_hh^vfy{n|P>$=D}(mg=rr3_Klmw!Sd7Xb60JdL`* z>|(8fziDT*V$`l6kbssnM0?9jGKue?H<#v+@Trg%pSSb0Ybe6;wTfj8$8vt*w2DR2Z!3@mh>b% zo%cvi*aiC!vOS?YF9eq0X;$fxWb)wmdi*3e?IST+8v1dAS?pt3tbj*i;qmLG;b^G$qvHW zpPjFGLY$rRGdJ5Q-6>npKb)U+90ALftkUv5XV{^h-^^TDCP9B*c3sm_1zrGmTd9k{ zA=7EVBZ+ z_O*dveSuZU)&O?{@P9$VJ8XQ8>2#meI=Q4mpNZKUO5+ZToZc?$HWP3nBT$Y;utP?H z`V0@Md%RI@hJ|B6$9L%BZmgBD(V)(7jYg0XW5ZAaT`~rSOb5c&H`9o-<2>o^7Uw!K?zoIgnk}BIkN#?Ycw%tV&$%WBxjW4|Jrc&uMOJk zB^7r3nJxg*P!)KKWLCB9*UugT95df?2d*I#eN9jIK>QJ$uJNG>%O54@X^m29IWthg zjSf3TxuiJ1I5WII4t0B8fN;r$)ZpLLmg9>6FF=D31@^c1;|ae>c$JDX=F8gj?@1#| zK@uM*hY_A19XG9pH4}~IRODFbL%7866a2OphRZG~QoMg}=7rXn>^OVde(r~Uk4y`f ziPVpLv-?_BA=L<^1lWGQxW{}#T++3K;EtG=@)#m;J}rYVlNx4$cVRJ#9gLLrtjWf$2(yCQ%=y27!-52WPGJUNlU2Ay z*NKgkDJK|jsuTVl{v`P{|8~2rHKmooxlN6&u>h};QOR?=`Vn=|Mw^X~c)!X{8_&hv z!Gah!>&Co0#qy5Br0N|2ygo82byl#ajsT2U2@d11U9^abNsUvqrHABBf6+}CQ~wt0 zXV(hciMvsK9GH06RXd`l`|fX}Hzj>gYd)%o{_`+ANpKCv?J@XE&3wY<=y4EamoMw1 zs-C`qI?KxP43=F0WC2SA`2}>$?))&i*a=~tAO}P&bQDqS(!*u^x_F9XJBJ_^ngZZL znD0YwArK{a_p*2ZbJ$5mM5CRbVxqO7ukP^u{V2~|LJBItKC4!o2S?JY`m$(copjmm ztWAndekjO@fFHry=ABCEZ)F13Ayh9Z-5|~HfkbPicnYbNrWXTO zCw~EtY)z0nUcgd!OaY2z^`LS64s*MeP-gkudr!7*mK*T1sv36c$)dj2O$0FPm$?ku zSK>8r0p+8WvaxWMbooeJy(^c@k2+5_Frf4Le_sa(T>tQns9pJDGmKu+uWk0)^R%yN zBHW(W6_m0LK#`nc|4Va@$3ueg$Ru6+_@^A2b|zDvdOh8+*nak_1`XdAF{Cdgx}E-- zwE!Yx?iYv-xH%tdP+}1;0E7(+C?HUx5~7G+VIygeOatf zES4OiVW$O;Md6%|k71xY?r?ldasg;e;F#@ajq@#=dG{8R>sk*V@m>=;=y1AdbA=`} zEIhg`wFsD_GxA%dACnmvJ^Qfz_U7fk8^e&c;S-f z%>r<&*NOrpS$=a!*s2>N>VFJZtfUTklD(7}; zpt@$94dhms5Q_jZ0GE+iC|Y>&drTQ#j#axyG9Un%KClqxH>O-9iry#(ju*(>U8gH6 ze;40nqOxMHqs;>=brpk;zc~Je0v)HM>gN?{I0~fTDknJ<6UC#;kHVQ1o^L_;VS?f_ zTfp~^YT29u3d4c^3(`iDryXrLmM~ulZM<4$FvSL{OVAZF~zak)yj;YN}E zt=6S>mUuv-AF|rJoSnUOOEQ#gh=q;U!RgxZjcsJa*BMqVaPoHQ=;NcIbeoC=7h-i^ z7f~RB6@A46SZm0VCFxzf{o?Ap*XXH3eDT=IWjD@%vL4%t;f>2`KaN z6*1FzT|AFhrCS_Q)#cm1C_$ssEsd|vHZ9`UD!gWiS&fTZhAM2+VPH_;yGq!rC zc;BDKi-+YdRh^Q%Hc9GnMz{4=I2c(N<)O&rviZC|Bze4F-v-MgD`g%BZ^xI#&SrJB zFf|iy9ggVQabE4{$ctYmkH`)ZH*qAt&JO>42AHkg`~L`reh3ViSey^e+hpO!FYkup z^js|gP-BfVFjVDT_02*c!V2w%=asNpqp5ik2)TN7yg0)w*gFluQq_iH-B~A3UXW*G zQ9Z9XOzVGJI@pokU#CT-=yu&z_!E1|eljQc3o-yxYd6nas*ZvhkmNPo%aIdV<{_{O zTD1?AGdH~t4-Q8K_X7(EM2Ls$g?;h+Ghqn;Li~?+yBOp}yipi->Vn^iT1Im0n30k? z5$F)FXjWf0W5^qN0RgjeE1QGI!LLL9f|46j_+2dSVnb3*tkob)~ zk&MkTWGN?~^oef5R-Y?$j0Wzx<<4J;6$OKq#o4&y$98rBCaEdk0O#+-M5nlm7}!_~ zh<4~_-YQ{ga`tqS1yRY9?wjq5xJ~6zi=gmNQ;{&YJS#D}C&3I!6gnVLH!+e6uwlE! zV#~_H780~0h4muFBRpD4ric^f;yr7|0J+BT_*|WvKtuIvfb0A66(R=js+{}e9v_y- zCZ&A`*!}OBZ~+@+nMC$V&`>ZA>u7T z5WgirKa^)3r^+nQT9&r;`m+}l?^VrQM-_hI@>Z#A0 zMqN4k$zb8)pLP(wz5W9Ck87v|(EqeP!(wP0X9|iU%Qs$ei@(2hP(%mKN@&A}#bi!E zhf~-VBok^jpznBgS@>l+Je2ASf@rv2S=s+Wqv%OV5rLg<$FEQ7gjbriJ0vp)v<5Pw zzY_hbCR}nIFF;;ol{_`}c%Z;tl6b`kYzt|^2MZK{t*P0ArB=yt^5tg$_yn>ZA$=mS zXLthA)U4LFYy%VyPO!m-AJhTm04a?eV^rH0mkoKGueUco#)zEKj9ZF{Z zE}|`|o91T>f)LS`LdsbM#8ChB(p{f!aDVVQEt0r{wiB5SWd?zhxa4d0OQ}KDV@w&z z3e0Uo?27wji+NJ3@xuN9elMvnL_w{Ucx}OL@|WiVugbZp`O_itCnZ%0Vjn8rD(#m~ zA4mhQ+ts;YKUx#PV-i?y-5j9m)XxpsF9_K~C`M3RMcjC>OmR_5jthbM>8eM`e-N!7YJJ?WtRrZl!Ht(;!qoLqH@$V|^%|JkKRN*Z&-gzL_t_sDQjQ-`-&gm14Bvmj0F7bM_b3g&qSLC|zF+aab>6#4 zIBVSvJyZ`1I&1%PXDgi_Pn?g3ffMHNdj1}W2hW}8Wi*0p`DXN)EdS%IAgtW%m7I2K zhfWRuVdA<4f@~Lnw;_JXTO&@Cz=Cn2qm_~6E%k>3S724C>$Y3zgReW}r8wK!h40l% zjAz5`ra9`(?0L7i9p|xq`}*V3rWmE1-5Jlj;WKz2k9N*3iH>cFYb%EN0mdPVFTcvv zxnETmUE;gWOaFouEeQ603Oc;N1)7J6F2dop@YL-pQQR1Csi@xm+{p&tu?>$US7w;p z*75G)?tPZnKfn3BJnW^`Wt*@#?3RWWJy-hFb)6yP<~1|@#}8a`;TnPWfY|MrY^_t3 z>Oc+tOZORCp0~HGs_-jshSP(II<9y8{$5da+pYT>v8fP#r6IqAnCrbeBTI3gl81L> z>OM!{AEhM#@vh<{hynW;`C(Ic&(B92R~wK$#FN=IfqST&7~L)P<`y)i7%od{$2S^; z_i45&qv-W;9BHgtlN*Uw+413~i1#sJI&dZSpXujSU%6Ms;8rP%{_<>)9>x27Em!7h ztH0O$GR^+xh>b4(xQ=Eqzw!0H7-K!O8pd*aP5>+(wr}KY{{HUw$ZX!3y2^gVv%a`u z_`VPN=GX_MfM0$&oyN8_Gj59HL-1|Sk@KM+c5+kH{SbWX&C_PtN_|I;r)2xSjRa$=?{`&5LfuOPej6&%`XaH+*z2 z*#NSS>Azpc?eOyk^~PKEz30bouliZze-w0fzSSIZ{@YLgC;$AvKKx_*PCuhvxRdzq z@SIzPZrwydp=_se=U|)Po|@3-*nY$~UHsoh5sj%$lt!g?sD)tgmFMv&B9U81- zj1Eoq!}K_rwrplc8BMy)Y2%N)xa##4^a+S%LS3J={Ex{b=RX1S|9O%7V~;Ie)aQ5)2H=Ina`#cK5MN6gdN_x+{K{3cXOPRAg=9uV_dQ?YN zk|pg4* z!2sN=dv=pouFg|YG~bMlF*I+N8RO*2wWf6HUQpSNZjo{dyeu0~Ja1P7{>D8@ej>jr z0;3ZdH`gGZyJ;7fc=knBc5zNk8^=va)|QOgT%Imv3Z-3aSO8gUFEWur z6h>(mr$m8wQb|ALDpN7cy0=2L!u$${RKBW<$)-&1DnWyhYS{~JV28}=cYtSn{W zN?op?Rmx6P?Wh1yOu{Q}6TWUcb1Gd-ulLqbF)pYlJdJ+9??cGcKPebrr`c}*Q7cbB zGcRCr%9K+sdgLEWWi(TY)fFl2S|}AfV;*IOb6TAybI*C3uNxbtoZ5S6la@?GE1N;W zQFYG&7l|vH#qW;mjn0Go_I!wa!|V(#O6)KFTwSZb6X0jJ+RwCEtI2Z|YU$Wnc3>IwXBfYra^0?Y9aV38NI3hSBX4laxWv z2{c4ffRF>~@g5>G17NzIfH8FOb9v?BI^32I?1>4 zSfWots= zN;}}F>$W$VbHgwHz{Uw6IcimWBo{|DEUmziiEmmedySpWSYnB(B|USBvlvZgM<)>< zHcg>=iBBum$xRDx>_TA0jeb%gIaRHkC|BY!nE?C0aKoE za)5RR#@$OKM#Q@~wzphrwJM0!%5bhcd2vX(=HsGpcF8-&u#$yeqt2yMs)pv`eNf7B zkc5QLVoG_;YArSei9x;&xShh|%mVuJ_#`PC7_iC!%G*bSB5A`QP6Qs1F8L*lQ!yeDfIl_#D2b1J5I`*P2@3FR}Mr5o-%! zMhKKhLHsJ*qE^-zP(7osQKwlxSeoUE;a}6K-_$18v#o|s)EzW5P2RfX+oIYuU#DH{ zcIi}`@)ubifz5u+8|UM}4gt&`Dr(I^tkHksr$fNLSFm+mcbaPrE{DCqY8{uigoHk` zYl(rz6Jvp3m6r}P%Nlb=8517Wjv4c2RSRERXAskOhjXV7g<^)>KTw7bOKQzo;e?n< z(t_W3DMm_Z<#tJd%9O{Nu?WL}3@*{5sne2{B``4hGQ-O_?qK*VECKp&wT_s;zF~Q! zFCp|dbzZ0C5)%f~GVj<$bS~MYypHHu&BG`hT`~`=;g_#aai++m60@?>E91wF5&zzU zDC`BrNIRn(tA`ahUuFOjYIjjGnl>V#lUF?3JIKlzT#0`tv5#R$MRtUO=)1%gDHYmL zEU-(}i*VDj)?X<`FacstC6nBQPoA_!iL-k4k`NyNs?Z~K=%r>!R0=2)w*AiYBus{! z8$Ei`Mi~{rnn7bd7cAs1;!kUPd}}n8t)m(*x^3aAP7L7?-n3PZ`7-@Dre+E>;yjB9 zU98&Gk@ibkwG~b{#qk$wVf~DgsEq2pmCKG0tftg3ElZBfcL2&r`;|cnt%!2qxk(%M z4%_-G<8YD~dz*CBRbhtqf}(j>>~hDBHFJv0$-beJw;rQ%8(wXCAd7geK1mV0OqWvt^IkVfGM$)?Z=&bLB78#viAQqNaj zi^E}$253oJG%AXSvrZjhz8rvd-mZ3o&C`NSgQXYHpb5$v0i%f5;ix#c%;$|dR?bMG z?2Ze4zeUxgb@F1EzI&;D>e|=Y9B!6pLcZZ0ddr~QUoKl2*12uRN_AaBB znNM%B7Mh?Qq)s+V9O=*=yK{w2jVKp3r)37ljc+tzf4tQyVmj=a)VxeARxfTMTvsXo z-K9|1>S8mPPaP>mq+t?D9lC}OA3mXR!g0oaN5dkU1_SZRPlsBKv;A0+(X0u<+NH;G z3CQubq`qJ9aOdslI0=VF)rX)V_*pD03(_Mqjy_L;)t3x8#LDzKW;4lw z;{LWh8<8VWz46hfa@~Cx2VY?5kZiYr(Dl4S{@qoMyP*MYy-icz@tX;HATVxqgdW@U zNKNZbj(z}q5%{-%ml&8c2&ZOB!mu`|6u>dp4_=9)V8^{iTTf#$QF^bNa@?}##t!dN zeJR_g`FHg~(IzA2pL%UWncT271A*_|N5szh@nWyr&B0gw=1zA=La5cciN!g#vI%1i zabluDt`dk$s{JOlWyB_A3snyF$s?^$(1Y(hM;nDt#8BhJ=;OK_wAPGrcC=dq3cxU2 zl5O{y06irWP(7wLu9R4QQn#u)M=(&K`dP&qf6unKy7LO>7L}#jB`b@RW21Pw7v7Vyd1nJt@+z-@WK;4N!ZLsDZd_b6RNO z;i*wrQaDmJcZJ3xQLuD=7L_stWm!VBrT&i0f%vmn<+-+QMAdNV1Z4`~ud-lXjW6uC9o76n{|8m1mo-Kr+eFZ^~jNg4}p+_Bxmj_ibdjFg4HCGf86R16MXGwLBO$^evheX5u;j4dVvWg$_YezDr0u6sg-Xe%0w@ zBt48I^<14a&g$Rmjo6;l!$oB-yfBjH0=N|z0mxMNiH zGD!sHY9ra^36=_=ziMY_=NKxkS+ou;p>`Zy%T9HrEui2iRv+$v9mD@TA+ND^542lh z&7iC_D8!PWm@NP!F>#$v%g+z|#wuEr*+Z!cuE%y~(NQ5C#$72%$hob1vCC0R) zvXp$0gS*}M%E)NnO?#C57R}Z^-T^gPe8Dibb1eLRcEF`2<&{wDvD6K#+W1&E3g2E1 z6*aVBG3&-AG^*?Jrex2CywZLxWtdqayT@&7%ms$8YJdkSQ>*0*S7vdJ2l-%ma2>f> zlV`hZwF&&e-Fn5?sdjx8ngba1@0S_Wofut`^_lidYt_Hi=VuO&C`^S}TzGWD>bUNM zo`Y5MS^y>fNYqN}{0-*|?u+F{zZh~z6n@%2FJhL+LYNcCA-8m@4@wq^kmVRlqdFyY zKv{+wB%$ks<#E_NHbUd=qkAvE-<@b+X84v|&bq$7Ks>i?y9L*rEM4NEabYg|2odLZ zZ{Mz3K@3y6tyJ~eP=wrjBMHwopJ2rErRyA31^`GTKmHzBT_FPojYe;<04N)kJ`BEm zZwzpWsThjtn{+P3i1g4xR)@BmMs4&MQ;K_nffjl&gf^*JSrR;gU_wxgN+psCcO0^P3gs;?0wwzwmh?jY{@)(66*N zKfY(yz6i8`Na*X6$nJI10kL<<5-kfCx(;WYSxQ0ri;+^YF@RJL{10`m+E|^En>#tJ zQAWMSwQ@Teho-Sl0@|(asHy1KRRnms5+-` z(FrXK56zxCD#JOyyw5G3`#YkMMCc0xCyO>KDHWnIS|?C=tc<&vTac|-kXc6nn{t*_ zA~S(fmmO<$FQO?@=&S8=4k9l?8StCVI(0aIY}nu0xPffxplJL zC`sU7X=>t9jBRE4CtDhPd!ZsK5My6fb=z;y;z+X$G?F*t+H-HIiN`QI8h~>onoTsw z@Vc)FkxIrKdtV7E%R^W(I64@B?Sy3eUpDHj#f8^*@m2?Q^5CtltCyFTxIAgFIxiNc zT#7y(7T2;Oh$U?E{V#c0;pwha_{51#R-~7A+uUxvsQN(!9!`ZtZ2?W#Y{rPpC!!!F z0c4c3FUL3Ho$~2Y*li<2>6~CL&8ki6`UpM45i#kuXk&8t?rdg;OCx| zpZc9O)tBrqPCfTkU|uq%4WMbaa8O`v2Q+2EUafd=I_`)<}NXZ)& zEk*fBO@Cn!J(8DGkvCKYoD;w&An?obYm3?^AQgEydJlt=NO8};0WdzJd24u$+s*t! zAQkA2l%HPBE?3-&-1+`IAg^_Bi?Z?PapK9{5SX+`9y+{-`vUWMcmM79;<<^NmNO#> zufu-GJdTzJaRs84_>r3Hn>}#6H!S5!p#4nRFb%Dayo$~*OXgm%o zLN=p{VGe{ThCDtI4#4bh2xF`sI!S=_KjO8>3XSA-Llp@ftF8L9r}0GR|JFV{BfCY_ z0l!sg!2VbscMb8>YM8+iW5n=Kf~{qB4<5Ez5biFU*`(m5UbcKE6BP=`Z(5!*rw_+x>+Pu+;*P?R9!1`sc9gu9)1Nk;SJ%*LGG z(wxobSU5gnW!_jA^I{~BL`Ou=t}Ar~uM5?|*9^wAq1fKG9?cjWD>9mmyzq_C`|6r( zRug@QL7zXetrrt=0R+*oio6e9v=L!xp4Jhu2rjfy*bG$W=Reo7tOXa3cfH68;Ar~^ zaw&3!feIy+16bR=R=tEYG+mpi{$4-vT*a?Kt}&>kiyu*%+i{QwV`ZRnwo!vNjTW+h zJiTy{aW2`aOfT{L>7)sR_g5YA^d>7ij6-x6HE-7&<&of5pK?FG)MenAoLO(|4;Qfu zP@h^mo4iKR_;XD`-`^Ux!-Q4(hPp?1%8(rD3JC<*28=MIP{|2jr<Vjp-@pC^5+s*$mcu$bDqXGXKfj^Z+)m2)}D*BF(l}KV}t^P+$UMUPgPGcWpx0u>TWp&x@$11f+(vb|@11|Ma`9zOn$Gk*q1QQ&57Y z&J3VsORag&P7UyQWTUM)<{Px}Ab#vPUpBA2j#e+g1Xj=v5Gdf^*BHbV9ik%xdc=}m zeG(2IDYw2+wFk2%B0uc8hBZgVTE<;iylxIi;NA|q1n6WFI z2?#kgNJfS%wK+KDsD2Nn@MZA^k))RIuOY%9FQ1V^n9&ITs&$R=kC&1AD3?UEop>jF z`?Pr*-h)W}3wn{y?xfX2o^nl*LjFZwv(w2fDmEk3qh5GVIY`I%ecd5>*r@fNcrEWg z6CB^Zja<1qF<^&n5H%#7U1>^cV+ih3UYXahAS~j=jU}PJKLEDuqlB zz7i`8*m%pPp)*72(C!oW?x6Pv)(s-3QAvCJF2_*o{+wN|<&v}4vn4k2c+cdou9fx* z%KOA(^rfe{+yMpqm7^%P^^IA)hY>UV7{9Hb6oe}>s8%FUwW~NL)jeA*$KSpLcsU(7 zsie=yRliOE$qMQ_F~KQZUY|TMoqWHg$MvToPYV9cb%()KsZ3zJtLbnLtE&NL$_^As zfi6kC2JiNdUv;f+u5|}0zJ^*PiYj)TWCB_#K51r`@SNDD)~nSh{kpi#^6rp+|=yWIDxdEj0{U17xF z9muew*=t^}$kab6#)eSlVT6oy9O+T#iWczusA?ty!l!dtOToR^fjM z-nI2~G!HT#Woh_wSPdzuZ7>RnXl>gB?uc^`8VjZu;3gF>0hYeFBQC1~5dC$ydH1U{ z#xVwOlx80Se%PYz_Y)dDJcDtuOeAvoSQK_$f5RUhsFbC5z=Ze6T!*(l;KV&#}#xE!0ES-PQKhfL)#%Nu3%bBP$iI%4M2%K~rV?>)$icy#NojJtCFo*xWO!tsR}c5$rP#;t#bPL-0V z_CSNTBdCRc2gbJmhrs8!02jGh#MMF6m{UBssi8sG6OB>!%aZ(^ImO9EuC=Vs3u?AQMigb8>B_Vb|siZ2T2S?9oM@0rAUV zCa|k8iZ~M;iohDsYfGmAw%va(xZUixU|O;ESQP_ep4SV~W*$pByr?Qv4r>x;Vg2$2 zdf-s!hOIzfuD5Hx^)8;Dfx?j(`)}l!9zv=x6z9*x*mFUsPVpZ|aF?i1aElxI9a zV?7jC#ADc1H@?M__&1d>&q%PKe+$5AWgM5Qn_dCqZ|z1mgzX7{%jiCck5rixkum#E zh4kLz&+dlfXLt=zO?z{bBsfa@>e^F);5ceFNjobeseQ{3oZafeoK4k^HFjKt2~4lXbDFvL zE(npKZyr+ISkjHG-&tjpB5k{CO03&qr;s%hS7EtWuR;l|*QgEv5(-nTOY9E!aWnx>Bf>2CvG4!mrd zcPzz2_8dX4QNxpw#O&br#Hj#FIyKDDaOg8cfpGQmdz~K7Ml+FRq`h5S>6Hcs^6QU4 zDSxt&y86m%qqh?Go_v8^BGFXDgFo>VnfE#vnW9T{34-6&LHye+G&HdGFZrFXq``-xib*SAPR{(2ySuqVJuY;ka zH_d;L?VktpAJ1u)o2AkH+LhrK3;I5T{2qA>3LJ6q{A?h8fd9G6Fg{O_4i*DoCs=S` zehW1~AOwN3@cCI&A$XRme73S0LGojzAAfKv{2)OW`P@mf?dm9v@1m<#V*6Szj4?5}?SFJHEdnyeJOM6KZ{{KW4R`e0Ax-h&?M z$9|(X{oa)&@B=-gRUy zVC_A^0aA%q4BzSA>lr-bR^V$;Xj4Kjm=#5k3-4Wi_k5e{zqLT;y#L6*!#a8Qy?B3J zby)}YA3?4K=WgCkRCLxHJch*le2{thdL8myNW??L2og^fWlJ*(p87GSi2~3^KGE2w z|2?a6@W*6$0>4S*Crm4!c`0gaD&e$bDi7HTNg}&v69R6U?2LMh2Kt@u!amJ?s^D0|FrI>oI4XI1 zh{y;&$>fZWm1E94$l`%lsM3Poo~jajtDXQ*5Tw#!{|~?-;B23FRjPlcp!)#6 zmBT%TY(UYv@!&dio$%@T`YEHT3wco)N3k7!%^ppYypLe1@KgnU)X##^8tNkj2v1m& z!eR8|fK6QJKye5adfUw#VGpJuv`f>}Cp7$~7W5lL#JIq;Y@+4o6LDWHlWau*c-obT z+^+CXG(_t~754$|A|np@?N)zBxw9@4aXcbUCg&Ks+5r{ChR@_@1u@))YvA8HfWOrP5!{S3UTg-8Jxj$c&`R93%b+W0a)wAnY)*d&lp|tCOZFs< z?kfQ1MlteACWsz{j}~|K#j&_WdKH%N=_@k&x@E9CH|on0XfU@<5tr|_1v>ALes`T% zj@GP2U2+z=Vi6sejTnv2%pL6_hJ;Ol^#~o-p|jXtm0ebar%w^`KJX(BmtgkH-2|MN ziNW(ECy5T|l3QX+20?!eTA)fv>r6JOP$7l})i8M&ZWk!`E+nuHG|;kIq);1f08s4+ zpK3j>+93@=20DLi9)chF`e`!`-F53M0lFmXozwq`S(s;YRLfThzG_I2DX`}#g3lnF z0fsju2NBum&rEx4B2JTB-Kr1|T`!=x5V%engvKIP=}1z5y~=-8qOL&nM?@+3wFVFa zw}BD~5IP%Fny3O%UbOV5`wh*#J`Bc6kJCwfMWE!(S{OeW{29?4C@T@;SrU>Z$|ACT z7T5E5JjYHkWx09-V9+4Yo`eJH!b4wm!JPvApp~l(%oX_-7?crrYo_`0Eh|rWRqa%**q@r z2;os$6{T7L8mO47WO-~eh0$!w3@Q>z{YtN1UUB9Gon#hrwig2v^9q{O88EF`K9eb5 zi=vT^+H|$d;|y{NnC0<&b1-t2fq@7{4wi0|XL6$aE<%5VV|Ty9CRS)P&SEt7x8sd= zLK`L08ZQ;-HYgHPlhM$xAnst$=8G3^U%YsGmgiYc|GWogLBO=6KY_uXyv(Yy57mA9 zu=!zMYqaE%Mt{ymg(a(O$7ZwDeKnRVG{s8gwR_HK+*NJI4jJ1G75NL`VJf*i(5GFS5qFxY$G zrW1cJ;zXhvj~^~i`McXP_>5d?CJ>pSP&5*aA9;Tof4~X;^x_Lx!9pA93%mDZR66(08fGscHXNQSIKJ-L9l5gTg1&l1kX&8UG zC9gPyH6o z&Mz*Hy+KuWP-l>_C?1RR3p+6T8;W;(S!hScMB11&?gX0<$1P)(O(8V^P}zSH@&V=( zw zKMk{a@x0J@ZfepWh(~GxY;3aw_W_JkII+47u3}rU#N^pL&#KuRQixKE1PEk*b;1J& z;{3_QrCSdFcH&eA=1w_<^iOV}VGsD$D;9P4y^W!0LT4i}koA(&mx+JV3CNYmh0+sD z-*tL3AWUv?xK`?)qXZf*?f7ICmo+-J& z?-wSglAfJOFmlX(1_+R%9gIwJ7tP)E)Zy%KK((?d61Se5WxX$tCjEY&+vG$g$A})Y zeS2wk-P4Ud!QAkAuxJIyvukLF0?@#%ihW-jdqYvQD7+vFKgN5L-U}9zj06;0O{<6W zQuhUENl>gnRSSQm$f1YP?}=rYk3&I6plF-{?h$foGAPaDSbTBx#n;i%SJ4+= zNp5H4wn``Ik6ahqLECVn z$iL`*Y&&mWUcRm#!5O`*Mmo|$%w-{7d_qh9;u9#X-jsjn8YlBYO`gdaXaMk!mwzs@ zvN&sP8O#V5|jz4+uOw>Hd{UHaN8+ak5PXU@%UtL&VNT5Y(x zt<~Uc>GEX%kN>J(q(D>=zJP+CPT*Tl!&GX~t3RNEMzH3XIw1%xy`?owg)g#`7 z*25$-y!9Ow>GlNbB;4-uyL*SrOnNig4c>C>u0SZ{kKp0c`_XvnaG5`b$E`-p@x~dt zw~m@)$yQ2k$n+>qdyN4P#4X6QwSnS#W3eRHc0BZk8=|+(rIPz3xvg+CyAa=wjeP(z z{0M*jTPWJVjI50UvvW$p^ni3KgBqP3VER6XN|+qoj#6W^BF~yIQ6{IGx^s&bQm|1} z`@7yCf48Cw5NdBrY4sS$VPbcYNcoO5n~tsG#$CyAVqK$%JemI81fz2a=t^QC!RKvK zjTP)O`b&NUr2KC}hM}8$Le-qhdn0T;Sjm5!GWt*ZR^aH~Dgv0CWE=Ex8>9$S*Xg$k zVRN-?5vR+l9A-$JId`~ugao*`kh5yxJdUVyGvt>#TgOHJoxWwX*2FmQvhGXu1`L11 zUzI0!_=?a0cVc^9#BYd;3GyWWc)Q;J+hu65-jWkBmWArk(?T_Y+JK9ec=5?OT+A1r z44i+ql%(TGMa{pd?2AvHlylI*eR!qVRuAmJF4JJ$VuG=WUtkSjy36ysUe0TDLJ#W= zJ$vg?e{KKnb#Lv49=^83Zmpu5eUX1K#g^w`QHGLtX`~CHh2V8!6U0F@?Mz5+yPW4r zMF9CN6ERm+4#|T9dyOxtOTzc z7;curnLj;06!$Yl4tVU6E&#$KR||rRr&|e6Up;~=tI8stC}<7+RTk3WeV(bpXMO%4 z%s58{*tDh zXVtgMf->1`ROx`-8&W+r9J_%kqC_6J$r+R88i&T)j+GIxFYBLX|ILjiJ*U$=OSwcw`wKwC`fS zFa9WwLR$DB?Lp)0B&$Y=>J`-@p8Aa9ps_%G%@{UmR;{fX%V{~r8ijPt+^6S;BW$+r zsO!UX;kVSUhRoj~X+1c4vp#~sHiQ`lxi4O^H7VrwjAF;8Zis(N3}zYKiAA(85`hVM z&k)MiH1TOdel!5XthFI`t2mhyo)HgMjbq^m-^&PzKtM)xFiart07jIOPYetXaWtuo zhTYa>AKT||xW-NiSHsy>_rwogzF&UuY(M;9fsi!uRa~x)MXqFW$E=1~dbbdEM|<>g zqQHER73!r)(A$6OJKf$o{AvShM|_(Ma&>hG>!ply(OV`J#_mIMNr+9$vm~jO&|IHE zz-jajfuVmQt4H79v}m2L1m``VsRAK-x@nxq@p`%nadr$)h5>P?RBT=#pwi*{v1(kA zCg;badIr3CAx2p_7Z}(_o#Xk2wo*VPfZry0wq(QuouYra#|!aI0kK$vd8u8MY0o0$JdDf6N5r&#Nfk8PO3v!_J*Ug@F>|x-#Xo`j ztn0p6$`pTg=R_<3urkPRIsL z4vmK3UKZ%$lKx4fFr(_b7s-wRA|4y-hryqAks+*&H@zs;Qrwz&bLcuw%}u&A^F2{QZR@$Y*15ZMS~ zzJGN~S6it%`*0!-_;owD$u+G~c&?m7InYbIR$^-0#WuF4Iru$GPbLd6YLnkddfL>~ z%}9SwItz$RlHq22MvkEJJndqXS-`uw2tt<56J)7sMfGlEK1ZzmY z9w%1n;ycJ%ohi*3>?fK72kyDi$L10mlIK1PHv}rK}Nl2k_uHYcnu0*`8EC;ul1`5f-fJpOs1x)gZ{;TcoZIst8AijSP zVvYivn^!3a7ZU|tP%Jpe3%yMo8E7ig357Bh+z(#N0wY1h9FwIXLYbJxkOB*CE~s46 ztU-QI;6r7znlPqXUG|H0Cv?8yN~@&=RTx+>z?-5fN;E@^5RwjplzE4EeSour5oT2> zzWE~ESj)LV5@?=j=UIM=}5OVSofjjYE=8|=nG3&=CBxrv&rsT+* z{G#^Sx{z?rx4}U?`&TZc+vO*;Kjfa z-OWzG31EuSy?Z3+6?%|xs`f#5ii}p=BFBuUGoAK>T^s=H(sQx{S&?5g z(~4I@^BCvk{R@AO5MqM}olk7r&T1J;N`6NmQRPA! zrnYnY;FBBd0cgq{aexw<{kiBLY~2OW(O?(A*KIX?g1vu*Lw3wwLWkm#vZMHy3Kkue zq|941#&lWAvO*k-18Vd@_hIa>8@dSIFZOZ5gh`~7Hy)LEUHDenru}PX&CG@;rZi1< z;+=R}6Wx!-4dQH(U2c#vVw{bggb1526SZ3(1D23T-1oh=z(ferI1pP(xx~h0~s{#+Gyg;BN!kpPljAfP>7TRLjmXkz*YAbbGsW*q;k0${zfG#(?P zG{u~g=8(lc=zmoxZ4s)+ctUy~B+q~gDFLg5(nK{F9KIYVFT&~ii0ncyFYkSO_UQEG z59fc+zI}QB^x5gl2d5WkETYS%-l#E#XxNAo*8}>amHe1}CAEQ-0uOJ>EVb6+bZ$)_`!{0o zwC!$j4kqf+Ta7hZYx`=k8485JE+n}Yz&w9I&xzhqztyR%4e_c?DIZ$S(65A0*e3OQ z>TUOZcO!9{u4Rt4Sg#L2jnpMd_|-<>P+y*6yj?j?r!z3cb)Rvr>k6Pe+_Jl&Ic;(P zwDWXI)|Sx}c7NB$6S+ierTAMpn*O0$znkFpc(8Fxp;VKJ-?-7(_&<*LhdkosURr;n z!2|cyd%B~B0-zWV{Jub))JEk9iLaCCZOyW;UGlZdZ5P!Il63xdXR?2tSTNJ`yQsxF zGu1ET$c=VU7gU5G23R*Atw4r*ntfulEyn@NSrvG#iv(8N57LE6uzWuqI?t=!=R z%5lLhQI2SSUyKiKPT5Rab_W*&apjD|EGMo3AEsO_WDMEb$T$MvLXq)<6{CNu1d$P< z|3IgWsogX>Moq2$4^jK?N7S~%ehLflL4pvw3f_)sxLztmJbV~5oXHw_9k^%~E*$0& zvm{MaPOSZjI578o8v)<69mF;ZGi%-`@zUENw!x`&XbIy}4mJN@d%_1)!d=hb)adZUQ_6g&r=&cgbA@4EM!_Bp)Q z?)dBaigh{*&_;L~hz-gMv~v*G-JzNr6uP;zQFXMh+RYv-8b<%dMe%={Bkg)wy}>It zez#Pz@rh-yeM#`)v}n7C?p<2C8JXSYygh|@V$7z8!*f#A!J&kE(U!w*v#ZNBLBzwX z9mxLgF3vf#w1uc+9$AgEe1beFh<8g_P$-?|$Bd&&X~`L?5OCz=A4w?&*cGH^P&LRQ zP@bGSBjcpICjPbKYTbWXzf@Wwz>}b|jD?De9Z=mJ04#@MMfU~x>n&e5UTAj6m8jt{l z+Vji%598OMu3&Yk-Wd-&fHz>!Jj8Ux)||4f5=(fl5xC71M+<*5G(Or__b#5}HRiDL zl;X?5#~@4wS~VJ|#~@tH?;r7rvT?Rx;&(8t4I2=rqId9poMT+)BRQVOsVWWzqW+tB z7>`w2sN#UZrUJ4VNj-IMBzF%enJYLmp}1dW&LnY#Ts2H5gA?9H>$2x87UT*6SBJ7t z3FJoBZf4jI-XMP`Ub>HZgEUK{=1ADHVPbJcrx3R9crxM@_F&f!#SijIMWd_&2alDQ z#&1OLS@h-6(b3_pFWA$B0N8VN6|3w1v6wB(=&Qr8ghoCyL)YFVw2#YMOt5uP;0%0FwaD-$QcurYFz! z1E;$J{#}bKRV7T4Ja@ES%XCJm=<9dd4KGf!9AX*asyx5E|8c{x>UYwi3J@%M>oyGi zqgEgNIuTUAe?<8&oc~VtMab+719Yr05@wqmW5?b`(jK4T&Kg84Z&3z22547$>%4!ytBv3e*8gmb@vuepXd3AWS|0k27_&TJBl`zmrcF(CdW^asbb`VOpDP~; zw-$%utE3uXC>^kHL%h3(`4krz_w4uH2P;*5K(13m`z{%PC})&54eVN;eh=g7wGZs` z;8Eze47e4s>U}VxYnElt$^m3b9bKz4{QaPPsu$d5b_ zZ&7rLi7{cVKBqsnO$W`Gs2-4_P{4M9dv=Rgz;j^UYk*WWH(W@B-jFm%VUU)&Wb2yi zmdzzK^guJXWw)hrJqN6ofqec$aW6yhB#kJl&8zYcIk>AFOsk5>;<$XZhl_~~zcKnS zSY&@-+*FB79_;#V=^gxY7Z)3kz7}%HTi?M*YL##ATj7PIS${IxQ+){<%2ds=64BZQ zASb!5GzJ626+o8ND2d0w}d^Nv|ap z8(HA4N>87A4G^9t&Z+yg6BAoIdM&V}!MZ^u1#@oY+q4E zjie4c@_OBx@)L^eGhY_BUO+Xfsq#$Y4-HQj+jDlGVa zM;J99_@Ft7Cg55O@pErQ4!(Oio=AU)dfe-k9j&5ioXT_@%Osk|Dwp|qzS{lXc5Uyb zkcpS#F_8vK_Q9KL8bg}B^YkhM_{K|}2@>wu0KP+lsDU`Od7}p6EWL{JEQQBuBk&P8 z4`SDp@{B3UT%il9FbgEi0v*=}Cw}?2f3J@Ze}f_7KX{b*Z)c$Rw=>oTkU@VPug8`9 z(o((Q8euBbA|pLM7LSpFP^(MBe3lvWbq<|lSlzz~;G`;z|5BmUI|3O3LwU(06xd`R zO^I=(89NqKaw0^^-MWj-i`&s%HcQymh>cE00wfV^C;gOVA2p+AALXG z^=e{sPjSx02e@$bB0d%;;wyi|X}UxpAqe}4K~haa_u}S&pU{m{p7-w2Yu|KA z_!00jW%teZ2}y-phto!!3(Q6LBP9p?$+u7Fy=@e>$pXFdF2QZoanlXf>N$kDSx?!I zT+c3JC`EGHva*!(<|Q9-KH=p1`Q{}baz5kwSGr$jCE%al^XHAd3mkt`UDmND(dC2Q z;~*PBqyA7grdNK;Z+QLlp4qQl%^+N@1TOEL_^$O0-BjEg(etM`mN4dB7tqL>R(iA& zG&=&n7h`G`-}fAvbyV8ZDj`ShQLtrZ|W1MyhBDaDtbDo9r;#I(Zv&3NRysDPXy zHkChSa|e1C2c`mTva1ogee|9+LhH}`*I$KM&0AkE`tBBxEwz6+o`~B=yX%bJ_bu60 zo8-0Nsg-JN?*j23P%-J%3~8A3H@|DGKdSA+Ce_p0Ht>kOUoDjT97mA0<<0J-qf1*i z$P7Jkh9k~lIHGs&$@$}c$COxYjgSSD(JmRY57CpU5QGgZ7Jvgr$&MIAIm3J};8dz% z-n6;Tx)s;7LcxFdXO_1y=?l0T#OW--P}k@>o+u7-9;vackT=j?tzavB_0$_$(d)kw zlpWc)!j5GQId;UWn%(1-Rap@J0MBYHQ=KA5PL)Bh)2WxiUM$D2kud?bV;oQ8aVVyt z!-iQugeT{Z4PL>Ix5O_$|4;S_5|=!zCw8$N0E43J|3rULNFO=cCT+2^{AjV(n3AIR z;*)Qy(GQSK>XSa&ap@F9hz5wpZE!ihBMPNl!#f_TMU|AX#U+?mBZE1I>%>dwte{43 zB2d}V`TbmJB4(q z#)({jpLTzli6hE9<=od8!rFaL97gGYPdb5dCl+26Weh>!=!~Ixc%7B2v>q9lYz~$N zRlSw~x%U&G+nqgvXERQnNT*ik47_C0gfmS9G79WaUWg};AO34Fiob`)qaQdQ&^PX1 z9jW1TaupZWf&D(vqQ_63aiRbv@_05ci}rGwG3v8iTxa>~B$FZ0 zQmpgZ|8fhjee~>r12tL&Xk)IHit_#$ddqZqmSiKDnAIR9prQN(`@qc{kO~$2TR_DE zoh{-bQ4$Zb2PT4>!_N6r6G;%d*@5c_2n=b~a77}d28^1x2ImHpS2J+6N}cBgz-fUJ zw|9TZNT*p|h+>{q$;1W&n43$_0j-d|y{4Iw0tSdfYT%2xsfJ|43l+_Bh)TdMMIWK( zr_TnCJ5B$%W%7@oh^J={&rk0@JQH`HU!FfcySx<7&L5qL2TxDWA7l15?&sB;mwp>S z&|mRdVFI>nT)_o^hpwV%cnsJ9zgDby7NuM)2l$-JRIo~P6k~Qd)+C6h zmR@j=KHI`bDBw~a#c71EmwUZLk;-K;&&q;2f+udmc{BAH(kQFQh6o6cg-sFXAyq=st{^kGrKX3p3@awNh z|Mbtd{xG=x`>zkbJaXTWXfq=##&UlNqWgs1K}+vie%yXxChJ6#;c41y8pq1F+`M^t ziSH3b*Pn<3=X%wu8jQhOl8Tm5c+mmAtVk8!qcP|GxVbfwb2Poj8fFzEmWLT*05o8R z*bVaOu&yS~rsX7{Q<*;kd2L>!^_Y;oTZcy?Y8{1>WZMOWwEl2TFPo?Ggvn zDMW#u@<=iU08B+A4xq2O6NCBSE+?M_kx3V{A?jfu11p4iO~Z9}nzrA7S;Nt8fG;p` z1i@KbDL=`o34S4j15gwX9bbQ!2Y0b=uJ+Ed{Kmim5p}UOwTk}h!v;jO+3d7aMr^vi zw1|#_>VvzaiPr%GsIKH6aR7g*WD-wT(7S(L*vBR;%XbViz=ZL9Y+Ftl6y;%k zIb%@M)h;Vc@8jkZKWg6Xy)io>?|Z&I2b+V7-)r#no0pFb)qQZ+ht_iuCt*?rvh@eg z?jp{dNmg5n(nYT0i{Bj{4c4}D(V>;!{o$+Mf4!-pM;jU%`on22$yrlP;DGIoGRt;f zoP%d~fBCn6e{fgy{_B4~p>u<`wQemAF5F5u^-c9~>IaWZz5mba>;QfPc%i7A=UFwI z_YZiAp}1*>nr~p7-LMT!@tabGd#pM}YIyW56sTc)Lyj1W|B?$ z4q?0N9y@>J`(#V6;vyy$OEgi5dBN7S;;>EB0V>MzIl_3c zYgveyN--G{#j|387;H#mK)}QKCx+3etEz=K)oP_eEYu{H=|C)RAHo0JCU#~a-{>(| zMpTYTKka+z5^E8sPEys0TorY0HMk5;Tx_6-I6);PaH{v?Vwp(frLZX2tMoVg;Q_6O z*2VojVruhUJ{^CXBye|Y8)q}XnQo1O5tOe$_$}x}6px=jd?;#~T2|KUb}zmm>T_wT z-S(>8J}T$hi5=XiJJi4J)xW)E{YUbRH*EPPUQ~+?{qlcw@5|Nt+1k5jCrg#O%+;@b z+pT?jyV`o9Jm59+w6(Sfu>MOGk6$M%A7yX^dcp?z1Gb)ZtM$xlVw_~gni;U*)eSrt z?~EzlxNWeEh%W}LHU^JnuEq+2YusynmQLs?NYqSfyA*O_ z!OO{UGHKRKXXr$YW1clg$_7d2WEmG|%ptQz!p3iH;KIJrj17$BWAWz((u>rxcEL;rD-dtRi!CJ{P}pjbxvhdj;HNE-@&I z-vTjLa-#D7->2w_5+Sn4wc{Doe{0rz!^`GWwUpcC*z27^-bMc+ps!Zq=L(bSQQ7m z**KZNXb-`t!R$IEFD^<6zCawm$@xhJo|GkcXbjOxGwm&NHAP%beB9r>><`3zHOk|O z7^zfEW8=Ee$P<-hvv{mi$XL%wayA8{Ffl9Is|m17B?!yli2{J9oUzqpe}zL}BT|1g z$D3UPz|i?XOk^=1Wip>|yBxCPCvxo?S<^s7B35C0@e%ABTQ=s1izJY%mH0+U@HlW1 zFk={+D$MId-U_@V=Y!XLMSbkNp180PtvO zfosQrB7|*C$E`RafJm5TS;48pTugs9B{dr>zJKJ@4&){?C(FweX5Ie$N%GM)$4d0z zmw~uaIdGc;d+@;N2BP;=IX_SUMdV+&z1#vfkm)SaLuDx6;IUR zV)7}~kDU5ij^igom{&wh;#`f(j41P---GwXPxI2jZC=&xa-m9C{bHX?w=C+pQ(eqd zth+sr4c>x$R6>&u)rD#MP_cjCKf1`lhY}rTok(RL3f3u9!+VuWIgZPfnLo&LrM+;-d9PGf8nrYR~q+oQOXR#2>;R{|Mjw-;7C|TWudF z8lLGA*3U$3Ca|AK0%0)@nom*FF9G=PuJ=1ke2Ow3%d)k^z}eCBNq_|Il6P>soP#%! zZ*V`k2KSI>&`iF5o<4>QgSD4W<%@@Mq|D}eR}a1-(K3I*6+3@|12k}d6Suzb4$$rfSVy9QNhJjhD`!FubP%Zs?pfBGAui0DuWpDHcl{`d{>Is>d9N7+=kP$x5&M_gNo^m4sRCM(#_{#Lcm3F{=G1c1PWK&G!0CO{+?$(V zQEvTBa1IL6FaED>48fXF@c4oqr|sl#+9`juwae*_bHjgV{hIEsdBbd8@W5Wy$5z|R z{S2^eA%i2V@lT8u0{_w`jKsBB?5n7AX zJ1|DRgZ|-C=7oBxm45Mrn;tJB{aZwe!200)_I<5Fv;RZ=C#n-#o8h#lT^fR->zb+y z>T8-}iQRwOvTz2`=cM@5EcKc!*~D!yi_n$;_(1dy+EV=v#6jN|Y~7jjK#vX%56L^#gDM@yFv2Bv2GaVWB6b`Op8e*Cr49as1}9sYAp5=T)#A@hD$F0+ zFA+3N*5IBkDlE6pSI$`6UZXLVVdph^hdpi!BxVq zjfsEMc{wh1@G!e3_c3=I4aQHOj>lQEusH(8p-R`QO+**0X*%Eqs6RFh5sU@)HdUzW z8W53T$I%|uQg_jxK5^cQ-5s91s9J)1YBU8eB#b`W#q!>51|TpCKRPE=6YJ=RnMxzEwH`2_2Vp6Y?dbjJYa{V zFgFP<4VcEpfFDcaGhx?x9z!IW?=E=Q(Yy&r9Cd$o10ab8<}wTgq4$E@roASoEp~sI zXGi)AaHMA+dh~haq8cHssQLDGbb7Uen&zsQBLucSllUT#Z}$q!Wl3X>?Jlm5sD1ML zu$}0pImM}W{3v)2Vd7)N7Rjcf0(i9q9rVcsz&HZ)yU#{{MD~D9FlRfk+Qyrd5I`7t z4-EcLiM=oWZo>W?cgdRfAglmi(-VI}9PBNXWZds%+ZR@ewpxK+Xv|L>J>hy;Vt=#{e{lfmqJN zyUf+qOMTZ*@Xubo%|52Yx_W5}_|3cTxIT|BDc*&+<;ECKPP~4dAgx-{BI19Z*+~>! zNo3N4qu=ke=k|y2c0(EG7vr&rt@6kY1 znFZLdt-n-Xtc{VxOq%UfE z!3vyb&mC71yZ3VmPL z&riW1r$Hg~k9Vs))wv`At|Zb!sW+>&0)F@K2q5Ac9m^(1=31rk zG|Lw_j~F}}4V#OYt7%c@6{QDZPts+cp}!S^n_J(!Zp>+x#&E**^@K|#M!>phCXCK8 z0y!e)B3#M(CDTrLa0!2|n&GM;ruFpRy$D#zVGpkdV0uoRT$H%LHP>Ac~zMuHb*sMKiDz6E&$QJ%yUE zY!o3p9bhmTbV&C!J5dx(nZ2_5?w82S*ko0BbDHDRb&aAkWmKML2(Ljr5}@&`||SMw`Y$|DU$L2 z>9f<94^A(F(Tu1-nO7r32|a2MC5#PCC*mkf4k-QKu&2USvai)45aSeLcPECGO(K|u0rzCHCgL*5uB zY%XWa*e~80et+BZ=B3jU+F{Wh98NeQ-!!fZ{@RJ*0T)0m@ez)UiIZ(MyPv%s4#oGU z56|zPK06EE)MI2ig8lmshQ>@sl8}v(nAs(bU}1m2)411jVrzlkP1G{URzz7CA^`bU zjWwOD0$h;*vZ??Idnz(efg&~MJHlFv;ZOi7(HQa}T8;_0A~UQ77ziM+J}qhJ#5rMO z8g;FH2l&`}!dVSzD6m{zZ$jhLH%SpFQIOSr9jB9%L`}=Af3FH+1k{69m$Ggv2j#7 z$09i7Q|k4{wan{llP2RlBLKo=yiJ`Qm*#AA9}L=6%gbQ^G%=F|GJA4n9a z?S7Q0!(@aXP&#;$$}p)Sa{7(rbssKq;O!5XInYt{)%GY(*KCmqm0xN@I5xDEstg;t z${=cg9bk|Kv^gAZYGPu`%pe>UOH4ul;62bIjT1LhYu#v55#``UGZJo=jc|`cx!Jzl zDmUAEO}6Gm5CEg%1rBse#n$YsQ^>2yY}l;N_DsVG(0TL5Y7Ch?*g*OE=&_1F{Pnrj z>W+6rCoeG9u|{k8^!g1lPiXyui9MbjeXN#>MrHpc>JZYL#l0V zb5u1kbpMa;?zwckG;=eLtNVD;3;PU)v+)&0Nw1v%gX@&R*IxTpei3>rui^qQxgiS@ zsoL6m;wO_H<#?e!^lOP(E0^fC{c`=WdqLef7TCK!FmgBkO5aCajl3kn@MK;DT zEE=%41eX__AVa%Q*PLZJAEuf2Zf%PD{zgJx228z^v z5RJEN)_sUv^Vk`mq-S#WodWpS$tsnLczj21J{uAlj=Bh)LT*$zeRC_l9}h@>6M-k} zU~o_>xi}ac;1N3*9B{TbjPx2DP$of$<648ctd&B?jifE+Wi|v8v!WU1#2y~+ejW2G zTXQ)AuqZI0jT2cElnGCwAze4(y?&h4f(OHROlXXIN=d=LN-OqCuW+<|Fz==5-4mYR>(M8ROdtq5)1 z+L)ZrWXhrV2SuHz6^Hh6!i(8@(8-zrW(6pqZSvzR1=9g$>9Y}P;6dR#&Vy5SRlus) z%*EtyFo}VNf+yJ&z=N*m3gUCP`4rRCF?t#MZtJv@Bi?$z={Cv_!0&B;_@sTjx%w{8 z9vvOsx()sVFt&*r#|sQx{pH{O-6AD?RYEbkUYH+$mAZ#JOJ6jyP}@X8uH$WwP2I|9(P^9-HCCS8)Q|doKS#>i zh8sxoU&y{hTKJt(Ik($D@jX<;x8DaFZ0<$Ty|bj#!|7rDC}LToH~xaUk_1 z0jLt8S2LJ99UXbEvUtKN(<3Bw$n%>-ZjLg43*knu(B34Q_69qNHGT)Jl8tx+x9(T! zTOQhdjnb?aumh2RYPz_lbVhVg?Ct8N>)Rq%1~So(1`T(Tm}*F@SKD=c`TYy=adUYe zHUIW&KM%lX46=D)b6>xg($9LV(MoAm0(V1~uLwp8DLuz!}DS<}mzAw>5ha zn%g_^7M*EEZRmUAD*jT*yo6X@G9!&v7SaYEy`7kg?Hj!r9^+ZI6psPufksE~)M#bi zIf3XZU7SBkY{^ox-U!h8xfPt_Kor%;#DijlI1q|{&GUnQmrC@sjoetW+MXc48;lxA zH3U1*$|~$F0zJ;-*&IB!3G^&ap#6-0O=!bm$J;1+_b3|!zLrnH2Y~kGVV1pyfT!_mq3;f3;nyb!CsP}g{Z*kS z{joR^U)|}z2edi3d~pAk{bI9QYhO2eUL6uDh*s6r=r>Ui@9%dEzd;qEx}%lh%tae_`kXgVa=V017|L^rd_D? zr)m}e;`b|PKxAFk2ZDp&>R5T}TWG@NtpfvfaID}M-c{g`;6osywh!zqn;Jy}Mu%~> zRNXXxXq&P460Y@bJ^76U@rJQsK-_L?RU;4AD>Hy~mw`EO*FLe5`RpaZqSPuP4#a0j zsyeKW52@{dA%k-_owLC^tsWA^8s;tBy0a^lnv~O_LnJN~T4 zsX;Lm4k$akX!WZCCBFRntHYz=tuH{yv2FzQx2*wI*;)rc`B7BG>=V_c^LI(3EJ4IMy0ha+FQR< z+qSxwMI^{vxLGrtvWAPX33iZSsh4T&BcAI0Cr)S#1QRGAtZBy-3Vkg(-8y1vtL@tF zNswZpA|lQVbbla(?<6{PZR%#!hnhO_Xxj9Im-HF54ygf#HyH>Ap|pfL3CTae_s%Y#hFsoFip+Fo+QCeqfY*q5Jhdt?UMvBNB%7Ks6y)=hL;G%$KG0NU zIVvArL*=fvyLa-7zY#Sbg>XWWLr}X1woor^a4YRcZ#!v+!`sp%9$c57m zj3=lK{DKU(H*b7vD&4Te-;hmz4sizFygVhZ0K9sp(SL$Q^Ee&HOPL((mL-J#Yvu~E zE^-6Wo*!hdDN?*XH{?axEhmYd?7EIy(~*R5IBhx~&jM-E`2<7OHrOi-PqA(fYlsl7 zMc4D-ZOygI6t+2U(HkweUptv#9d?R+s7i+^xl zEX|bkq{Y%>x2?YSdaWIt7f$#AWAF8PAvbG(GSll-TBtGytS>!;EnJ>-*q}XJ?)eEFk=kh>7zUToC1?r{eBa?Z4i$@fh%~@av14h{jl3(KCm2Chx@W-Z+^9G zCBKnfUh+6@Fj}6kQn$2o-Ix&Q%X^yZy|goqt$f5bZMKbhZJM}$y{wM|2@uZvxNZUc z!R)wz%@H)1&Xxpk@3O}0diBk24F(zb!sbZ1TqCEZQ@XLTTqop(5X|4%O!R7x+a`Wj zcV>67Ubmg~)^%$qJis8g4Uk|hF{Jkg;~Kzknv!wiUKDmM%DPWVt#pl4o;?CfIfNjQ*f9unmo8m zPMsQSIZJior*a_9Q%=fd0uY?QVm%V*Igr!JkGFM$RLuOHz5pQ*G8Vy-_^~L~RrJAK za9zCwowUp+qL=03K#vboKR^o*l8YniBQ6N>oDc5O!f_zL-$oD#EY)4w@TH9Nn)aW_ znzzwph#eSz5QjojY}(uhcm22$3CJnfJf{l4cxZ1|w~aB;N5)8X`t1YPBLZUj5g%(x8; zWv;<$$>8eF-kIBFeYhF4MhnbvJfdqA&*mlAATbPoJD1mR*d+k^qe~qk$QzI$;on0F z&BqL2ZnU?Cm7f4yc2&R~1^8JVa*D~h0Em$1D3WXzk8ws-I)>4ziMagk`9~Mn^97Z+ z@!N)kd@eEwTj%TlQHT6M8M<8TetTmW-^_M-#s{XyWP1o0CnyzW4fWX}KVA}6k}mX( zLxk#oZ!?6V)|8u*f-d4}aR6=zdIKA&MQscBAdT|?GP5RF{WKrX<12;L?IYD_pmDS3 zvUn-e6^%(ee0m9u!9V{G`_BjT&(LVy!LA+onvS=h%7J^`HBz_P2Tj*K5Mh5iG~I#} zJ#LQHy9Z9%u{v=hdG2?A`0DpxA07=hHukK4Lt|h3u1iagHncQsw$xtQ+&0REb9ZH) zP`+^9Eo`7w+b)8kWlamspjN}#9Vo2-bl}#TmXA9x(%PsRBig}c6gnr~kXkJ<1Lv;$ zAlY%60==y-Z4)26;Rjmpg5?a;Pslb_n~0IT3?EaE%`<;AH?QyOHtNxNYipV~Ju{$x zb+LhV-Q5n&uN(ERz@#{_G@5ZPD5d#plt0#03rr zk;!O4ov_PT0Qd$|$RNWA*fqcdwYCd92shOP5U9scqw`B6fZBox0F$l749HzNT@lz4 z($cObM5X0$GFX!?{iLC{Vi1{;Gb848aa4*4J~DuUGm@Fo^iSSi5AtF|fTzl}g? z;y|TWah|0*`3OM^bwoy^LEaJO8PUt*r{B0kA+6aprpho`f_=eM*yC6OIV19ad8$&HWp=wKx?8h`9qs3n2veCSFK=%4209*K}__eF%k< z(%Fa$;gfhYn&LXPN&HsKr+`wFtmRB_eK~=Z#3a;|OUy-=sG;WugnA|}alzPR2&h7L z#ykCDsjv1SV7w$CIABEEGE0kp7!X{hnFch|Nz!7JtBX}Srfn?eD$eUrZFVXaTusws z$UY6o1_tC!EaCzprH6DH^cW+!gLE|T@RT`bmw^~eI6Ac@{%DcX;#7Qjc=S6_sBwl- z!{`sMZ(sx~F7dI7wCgif}mYg&>A2t-Jv4ETMhZtMMuGj_EiPqYeu9d#UaxDx{n z!d6@&U3VSd5e?);YD6TAq8XezWE=Y{3}PC^UhV$ylNH_n~Ed4qcMbZ+QCgcCN^ z&Qq2)&O<|<4s#0|A!uqtd#^Y&jn|$1A6o!uOfsb4#Ma`^tc9NmHyFmBX$*N^GHteW zQkF-hlYehFsdk(89Jy8_LEJjJ^Q&|pVy~fq^8S0$@1rY!IofABJSP~W$nB!L zg`2^HQ7;W9L$k;RWQsu0r(CG#Y5bQ;y8~+q)+`EPTjJoriIdV34z>z~MGsYxt>q{r zQylaUJb*0CC$5$!(!I5I-Wc(R~0+BRGmcxt8Iyl=MgCV|oO}pZ>6VmN>9A4O5=mbBxInZ-jMKm7a2Qsw48m}sTuD@ftW`9>A%*Z!MMjBqvY9?l}+3~8GwQQAhLIsHh-h^MP#kv_)z}q$#m+# zIB=zJdsfRnK?|tlTz3 zR(JH^@2BT~!^?}lQGI~A!FFT-$Zg_#lV<`^T#a7FdMU((mRUi=lZh-%R*Y=}dXc1B zq>lb{nJp1KcA|At{t%D@Cv{9$=reBuA>6ZDz>ob3T>HDb_hWcIt0OS!E@N=j_S#!M3&NO!f@k`0}0E2YW8i)(y5&W8{BRar;3T?B_-pd zU%~Sps+l(V2m6Td5A=p;=p(LNjgq*S)1PJ~H+a@a!fXP4(^w^mOckX5qj(bsM_8X* zLjDIII81Gzg)yQ1JP1OKyhYAai24O3SC*R?&x=H+M$dTmMlP0#Iu?&){#um?Mj$Sw zyd1!PDDz3QlsQZ~%h@4=au?PWmiwhWf3Ljwdt}7hv;KYDmuPQKvkyU904gaWFYfw2 zcW&<{u}yvKM2vZ=!E#fkTeMGiN^?ucst)Rj$1GrX@WSkzbgAo;*p4CdI`G>j42uvh z(XN2#mhF(1zgEc74;hqKTgSD?q`SoCO|x--Rji4vLoJ@gqs4nu--HhcN!sBOh2rnF zf)f4s-mLe8{MnA%$*`XLC-BI)?~lH3XwE0^wG#vnHy)t&W8;Kv2Iy_68{q6`Ci1f7 zmUfG{eC*34gZCDK`DUVP(s8l{eilEjneI=$Pwg5Ob`j|-8bTxSW251pdY|HWqHG%J-*n*zswDU_ zIE-rYQ}5Fm{SxsnY+jATj{wR#QmLB8*yL-qiu9kh&<}H29%zJXZ0~w5%OcW$KiHBN zxk5X95tjFS--a!2c1u-##1Pe<;ua&P!Pe0}ZN)GroN_=tZ;Yl3+=dx978tB_n>d*^!g73ep5ho||gkS4-3Lc@YKD0Xel$!H?SRb`xL z0d5&nzR)tT{l?g?Yer7ZXc?;rYqs`%nj}JA$v8nmVQ+!ok4%!tl&W8U38FEE#v2M_ zezBeNGx<~RQ}pO|2>{$p{DQzJ&Zh}w=qUW^5^_)^gCZb_VVMS^%&Vfj&hm1; z63axE(=1hhL%6MFV0HG)#ypaJ7T^awEpa0`3&dW+B=-3LM$>)yVqC`p5<&^V0 zt7h}8BAt%wp-GAtO4*TO5|y~jI4ig|?C`}z%{QqLYHpq~5vfv>;?R3Ajn4rnzho+B z3Xgi3=?5B&8DmK&&|3gGxdIJ3@|V)lVVGx{)`h2q9_j$V^ID023sC=xyXRQcWJM6) z$Wb1T{m1uH;XY>Y+b!@=<)yG8wiH>*&bNyyDPy=soOXtu_rk$RE`Is>KQNaA*C4LJCcyXxVK^mm8iJe|R7%S=+4H5OSsRWgY%Q{j19sw9bL=)K%~ z`s^GNoRN{`J~VLlW|?F;q+&X~|35%x`07x615Uv*iD&36Y8;CVPxNG|QaV!@P>-8) zNdgHQvwGh=x%d3C|5I;XmdoOJI82nx)5C=x=;1h94AF~!8a;e6o{oZO0cqgbqb0Z*|QCg}QqRoz~B2ED> zz}T4hPUgjb0cSZPbKoBi#a%gmeJ%3|z_TuvvW!P@0>RthXH=Ci7bsh(Qm}JHA>?EN zEfXQtugl?!^!6dRgIuY+6bk(*^c@GHAoIUeiq>-~3v`W!PZYggzq>UalY{`5VHeXW+m+~N(>NliJ(^z?dc)0z&%JV&ko!$~7L!xBJqe}B0w@@0W*1)c*+rNCj_FN~hZG2(4V!8nP3 zE->xHU}^KSTT4CF*{sIP?0@<7Q?x(H{vdN-)S0_M61c8t*baKXHD~Je6aVWo7Aw@Z zd2xP*B4Ylh<5i}YCH84ONpg~zuqSEV`9`$CMWr#(O@Kolw5#eWN6`CDd>?|#A$Q8J z?xj1chPGKvprccsO_|J)?os9Lj&QtxqbXIm15I)tW%fwF`#xA>VlMJ!c`#B>0^5d1 zCV~A7YOCd?Bqb^E<9zBy@Fob*H8<&!PLvh#T(x!lE0PU@bfdjxw{K3pus)e2BJ7g^ z=`C;MU>-o5>|WY-Wzw{F;c{qGfgjfpKp9_R2KJ+sBXyiFI2~_}Vw@#HbjabY3ph$) z4CP)Gl|pKMehS_2>P9|4Va#FwN3H$!S|1)WuIJZ$&!EHyg9Xthq6e&hi~AbyNddbQ z+50dr%ollGczp1mBoBEE;b~4kjis^L$LQZYD-W(YW*r z)&5c!(9h|WgYfum=Qcclr43tWLx6b)=1ph97weOnm_?qIh)yx3wbaX%#E<|i*Wut# zp)dNoa-Nt%7vuTrNZr0IkyMCv0!`|#|LcD%37t|BJ4N5YxkUeX!Nk$O?|b@g-ySJk z`D7QY=7ljF2*Wm=i9tbFnR@R<*0T~%xgZUK(gMY&VhuZG4*@%Wm?`eWs}F4pHF46@ z(^JY*W#?2z5jD@J4wvLZa%LS9S_{b`h)ryUvux|MV%#nG$>MRsj0BpvMq=W3dsyf_ zqzKsQY_*V0K#hWVZZ`}z$=>%36jVBvy{<8r5yrU&Nj8&Rur7uU@8ighNbAd$yK|0qB69e9(GTjo}OZt-@YyP_Cha_XimZ*%QB4<4f*A?i{?`ZWvySHOisC*1{08O z+AnFliGOk3UP;2JZScSM6>{HK$bDZS_kD%j{tCHW#c;1y1Gl>bZeN+(4W(?u4_^9u)okAvv$gZG zxgLR^?H$X1)BcjG(_XFa>`fG$J^b+QHnnDd<`T1OD$K4cA-kbO?7OcFyQVPg+PbeH z^QdxLQ|%oUfxSle>+8TaOS$%yc6~<`UBe5CDz$D|$JJ>h{j%|<=%p>R_K!ZLI)vCv zig2|*vbC}}uhYdli7J013j7+7h}f9ehimqtVE^xLG?13>X58ZIg@1PeQZT zrO$5{^V*Z(9?%`>neiJz*X+VuiIvd)CBIG>*;dAz8(G+!nok=`{E1W4uQgd)$GB}d zLjhda&6%-?1;C1JGYweubkJ5I$ie8Fhc8}Rr~~`m1s*P$Yc#Z;rit7Np$-Ek9{ga? zq~>;i2d0K+(HJpAXjb=ldRiOdo`1&HMY8*94R?1*svaxYB8y*xNbWpr@~UF(`6-x|+5!|3Lix zLB!k|Z^Y;FCx!4Wg!Lpwj@QPc+8GkMoz)qC_m|J_l-sMyRci0F5$Y9n-F=(yI7#S- zwQS|KB{Pqb11`&7&P9m-#cbu9XD^C;X$lmjj5UOirv!}}3`8&WIH^{FeX41Zi2CVl z?`QFg)mf2DP~;F%kHJVlVmto&>HRMrQ0JURAN76ziw7ZT4Bht4GmgL`UBk+I4oZ=K zN)LP^0jke5>SP!at{UH|r^(o4r78CgHkDBL8F=>bc}=6Wb-Lhb*P`|8lf|ZIU5mE4 z3XeG{zw24a_Gv%;v)nXIdS%^?D_zxPtOPdJ@E_e85-Jt9*}uU((_J>gS4H@ikzMyF z1~uI6_tf50rzH{gRbHvb8TjAC(%8L!a_x>O4+{}ve|Y|MuVaj=s11GJO(-{<$>^%Lx$u=wC zl=o;AJbGN?G%^F*3v2|@>HO_I^=||9Z@oW$_?rR#*ZK3kd+P3;fx7!~_s_q7qhI4M zrKKaP|23)nNH?=-Oa#`8xGpQ$z5Uf?VEMS$J*UG4y?n*3bvVEb%XG$m*2+r zgpL+XV{Pjt+cdrQy3mW9%1@D0+J9;zc;bPw+}RaU3~^n$JYU;^88>pQTSXe14+MAg zpnZ#M_4F}94EMSR_HWtThHGbk^gb6T=QZ!JC(5-&q=Tt$y+YxAdZ|D3WZPEOpv(hpm5qQm8amaPGgG z))u#(b{20Qusj;@nPvsqW*y^b#I+@^r;Sp{GFE%U{!-1+VEuu5*Borki>Ny}qkx@2DfGkTlaFrKSV}@ZGC;~P?PDG_@f<=B;nAhEZommX!K6~I6_|{EU z)roZNKLJT$XHgR(DaQQW9_hM8NH>IaNJyts#u3uQt=bCQx_eF(i|+F6GpfW zdvUndjxO1ONT$$9rY`5=;7dw|esmM~Sz*jeqf6onfnX4bJpV|A>mc*R(g}YbDBleT zN0KIZPgNwI%G>RKz0S@vB$#z>IhJa%CH-%KPRVq|tao%rOek&U8vfpQrOD52mM%YR zwBdJEKMj*Jf-0HF@Pdpg|JdrG7llFMmJ}l8e+Jb-336Ggv-Z!^@9Y|O&Jz9FdXWYK zr){*>%b~$*DS2qpu#nQm4n1C_8$@UmuLrV_l@E=Dl*k6=P6U_swCDD)r=ifTF3&IpfFIU7NFyl^8!y>akr;P zY><~8sc&&5BV~;$Vkea;fDIuO3H}#>3gC@xvKwW81liON%8(#~?CJ2V(Ajv-X^iR= zSHNgAIym)7ga-pZ`u?4RQ(9a|0rrjEmxxHd$didWJ%0S`&Ychc9qX7>^MyfjB-UiO zNJ=W^txQqmR44r;d%$at4T|FJypO1o8tp?4(V+Y@+!8L?QlOvKph!_dNok_KFpNXl z@QLDoPm#ttu)V}!N4zRn5|^q;*A!=0b6zY`fwMf#XQ=HLIRKrHjWb%Od79>z959YU zjSa;qEB^2zgq=&7(L#0l3{TmkINF?p7kz%>{6&%$-$8QT#_YV_RK0hQwkLUe_j&3l zk@G)Mma%_sSa#-rhmWZr@tkBqT15fo9h+c(1>FAa<|YtXHndhaaQ5HWIvo5&&j&cV z5+RcpobJ4tj3zZnHghuCmUAPLqW~U*T{g>L3O>g!)U4UeF*Vds7U#O-Z=}Y14L49j z4fAP}5({wr`2GNpG6$pUQRC{4_P36xaqVI5r&SWVt~oO?HLh~W8ft7wS^V3=XPG@k}fUv%QMj-A$Ax;&> zR9KTYOQN<8>=k+O7s+fcV0cnG1c-gyg%E}U<~1U&1ch`1R}QJ!#$MdFQXIZ3MD2E_ z5YWFBJleLq`1s4$*VlZH&uhBAZ|qDRfBBlP^U-yv2|Vb#alf)Y8(L!|iqHi~;agji zVxRxD_RWrDbW^k8jCY@Z@PLvXnK4m=NTTgptH~uGmy z-)y&S8gs+IkpN(pCGz`u7x~6fb2W*gMGb`n8O-POR!rY&K6^1>oYgfu5m}%GC z#ZK(Di?{Tb_3YxNOX$g?o1~`qXl+T&wa->e&EvO>NKfb}8~2TEtq3vyCY)6L)DRZZ zTI)5nkbBC6lV7EnzFj@O31&gdsb_mWgo^rUxdD>ud`eMHKM>Eq-Z<&hKzHfvrtu( zoh6)*8Y;xIzIANdB5L?4yJLbfM%VRvynVx|FB=8G#@xt578&_Q=Vqhc+wU!dHIkJ} zm-a%H%{g~wd#A6ZMuHHyED6HuIxmODnX-`!e3&RDz+Do5yWCS;t8=Z~*A+*>58VJ0 z?xyD2`qWrDxB-jF+c(xrcBNhH9p7>6>9uLOH-hf)^*uTlbWu) z)>=*WKVX&q7XBBo-0CoMCkhTV}5(tLc*pwHXbZ_rwm zXnqqe))qCJ;#Pa2R&R)wCN&`{$!2Q8);B{?Obz6Tbs>=(Vz-OwHGI$keR^igwDGKH^OW771B8jOAD#x)q* z@wGL7m_j9ajG0p{qAyLd|9@D_rhDqTZut&s z*wAnV8-+aKDcRLZ;i-92vgG$TO=eU(xRaWHGhkt;SQ53QB&8Jtjr4I%NwkG4x6Mk? z6F#hD*C2{EHCMW)n3}-Ly5p{CQFEnxim4&#=7#8LP_sc4?V_e^$fG+)ybv|df%|c# zm7*u!(MmlB^6u5BA*|kaNX@n78=P=L626JZ1w<$5q7oqBEvdm1f(v{@)8nb(fJk+J zB}tT?xUqE#sgaA5iZ8FOBvDNHksIZH1pBtBH7drtf727G$!1bP)b5{s##g>d+Gv{^ zxJj?(5o(69wZgz(6lRgsi>pO~+rnTE$-%zn8gHx=3&ZS|FQIJ$yX}hR^L}b}h+3tR z&^rgNM%1{%YTHrcn%@{j5jEG0p}m=Zd1+B&5yG~l#x}pX#S&^fg7sA*7bta$lFD`s zx{j&ouTH#1XV_e}_?nVvH>Uc=%oBbnDrmTqs^__%N8;U<7kjXMlvplr;A-&HY_oMX z?wcEvL_HStw$#uQ?}(Z$0vCGj@SCG&WA*KISRH+3xp%e-G{NAv@(A%0D6D{gM{ZQU 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%0Dk!p=(_dR9*24BdcIZjD4D0UrY< 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 M1uq7@Nd*7^0O0a=hX4Qo diff --git a/docs/deploy/sre-agent/latest/azuredeploy.json b/docs/deploy/sre-agent/latest/azuredeploy.json index 4b6a6d0eb..4b6d42abf 100644 --- a/docs/deploy/sre-agent/latest/azuredeploy.json +++ b/docs/deploy/sre-agent/latest/azuredeploy.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "2403415415579441400" + "templateHash": "9242331632702473420" } }, "parameters": { @@ -67,13 +67,13 @@ }, "accessLevel": { "type": "string", - "defaultValue": "High", + "defaultValue": "Low", "allowedValues": [ "Low", "High" ], "metadata": { - "description": "Agent access level." + "description": "Agent access level. Low (read-only) is recommended for reporting and analysis without modification risk." } }, "actionMode": { @@ -137,9 +137,9 @@ }, "enableSubscriptionReaderRole": { "type": "bool", - "defaultValue": true, + "defaultValue": false, "metadata": { - "description": "Assign Reader on the deployment subscription to the agent managed identity." + "description": "Assign Reader on the deployment subscription to the agent managed identity. Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups." } }, "recipePackageUri": { @@ -149,6 +149,13 @@ "description": "Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI." } }, + "recipePackageSha256": { + "type": "string", + "defaultValue": "bc87901a7090d36feb7d80664d57fc9bfa09056eed316fbf5458855b9de97662", + "metadata": { + "description": "SHA256 hash of the recipe package for integrity verification." + } + }, "forceUpdateTag": { "type": "string", "defaultValue": "[utcNow()]", @@ -165,6 +172,17 @@ "metadata": { "description": "Azure resource tags." } + }, + "deployerPrincipalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "User", + "ServicePrincipal" + ], + "metadata": { + "description": "Principal type of the deployer." + } } }, "variables": { @@ -252,6 +270,9 @@ "experimentalSettings": { "value": "[parameters('experimentalSettings')]" }, + "deployerPrincipalType": { + "value": "[parameters('deployerPrincipalType')]" + }, "tags": { "value": "[parameters('tags')]" } @@ -263,7 +284,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "11748842726639098374" + "templateHash": "400180081712866601" } }, "parameters": { @@ -333,6 +354,17 @@ "description": "Agent experimental settings." } }, + "deployerPrincipalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "User", + "ServicePrincipal" + ], + "metadata": { + "description": "Principal type of the deployer." + } + }, "tags": { "type": "object", "defaultValue": {}, @@ -500,6 +532,9 @@ "experimentalSettings": { "value": "[parameters('experimentalSettings')]" }, + "deployerPrincipalType": { + "value": "[parameters('deployerPrincipalType')]" + }, "tags": { "value": "[parameters('tags')]" } @@ -511,7 +546,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "6562535881153200016" + "templateHash": "2881433815087416423" } }, "parameters": { @@ -599,6 +634,17 @@ "metadata": { "description": "Azure resource tags." } + }, + "deployerPrincipalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "User", + "ServicePrincipal" + ], + "metadata": { + "description": "Principal type of the deployer." + } } }, "variables": { @@ -648,7 +694,7 @@ "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", "principalId": "[deployer().objectId]", - "principalType": "User" + "principalType": "[parameters('deployerPrincipalType')]" }, "dependsOn": [ "[resourceId('Microsoft.App/agents', parameters('agentName'))]" @@ -906,6 +952,9 @@ "recipePackageUri": { "value": "[parameters('recipePackageUri')]" }, + "recipePackageSha256": { + "value": "[parameters('recipePackageSha256')]" + }, "kustoConnectorUri": { "value": "[parameters('finopsHubKustoConnectorUri')]" }, @@ -923,7 +972,7 @@ "_generator": { "name": "bicep", "version": "0.40.2.10011", - "templateHash": "5168893811325309322" + "templateHash": "5025769957758856658" } }, "parameters": { @@ -957,6 +1006,12 @@ "description": "Public URI for the generated SRE Agent recipe package." } }, + "recipePackageSha256": { + "type": "string", + "metadata": { + "description": "SHA256 hash of the recipe package for integrity verification." + } + }, "kustoConnectorUri": { "type": "string", "defaultValue": "", @@ -979,7 +1034,7 @@ } }, "variables": { - "$fxv#0": "# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n\n$ErrorActionPreference = 'Stop'\n\nfunction Get-RequiredEnv($Name) {\n $value = [Environment]::GetEnvironmentVariable($Name)\n if ([string]::IsNullOrWhiteSpace($value)) {\n throw \"Missing required environment variable: $Name\"\n }\n return $value\n}\n\nfunction Get-OptionalEnv($Name) {\n return [Environment]::GetEnvironmentVariable($Name)\n}\n\nfunction ConvertTo-BodyJson($Value) {\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\n}\n\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\n foreach ($name in $Names) {\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\n return $Object.$name\n }\n }\n return $Default\n}\n\nfunction Get-HttpStatusCode($Exception) {\n if ($Exception.Response -and $Exception.Response.StatusCode) {\n return [int]$Exception.Response.StatusCode\n }\n return $null\n}\n\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\n try {\n return & $Action\n }\n catch {\n $statusCode = Get-HttpStatusCode $_.Exception\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\n throw\n }\n if ($attempt -eq $MaxAttempts) {\n throw\n }\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\n Start-Sleep -Seconds $DelaySeconds\n }\n }\n}\n\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\n $headers = @{\n Authorization = \"Bearer $Token\"\n 'Content-Type' = 'application/json'\n }\n $parameters = @{\n Method = $Method\n Uri = $Uri\n Headers = $headers\n }\n if ($null -ne $Body) {\n $parameters.Body = ConvertTo-BodyJson $Body\n }\n return Invoke-RestMethod @parameters\n}\n\nfunction Get-KnowledgeSourceName([string]$FileName) {\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\n $name = $name -replace '-+', '-'\n return $name.Trim('-')\n}\n\nfunction Get-Collection($Value) {\n if ($null -eq $Value) {\n return @()\n }\n return @($Value)\n}\n\nfunction Convert-TokenToString($Token) {\n if ($Token -is [Security.SecureString]) {\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\n try {\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\n }\n finally {\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\n }\n }\n return [string]$Token\n}\n\nfunction Get-ArmAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\n}\n\nfunction Get-SreAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\n}\n\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\n$agentName = Get-RequiredEnv 'agentName'\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\n$armApiVersion = '2025-05-01-preview'\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\n\nWrite-Output 'Connecting with deployment script managed identity...'\nConnect-AzAccount -Identity | Out-Null\nSet-AzContext -Subscription $subscriptionId | Out-Null\n\n$workRoot = Join-Path $env:TEMP 'sre-agent-recipe'\n$zipPath = Join-Path $env:TEMP 'sre-agent-recipe.zip'\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\n\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\nInvoke-WithRetry -Label 'download recipe package' -Action {\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\n} | Out-Null\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\n\n$extrasPath = Join-Path $workRoot 'extras.json'\nif (-not (Test-Path $extrasPath)) {\n throw \"Recipe package did not contain extras.json\"\n}\n\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\nWrite-Output \"Loaded recipe package from $extrasPath\"\n\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\n $extras.connectors = @(\n Get-Collection $extras.connectors | Where-Object {\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\n $type -ine 'Kusto'\n }\n )\n}\nelse {\n foreach ($connector in Get-Collection $extras.connectors) {\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\n if ($type -ieq 'Kusto') {\n $connector.properties.dataSource = $kustoConnectorUri\n if (-not $connector.properties.PSObject.Properties['identity']) {\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n }\n }\n}\n\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\n } | Out-Null\n Write-Output \" ARM PUT connectors/${Name}: ok\"\n}\n\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\n $uri = \"$agentEndpoint$Path\"\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\n }\n}\n\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\n $encodedName = [Uri]::EscapeDataString($Name)\n $body = @{\n name = $Name\n type = $Type\n tags = @()\n properties = $Properties\n }\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\n Write-Output \" PUT $Kind/${Name}: ok\"\n}\n\nWrite-Output 'Step 1/7: Applying connectors...'\nforeach ($connector in Get-Collection $extras.connectors) {\n $name = [string]$connector.name\n $properties = $connector.properties\n if (-not $properties.PSObject.Properties['identity']) {\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\n}\n\nWrite-Output 'Step 2/7: Configuring built-in tools...'\n$overrides = Get-Collection $extras.builtInTools.overrides\nif ($overrides.Count -gt 0) {\n $body = @{\n overrides = @($overrides | ForEach-Object {\n @{\n name = $_.name\n enabled = [bool]$_.enabled\n }\n })\n }\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\n}\n\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\nforeach ($item in Get-Collection $extras.knowledgeItems) {\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\n $body = @{\n properties = @{\n dataConnectorType = 'KnowledgeFile'\n dataSource = $sourceName\n extendedProperties = @{\n displayName = [string]$item.name\n fileName = [string]$item.name\n fileContent = [Convert]::ToBase64String($bytes)\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\n }\n }\n }\n Invoke-ArmPutConnector -Name $sourceName -Body $body\n Start-Sleep -Seconds 5\n}\n\nWrite-Output 'Step 4/7: Applying tools...'\nforeach ($tool in Get-Collection $extras.tools) {\n $name = [string]$tool.metadata.name\n $properties = $tool.spec\n if ($properties.type -eq 'PythonTool') {\n $properties.type = 'PythonFunctionTool'\n }\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\n}\n\nWrite-Output 'Step 5/7: Applying skills...'\nforeach ($skill in Get-Collection $extras.skills) {\n $name = [string]$skill.metadata.name\n $tools = @()\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\n $tools = Get-Collection $skill.metadata.spec.tools\n }\n $properties = @{\n name = $name\n description = [string](Get-PropertyValue $skill.metadata @('description'))\n tools = $tools\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\n additionalFiles = @()\n }\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\n}\n\nWrite-Output 'Step 6/7: Applying subagents...'\nforeach ($subagent in Get-Collection $extras.subagents) {\n $name = [string]$subagent.metadata.name\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\n}\n\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\n$scheduledTasks = Get-Collection $extras.scheduledTasks\nif ($scheduledTasks.Count -gt 0) {\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\n if ($match.id) {\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\n Write-Output \" deleted existing scheduledtasks/$name\"\n }\n }\n }\n\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n $spec = $task.spec\n $properties = @{\n name = [string](Get-PropertyValue $spec @('name') $name)\n description = [string](Get-PropertyValue $spec @('description'))\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\n agent = [string](Get-PropertyValue $spec @('agent'))\n }\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\n }\n}\n\nWrite-Output 'SRE Agent extras complete.'\n", + "$fxv#0": "# Copyright (c) Microsoft Corporation.\r\n# Licensed under the MIT License.\r\n\r\n$ErrorActionPreference = 'Stop'\r\n\r\nfunction Get-RequiredEnv($Name) {\r\n $value = [Environment]::GetEnvironmentVariable($Name)\r\n if ([string]::IsNullOrWhiteSpace($value)) {\r\n throw \"Missing required environment variable: $Name\"\r\n }\r\n return $value\r\n}\r\n\r\nfunction Get-OptionalEnv($Name) {\r\n return [Environment]::GetEnvironmentVariable($Name)\r\n}\r\n\r\nfunction Get-TempRoot() {\r\n $tempRoot = [System.IO.Path]::GetTempPath()\r\n if ([string]::IsNullOrWhiteSpace($tempRoot)) {\r\n $tempRoot = Get-OptionalEnv 'AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY'\r\n }\r\n if ([string]::IsNullOrWhiteSpace($tempRoot)) {\r\n $tempRoot = (Get-Location).Path\r\n }\r\n return $tempRoot.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)\r\n}\r\n\r\nfunction ConvertTo-BodyJson($Value) {\r\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\r\n}\r\n\r\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\r\n foreach ($name in $Names) {\r\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\r\n return $Object.$name\r\n }\r\n }\r\n return $Default\r\n}\r\n\r\nfunction Get-HttpStatusCode($Exception) {\r\n if ($Exception.Response -and $Exception.Response.StatusCode) {\r\n return [int]$Exception.Response.StatusCode\r\n }\r\n return $null\r\n}\r\n\r\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\r\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\r\n try {\r\n return & $Action\r\n }\r\n catch {\r\n $statusCode = Get-HttpStatusCode $_.Exception\r\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\r\n throw\r\n }\r\n if ($attempt -eq $MaxAttempts) {\r\n throw\r\n }\r\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\r\n Start-Sleep -Seconds $DelaySeconds\r\n }\r\n }\r\n}\r\n\r\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\r\n $headers = @{\r\n Authorization = \"Bearer $Token\"\r\n 'Content-Type' = 'application/json'\r\n }\r\n $parameters = @{\r\n Method = $Method\r\n Uri = $Uri\r\n Headers = $headers\r\n }\r\n if ($null -ne $Body) {\r\n $parameters.Body = ConvertTo-BodyJson $Body\r\n }\r\n return Invoke-RestMethod @parameters\r\n}\r\n\r\nfunction Get-KnowledgeSourceName([string]$FileName) {\r\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\r\n $name = $name -replace '-+', '-'\r\n return $name.Trim('-')\r\n}\r\n\r\nfunction Get-Collection($Value) {\r\n if ($null -eq $Value) {\r\n return @()\r\n }\r\n return @($Value)\r\n}\r\n\r\nfunction Convert-TokenToString($Token) {\r\n if ($Token -is [Security.SecureString]) {\r\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\r\n try {\r\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\r\n }\r\n finally {\r\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\r\n }\r\n }\r\n return [string]$Token\r\n}\r\n\r\nfunction Get-ArmAccessTokenString() {\r\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\r\n}\r\n\r\nfunction Get-SreAccessTokenString() {\r\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\r\n}\r\n\r\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\r\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\r\n$agentName = Get-RequiredEnv 'agentName'\r\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\r\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\r\n$recipePackageSha256 = Get-RequiredEnv 'recipePackageSha256'\r\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\r\n$armApiVersion = '2025-05-01-preview'\r\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\r\n\r\nWrite-Output 'Connecting with deployment script managed identity...'\r\nConnect-AzAccount -Identity | Out-Null\r\nSet-AzContext -Subscription $subscriptionId | Out-Null\r\n\r\n$tempRoot = Get-TempRoot\r\n$workRoot = Join-Path $tempRoot 'sre-agent-recipe'\r\n$zipPath = Join-Path $tempRoot 'sre-agent-recipe.zip'\r\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\r\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\r\n\r\nWrite-Output \"Validating SRE Agent recipe package URI: $recipePackageUri\"\r\n[uri]$parsedUri = $recipePackageUri\r\nif ($parsedUri.Scheme -ne 'https') {\r\n throw \"Recipe package URI must use https scheme, got: $($parsedUri.Scheme)\"\r\n}\r\n\r\n$allowedHosts = @(\r\n 'raw.githubusercontent.com',\r\n 'github.com',\r\n 'aka.ms'\r\n)\r\n\r\nif ($allowedHosts -notcontains $parsedUri.Host -and $parsedUri.Host -notlike '*.blob.core.windows.net') {\r\n throw \"Recipe package host '$($parsedUri.Host)' is not in the allowlist. Allowed: raw.githubusercontent.com, github.com, aka.ms, *.blob.core.windows.net\"\r\n}\r\n\r\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\r\nInvoke-WithRetry -Label 'download recipe package' -Action {\r\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\r\n} | Out-Null\r\n\r\nWrite-Output \"Verifying recipe package integrity...\"\r\n$actualHash = (Get-FileHash -Algorithm SHA256 -Path $zipPath).Hash\r\nif ($actualHash -ne $recipePackageSha256) {\r\n throw \"Recipe package hash mismatch: expected $recipePackageSha256 got $actualHash\"\r\n}\r\n\r\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\r\n\r\n$extrasPath = Join-Path $workRoot 'extras.json'\r\nif (-not (Test-Path $extrasPath)) {\r\n throw \"Recipe package did not contain extras.json\"\r\n}\r\n\r\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\r\nWrite-Output \"Loaded recipe package from $extrasPath\"\r\n\r\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\r\n $extras.connectors = @(\r\n Get-Collection $extras.connectors | Where-Object {\r\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\r\n $type -ine 'Kusto'\r\n }\r\n )\r\n}\r\nelse {\r\n foreach ($connector in Get-Collection $extras.connectors) {\r\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\r\n if ($type -ieq 'Kusto') {\r\n $connector.properties.dataSource = $kustoConnectorUri\r\n if (-not $connector.properties.PSObject.Properties['identity']) {\r\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\r\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\r\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\r\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\r\n } | Out-Null\r\n Write-Output \" ARM PUT connectors/${Name}: ok\"\r\n}\r\n\r\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\r\n $uri = \"$agentEndpoint$Path\"\r\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\r\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\r\n }\r\n}\r\n\r\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\r\n $encodedName = [Uri]::EscapeDataString($Name)\r\n $body = @{\r\n name = $Name\r\n type = $Type\r\n tags = @()\r\n properties = $Properties\r\n }\r\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\r\n Write-Output \" PUT $Kind/${Name}: ok\"\r\n}\r\n\r\nWrite-Output 'Step 1/7: Applying connectors...'\r\nforeach ($connector in Get-Collection $extras.connectors) {\r\n $name = [string]$connector.name\r\n $properties = $connector.properties\r\n if (-not $properties.PSObject.Properties['identity']) {\r\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\r\n }\r\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\r\n}\r\n\r\nWrite-Output 'Step 2/7: Configuring built-in tools...'\r\n$overrides = Get-Collection $extras.builtInTools.overrides\r\nif ($overrides.Count -gt 0) {\r\n $body = @{\r\n overrides = @($overrides | ForEach-Object {\r\n @{\r\n name = $_.name\r\n enabled = [bool]$_.enabled\r\n }\r\n })\r\n }\r\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\r\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\r\n}\r\n\r\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\r\nforeach ($item in Get-Collection $extras.knowledgeItems) {\r\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\r\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\r\n $body = @{\r\n properties = @{\r\n dataConnectorType = 'KnowledgeFile'\r\n dataSource = $sourceName\r\n extendedProperties = @{\r\n displayName = [string]$item.name\r\n fileName = [string]$item.name\r\n fileContent = [Convert]::ToBase64String($bytes)\r\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\r\n }\r\n }\r\n }\r\n Invoke-ArmPutConnector -Name $sourceName -Body $body\r\n Start-Sleep -Seconds 5\r\n}\r\n\r\nWrite-Output 'Step 4/7: Applying tools...'\r\nforeach ($tool in Get-Collection $extras.tools) {\r\n $name = [string]$tool.metadata.name\r\n $properties = $tool.spec\r\n if ($properties.type -eq 'PythonTool') {\r\n $properties.type = 'PythonFunctionTool'\r\n }\r\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\r\n}\r\n\r\nWrite-Output 'Step 5/7: Applying skills...'\r\nforeach ($skill in Get-Collection $extras.skills) {\r\n $name = [string]$skill.metadata.name\r\n $tools = @()\r\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\r\n $tools = Get-Collection $skill.metadata.spec.tools\r\n }\r\n $properties = @{\r\n name = $name\r\n description = [string](Get-PropertyValue $skill.metadata @('description'))\r\n tools = $tools\r\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\r\n additionalFiles = @()\r\n }\r\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\r\n}\r\n\r\nWrite-Output 'Step 6/7: Applying subagents...'\r\nforeach ($subagent in Get-Collection $extras.subagents) {\r\n $name = [string]$subagent.metadata.name\r\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\r\n}\r\n\r\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\r\n$scheduledTasks = Get-Collection $extras.scheduledTasks\r\nif ($scheduledTasks.Count -gt 0) {\r\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\r\n foreach ($task in $scheduledTasks) {\r\n $name = [string]$task.metadata.name\r\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\r\n if ($match.id) {\r\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\r\n Write-Output \" deleted existing scheduledtasks/$name\"\r\n }\r\n }\r\n }\r\n\r\n foreach ($task in $scheduledTasks) {\r\n $name = [string]$task.metadata.name\r\n $spec = $task.spec\r\n $properties = @{\r\n name = [string](Get-PropertyValue $spec @('name') $name)\r\n description = [string](Get-PropertyValue $spec @('description'))\r\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\r\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\r\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\r\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\r\n agent = [string](Get-PropertyValue $spec @('agent'))\r\n }\r\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\r\n }\r\n}\r\n\r\nWrite-Output 'SRE Agent extras complete.'\r\n", "identityName": "[format('id-sre-apply-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", "scriptName": "[format('apply-sre-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" @@ -1047,6 +1102,10 @@ "name": "recipePackageUri", "value": "[parameters('recipePackageUri')]" }, + { + "name": "recipePackageSha256", + "value": "[parameters('recipePackageSha256')]" + }, { "name": "kustoConnectorUri", "value": "[parameters('kustoConnectorUri')]" diff --git a/docs/deploy/sre-agent/latest/createUiDefinition.json b/docs/deploy/sre-agent/latest/createUiDefinition.json index 87e82bcaa..25d538b3e 100644 --- a/docs/deploy/sre-agent/latest/createUiDefinition.json +++ b/docs/deploy/sre-agent/latest/createUiDefinition.json @@ -101,8 +101,8 @@ "name": "accessLevel", "type": "Microsoft.Common.OptionsGroup", "label": "Access level", - "defaultValue": "High", - "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "defaultValue": "Low", + "toolTip": "Low grants read-only monitoring roles (recommended for reporting and analysis). High adds Contributor on target resource groups for autonomous remediation workflows.", "constraints": { "allowedValues": [ { @@ -147,8 +147,8 @@ "name": "enableSubscriptionReaderRole", "type": "Microsoft.Common.CheckBox", "label": "Grant subscription Reader to the agent", - "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", - "defaultValue": true, + "toolTip": "Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.", + "defaultValue": false, "visible": true } ] diff --git a/docs/deploy/sre-agent/latest/sre-agent-recipe.zip b/docs/deploy/sre-agent/latest/sre-agent-recipe.zip index 159ae7454137f5096b46f48672aeefb4b3f4c11f..3205d3261917753562b85223c53a3494861f445c 100644 GIT binary patch delta 342628 zcmV(!K;^%TlojLk6n{`l0|XQR000O8k5$oJguX|{YdQr0(=-_X3jhEBWq5RQVRJ5O zb8l|cz1wmdN472czP=(i-CicyC_op>-A&8tpeWkrwq&VE$?jgHLP!7!pcV^N=*lWm zRI4NWv|o3`K7Kk+=QGat_y^7}oEUS?yi}pUi%j+M+7WxT1%Fm$9 zi##{uswnNojynD~rIh*y{a>Xva=kDcJ8EN^=Ec$`^Lmt=*0w4(dhUs3Su9Oir3P=i z_mtY0=t}RokzZacX_)UC@5)n0MO}{R&-1EU+MU5*ndz~a7um#=eWPtv+k1WbZ2vsX zC&jt#=cXEbTYrz@q0))TtF*enK=#5`X0aiE{O7;9|N9!xZ;a|Rs}Ay)MUjO`Zxm;y zEYpbzyAbvv+KIo^ro4Ds%yx5~T~z7VKEC*|C{OKDkIlg(o{-7)C^M6d9aWXJadYWi zG4$?od63(5Hm~es`p0dLd1x$c_-zc_+=p8l`9)S#M}K2oRi^ya<9us$wb097Js{px{Uq~>-8+AWQyk$z08`Cd_$Ceu|~%5<8J>6`sUIB~F(%H$PZ`9#qSm3v9WFP-Ek`O$c8CUs^es?zq< zs%ow)HGea?DRpHOebK5#Z7X%AvvlHr^dnkzo>p^}7kP4)+FEC7JU8Q0t43y8lt!7w z$V?__K2z1)EL57SmqstFS{Q5f%ve>F>UmvdMRBT1vn1Sty&n!}RX= z)qnG)$?16>ubP)dJ)5g>F)=-5>+xJ^t6rp8R-CKN;fsT({R2EW+`?WD7rI(zMU|za zKD|HeVXEUIpQhzPr4_ciGxCLqzjYVw8*W}rBRtKXGWQv zmN+d+UN{JRVkSZ{^a-NeX#3MDGxP`jHnl3#Ba>NmZc3x9sT_4$eU|34{z?8tUmZ-9 z&M)}H)l{dM?WxlEyAXyh^0A@E(@NPY%`*3Nu}GsS^wg;_OZs<36pP85x0SN>Vt=8_ z3*H%9Ves?$Mf8DlZIwMumrFBo1o`5knio09rZOen+~IJzq#sZ6X<00YqOx?P(gkhF z3ti3SFE0+Bx?hP9@HTzu4c<{-(X*Q;8)LoH{xYAPY;57-bV`>mywhhQ z-Q3za$-#0;om!&~>%2-AX1^?pa({Drva#nELvNP`cV3-d!%YoltS);(o&va(;iufxlrgZgKC}ioV)TP{e%j`** zXKEX=K|Lvmk|9veRwR^$@PF(OOYR1RCE23tLPp_0;Gx@2O)_g(1Oq-_@m2 zM~C}rcV_bH^`=wFGd$T}xHtRbVlgmzQrm&XD+61aMB|kKiMOqu(&MqQ)=bpBJNLdw z?mS5D+`}5i^}^(pRiuO`X-%b)@KYbIV-MSq#(Rg~%Y!S_VKzB?-Kz9N_Ap8FiFvzTd;U7jpD!(4 zfYY=J$E*A_lp9LXP`KYO=c$c;X1*}id6B1M;u#b3)~hlgIe(j0MR}1d%i=7BRucvv zX$w_@M$wsNm2#OC7c_K(*H{?exyh8C;^GZ2-Mb<2wj~JPOh7JSW#74nzJ@l+XKuZc zIUJ?=KrffsMPlAorM7)LA37H2C{v~RnaQyx{Na80{k?iom&?K$_5LJ(pCk$We>^h0 z{4|H^z50H|#DBmZidh1+zHOMKdHaSGb+xQvVDL9rr~scipyMf~SDcJ{mo@e7lfeA^ zc8UP7GI=+LX?2?Lv=UogWJYFjG}kacg#KO%{qci}9;DF?rj?IPGScHyVsyFA$EnU( z>vjs=Lg#vB=m@-x^~#+->4?MT6&z=}o|t5r)w47o#DDX%gRU97)nI?}B(=6SHqrTn zn1L>fI-gis+4Cisa$4lL3iM!)^k=Y7=pL5&a`d7i7V2i&I?`9WFWtwBd{pQXwkG&W zu~?WKlu_jF(_g2ht&*~48RxxjFbL|Un$_t<=VRX3ii}jgYht{vWd`p1^iGl&l_!M+ zW4a?H7k|OH68jf3aCUF}3JtGn*v2fMOqP<>S=O0hk`FuJ5A(g;z^5=YaTSWZD)qQx zbtBLq2|`k*{N*2AbYE(41&ppU+`1Ivv6D5BjO-@kn8%FRz_EH^lpUApvf|^!k9$OI zim6S-!>CD$JuAu!WsBC)Tkupx(^f@pl;tZUGJl+Bfw>(_=_BFlG6NQmf?He4CN-~E zcqmW4rz&U+u=XHVbNQLyOtZAQ@bp`h_&eDfZ6@BK1s-|^BYU~izJ}M7gu@Os#SeLz z9@5r87G{Cj1m4!tYFdkuonT_N^%9$Bpi&9DCo2B$uV}0)3zzB^SMb0!ng;F`++28T zg?|C!)~{7XTDQX4Jr%SN&(p}P5d|@yt=yynn);csRXSr?+EOTmz-?c>oE!Mlc%I}= zVYmM@#mU#DW0q6!T9v1{NgSV6OKq(xa<#iG(@fp_V~_M&T5V|-I?Z8PP3z3LIe6iu zJ=JB2wch;`kLKp@uGO8s+$`pNg~-3s(0|-?rmUWtiqw(q?Y+Z;mj`>hPj|Mr)z?LN zs+M(@snYztHspCLjnc6H%tV}3ZJFa&Y@v_UCD{(kvY6E43Z9m-I3r=(Q=__yW+9%` z9BxE79@#f)CSX30S2~}N&uLLq5Q9~zb77UZC_RxJ%feQ+r{u0W)23L!`Q*H+J%60& zi$gUkCMmJ#lYCc}#Fr~^`!vmp^BwSyJ@U`UKscuCg0>(0G?|!bnwtqGS6f{uZ`!vNvm(`QBYEPF*VOkwlpPe7g!m5IzdN` zmKKp-v@!5apPHN$gyNtEC3Tq%dup6PpuReMiesFcEK_H?B)7Xn2!C)#%y?da zB!qI6E@vz?XkNkicI=aNc{)#1TGId6zID^te6jn|ZqeA&q8z1@iOK!6*?rh^``uHv zDoWD>Pr=VcNp2a8KnE7sqiiH%q@oPsHXKZuLgLFwYEkg_@U0+kFg(7hw%~1=Jo46z zOH(Byqlw`y%y_Qz)Gqu@xPRg_$?aPc-yP28FxKbt(@>?;hI^b8nD#W;?Ho;(_Jf_x zFAm8UENqpOq2L>5HZd;hY(m>QGPDm+&?Hon7sM=Maud=jp)-X=(cI*8vZ7cj#Bbx* z*w6tZDD~1XsqyPWzEn7N7;t0*KzFjI;Tl#2pKTykxlGj@;R!lLcYklfX$w~rFCV_* z4_;?%NTm79(%Eir4?ii*0$jKpZf~n!e)<^!0Vtgo$7>qzvQ4>Z`m=sdooxKQE-I~d zUmOrcrX^&-J9V~DS!%0<_4ldHG8ks$rKIoC^irrE7kM=|@YYVeRy}Z&z>-KW`OK=N zDQ#+@Cqz6`n0~!PK!0vRzMh4y;9UUIBHh*K@myJB;Xvh&AMronv!p<@e60EMSTCVE zP1OB6YLVu3g>}(@S~gzI3Ik4`nu^C|se}ta-iOGpS?Dwy6>pIH|#n1zrb!}`(D#bQ|%3#dm& z^@s@3I!NMGf0~IDhP^VSB6a+o4%z7cYy}qnOk1 z8`BuU4*O~s6Cp#IMT)H`W|vm;q9y|lx}M(~3Is+{tRWAGg{RZ_R)r`15ELpU8r|Oh z(cgrf?d>3K{So^e)MIF4B!!ozocGjla*^vrIzGtHic`E*>T`8&M)RV8P%X-6cXwYL zSoNQv6-dpp7@5Ykc3Q;xv-33T7tdSYQi*zCd?^%b@mwRo%5)7fV$V$vi^nb0RTlx^ zA~%NQC=BgbX(}*W*5z~t&WH=`--TYotoC3kM}HrskF=;UEJb|RZbqxrnOX%ERZZ5cAmq8 z85a=76s=wnqR){=DVk}|>11?C_#We8e}DIvr!K0o&=+c)>2%>-K5RMIiocm!FzL*| zqq-<^tO2U?2>e>B3!}>(@|1GtyKn+$h_@3z*X&1cXeA*j=Zv6Wsd-5#d7t)QzG?E7UevO3&9dg&r1t@8uv!MTOlR6JRbLNwQ6 zWKDU-YAf-%$N|KT75ZdZQ+8LUjALQ5<}}1|l-mrG`OFUtE;Fx3?V0-&H@`*U{CaBm zqD;p|{`;^Q6`>#La=e76NwX7%j(?r@3;q^4WA+0-!I$^nF0-OECGBQET9GFjS;VqT zk>(Ul6&G7)#PaX}Ibqw>2Kv6QCi=pvBAei_b8`+~hi4^X(HhzeWJ(c*HMor|lmC>^ zuu!WfY4AZj1Mk8m&(blwMCn;ajHNzLhziLw+CgVAjlcos83QI#=VU^QXMd?QE_afn zEuBZtZY3xgVfs)Vk#AP2Wx6z3nwxkTqK&M()@($P%nLir8HK7W&TWtWp~YuM#tE<1 zss&Qxs=3ailjysMMOjIJBajxkF;Ts6C?zQ7Q}mxsIGAMNhFJb!rp{n4BM*gt&!=J5HCN1$ds%L~fDoESJ%N969vit`nb z6fyYd)=$$MQAIBo;RH1ef)O?jl8J=^xH#vBfIE9SAe)4uuIosF1&)Sl>Q~El5OP72 zvN-oq<`r=>tcqnqGC!%Jz2Z~C-`EL65sl^prKxIo-RW|sl_}vkuYbtHHT3)W=5YVz ztHba2pA5U$J#%K7=@d-QQ5$hD_?4$A)H-qXLU8NxDa8!JOcKhZ79NdcO-RI6p03(m z-3b@clVnjB8<+G}ww19hhT|4_p_X+yo@I16oc{=>33e=~+#0PG(Q`GtNX zenw&a;c~n|h86RngX#L)q?b#haexsg7DhFQSml5nw3Eac-|;o1%^o*SYi=*p%%It&s&rt5h$iKugOIZL?0Ek4qlm+Yk$B07W;?bh$E$CMs6p` z0*|I17#g`SqffbDyt}=lzB<(BYFcMmLW-Iwai)S(L-ekytn-kK-?+!SD}jDe^jJ%p zlxdbF2%GW-QMUV#JYR{)%M@=W2r~@XEvsoBtT2+f4^=_W*XgdcATgz z&c!}(55${j`|9iV?lQ~Z+yL`-Y|Nxs170UKxTVcCVY`VH7hfFCd9D45atdjWG~VlX!HCl*c9R|r`x>a0qaWW=-f0v~KzQ1qf$*33HEsz)#Q z9fDm5eIv3*WA`JSLs7cDckD`%0o$9P#A>khh!Z48LXFZaBX<}|jY7sFF+|52UN)kI zQ7)~WQy5`ZYI1ED`lf|dU7Y7ZeRUI)QGX?m&@JQJdc-*&fzp%nbYfPgBbP!-+s3%2 z3sWY=Ir1EvUO&znr1{hLMwzyiD)l6-E#mTYif)9pp7jjdH@)Dvpcpi)hq=TRa?<+! zn3$;uGmf><3c3%(I(Newc}?j$Y}-j{Sb*bItGM#B>P*HDSzeiQCVrU z%e)no{3=>=FDP_UoXC5CgcC<@w5yWq=_4v4Glcp0;#sj;&I?M)hO|1_pyCLMIeJ@I z&mbJ-7|_~k>G!3g`t!nQ~H85zMn9|@*CqSZa>tH(m^k$U1} ze@O0V9DY@Vvwuj#3_v809Dm!R+)L(JIuDi84{;=X7asXobcYrCYWL+p*i;gXhbS6y z#Egg;0Sm6uOlnSllnv@dX;a8Vu^~m#XLE|`cE2yT!{G;T4AQ0Z$dw*4D7dEwxKyt$c z<;DAF6xGu+1m6Xkg7nEuk5Ai6WsU~ThVH*hMs#!jpU?J>kdN$L>|{PqYH}`dhMciu zy~H`WKtD?1qIxxD^0Txo9LwtVA5p@goG7w~$UR2iU~Ldv?sp4$0Yg6{cZ>WTh#8IO zsjWr3ElkvYZgKvBb$_mG928X9BvHPuWNxf-VfdqTvCN=-tn4FYAe|K{%FD;6RXRQm z8|mYF47A6bf1ZVf?MPYK_x;-MIA1}j3A3%F3UoX=iyd- z-dBI2B(J@v2R_O1(#ya(VVwKLheIlFJ1=bLlYN5Xn4n+{>7YwHLWU z^DDQRt|&1eO8?X-L4wk{=`OeJA?*Wd*?ZPYN48Y%Uk z7Jem+!;+jfPCgxZggE8c387(yaE8-yr!7TPgS#V)wshA9& z?o6`o*?(&xiLLG%>SW{ib^jkYksbV>o=PV>>Exd$8^bO7(k?OW+*l|qUGw2Jxr0w= z+s&kP*sD1qlFl9n1RMh=2N#4PoM(zRn5wdTehn9$2#{x@W;;L z67uAS2rMPN0oleSj`YadpzDUf7VCGuv@WU&VU2*c zD}UnuG9HVzj&(?%fR96FTjo5ixFUn*f>Kkqcp*~|Y&O|6nHvpDmerD`+R&9`9ca$Q z?bc}YBQw`$X;FGwp6h&qDjIM$a&cswAN9#6>JNPp7*S-ti%bbFBdY1*$HBX@+Jaqg za7Me+2N9cYsIRfz6&YK*PyXtLSmB`X5r0O~%nj##(%!(Lq@;0?)eDLz>q=&YK{L%6SWnXsBI8rg^@9d8fklP#9If?*qHQV`9%b>UFLL5fg|>VMYZ zg8;#3xYwwV%4>G?xxei`d%Bv@fFl#YE2xGDi17!wdO%8w-5jDddqwzEM)y!P&j|H?B61Qsgc%da%``>VGmO^!viUz z2DF4LCs@*KG!%8pB}?Lvw!rRt00{h zcCDe@Q7{*Aus8r4`Q_BG4Wc=Wa)8O=(3Q@L*=nqEeF)U;6bGm%7D{%a%X;vhB!PX9 z^a|~A61~N<5;`0*Yd3Eg=1Vf2hE%iNcO=?>!eMMW{5@ZLC6=cvP8`C|N&m_F;BJy$ zrX6>vFQM^aQUFhs^MfLlNnp2N<;bNU66_zKsQmb z4hPy$Rj5!`M{YJ$el>8H!c8J@jYv+e;UBjbMb*ocm)GQge+H`HSN?@$sz+ryzTuE^ zQ0vB8$(trOUL!r442-Dslc}FImq~(@5i*&GtwiPI;kvNr)$#m4^?y70$Vk>$VS{Bq897f~iA#n7KvpWlb@?R%`#VLTKOn$A0CJdou@ zsduCYII%+LjgL50`LtF?73u)W$(#MpCvVOkxRkQSde032aa$~Y-ENsIow@i2V1Wb> zG9Y4vb@D{Ld(T&0I)5oJNvAmE(S>}BH(bCMg5M3faX&mGEJjJz5_>*;X-_;Wn4kp2 zgHb?%qL7&x;iq-2Q8)k%1*|<jSuWW-OxEXy6i8+Qadip51Qo`3%^-t;#q5_sHSoO?_1 zYbYB!L$%z5_bI0dyy0BPkaCyWH$DnTs=|=`_6U{F3uLAvbwyIzkG^|l#o>M#En$mw zMqh;!%h$3u9JQPSghz=5^UY!aQ=zeQN}J?T58_mAC1DP6;3~~QsJl=8I^cPQ-Etz93u)3<|vxc~g;z@FCj&w80AqFsM=@6Nr?lRKX$cklBQUKHo1Bp20= z^WxEPN2j$)jv60V597%s>Ew}0p00XS;c<;_q#Pv?j(@||Si^F7PZ;~<$#*+yNYCv% zC$sH;W2&Q56sr%^5dZN8z(d2}n!S_|g@hai?ynZlOY9s41qO=(o|J)p$7;=BW~xNL zqyM(2HH%mMZfTRd5Bd-Kcdi$kD8Z=o+nJ9~;KxrT`#hj%@Z4vwTiAFw{>k_iranMSW zcWmj}dF$AZmDzYD9yt@5h3J1k%@<@vP#HMS0U~Y&ogX zIjuqSr#EMJ-`vCRoNygnFpVU6NuXR9O&(v7BM>T%qq5s_142t{_4I z2=%+gd)`QcXT<9UGTKVUznI6)hvr;hP8qhfX{EpNY!eDd(BD_wStRQRO^l$J$Mw5% zNI};^L>-j^|+Q^4}QbH*ZEF@I@< z+kNbgTyU;bFa+Tx^1@>u#jbe?7`$%;bwVr;5;{9u0Yw>INC1G-3poZrgMU-%F@cV8 zwKH?G_u`fKBAHC}d@M=oUBuZ}6XFi^H8K`9>-=7m)kfJ&uVq z@l_ns<9dyW!3946e%R!b270Cauzzt#{(ji2T{zDlxR@rE@_%~_!mB_9FGVE06d3iU z$j4!@klpLZWi9fcM|EQS2otNEJx;u1!-3(1qK|BE3+_-)QR#{rG8GIRVicjyk=P12 zblck}8$Xhn%Tb^MDh)Pot3RJ?Y;WU5egb!UQm6xlJ)u9!^$Jk29gBQXrhll;hG+*m z4D1#Jw#fmm!WSh|7Rwb2DX&N{8ZfbKB?`vc3I7jMBcn9Y7EQ zc!xBgS%;q5?)2he@$sqq&B?EL4A)_a(20Lrk6fueRRK|wv!L2a1|Qr-5+DtYM!53X zL3-dV=6?-9p9rfVRQ-W&&VO|i7hPCs5Aq6X&RG)~h?D$WElx5iQ$&R%Fy>@_iy+l` z`c9V<{81FW(FKY0CJR=CdM4LmTJw4NJGfj-qa4ac`cOmwvJa5#FcOBN%5lQ44#MsyM^Nm^XaOB~FE z8q(3k8iGke;zTI|uN@=zv{_&SN*~@3CrEwUD>=7Z9oy3M*)caR7NO-v<7cF+-RrAw z5D-@I`bY|XYJYI89)VF~e)8Xs8zOXjdsPgsirp1y%hHVR_Jv?*kza%0QeA!tH=!A4 z$a&u0rtV=-@@JSAo#BrX7>7R9>k{9%sa}GoIhFH>Acs&UIWCrHT6Q4WwJO$Eg>I1W zPMwRG7TtOlxH!%LeC2?O!@tAaCnfNETms@qc}?;bk%53pj1S=@uZ5Q9<42 zI+X!tsnqF;7^ur7RiX0= zvpY~v*xhlr51>ssLGGKh`5e_rM&1A7fjiqRsPgylD3HIJ6tfvlk4~SSW#vfT7CJdf zXUNADt3Nt)d`OSQ4~+vrqME>+hDdq>&xK1y?0;6F;5 zmIqmm?Tv<0f#XjMw#!ZE$kp)b5MVaN0vd?{1VT=wDDr1wQrBG}K-t_11qhNQ*a%&VuU3mH7o#!DvMEE&e8#x*lcRKEDdoT>r!tCsj{f0T?hnq%yQ`l zBXJPAX{6o2l8z;EhuSSexfCndG@jo@86H2H(Lf%fxGDMghBp~uSMU#s7^oO;HBF%PBmylf7N#OU zWtN_@f%6Dy<;bTk*LR`e>=FzJ1jp~q+iFK`-rZX7Enu~!&XHmgYenjjaMeeusSUx2 zAnFBW;5Yg!c~p$eds}LEG6_6-dz&a;fTFjz*P8M?6%i2XQ2^()>)aRqLKf-*8-E18 z&{v!Hx7@q@bE}fnH?@+!mW~F_aXI=Q&A*DtCE^eGun`=8NJxG7urUfg6o6Uq=6uLCN(5CDJj5L;eO*(lBFrh_sqJp zPY4BCjFNF0_~5+&2}D|;bL{h}-c+px{X%Hm2tFLQ4M-4xr*_4aaUhraW^&`BaFltm z3Ld^@gV+&+m#%^v?*j2|;(vN&k_4B9F_(pG_oHq>Lui!}kTt}QWFbfplh$2AF(q3;gbNC5ba6g)|pJ#aT zGuxIktLi~OTR2Bo5Mkz8eSYUYLKfVcD*~&PuYnjKvc7%!@nvm z?N3+3y51i5w97nX7}TwyvZAKZ{YX8wK?}Qz3}QC9dpDD)!eejXu)0(uCsuQ6To+nh znvmWgLJfr0(g64%nD6@NHiu&ld2JqH*ZCDFSN}y;RF8GJhu;XpJ}ashscHOsw=|l5 zK$L_m1;%*eynm44KG)7MqyoCq4_!8^*V8GoLyk$5oskaDJq9Vr!`s!~XlZ4|H4Y7; zbL9%3uk9b=blNmexvLsJElnC);$YwedRurrkkLB?*0qGs7xI25!%nA=oZj5flSvHU z&RGPFLj6c8cJulEN&W|?XJ6eGi167ckF;TJcwHpIbboMtqylkq%mKUTdSLo|=7!|o z-iGYo-sU*>GjSyJL(ekzb_8nx89`zTuSPgT(H`&x#tb75qm#tMC!%{mX9dzKNIv*a zw#>rVvh~R*Wl^II)H=-->7mlr=n5^K3u;+WjjWCk z{%gAENnc*0=5q!`BQnvT-4%-EmAgG5e`8#f=kq$(@_-N9k!x|3OZLSrzhh^v$*w+R zuMTn!@Qwk>-;?Iv9bq7HB2eMuX}ZK6L{&P0%YTf3EJs`Zq(-_AxU;`t?}{o)EM+HA;-GYnsF(1(5k?k7vTq?!LLibFyu>cZGiWE;gKoRGe51P zIi>uv!dhpVap!00nCod+$7T#yDSyq$YdFru)r&olq%iVyz@4hoMUVc#HBkBjk0$^lISQ z?x>Ru3P8Rkg2*n^@9y^RJv-Upq-E~>M|s<{A>2%67;Ufv@s75a)1OPaVLHE1dNE38 zHJpE&ua2Jd)c&i(o-)RzArtla12tM&!FRsX z|NOzHloAF$Mryns*&+kb2+14226Qb*5o6v_!{7hz0d1Mu{QZOegHN}H?i9JnM1ll% z1g6pg3dCZm%hXcghL-JhOq1_86d^VI{oQ+5H7zvxy#I$!hktG(UkV9Iz?=R>v&T7v z@gr$`|MyG|4m`^t!~|7GiZGv<3dOze<(^eIG|c+FqI#k5&mUyJ%$~H`*9;54GRa9Ew$80^~ ze^EKGcWE}Vw0}`wE^5(|Y%aRBEHlZ?fkIJKXD!HmgyFV)55}oJD>&=lQ3Zdv&b$5+ zRbl(eAAj<6pXe?XwdFqWxE7_M7H^z~?FWTJ^~@ju(R{=|;4j}x)G|oVlg5<`SDRZ0 zP|<_Xs-vlPr+8eWzkH6Ssh_i^@O)eqh<=A(kg80+mw)?rxc#E^&mhE*yZ4g24*(?^ z0JKD&iZzHqDw8>3ktG|K?FUX zitNRy%|-#q@pQ4&V?WJS-%QDGKHepYeht0h*u#kOo6Q0F4!$P8^s!VXUhIVSfrFzt zYU<&$7(6ZV8U2_0c+^jUQKrs}hIXGsf7wyTsDGUqJTsHD#u(@FvBxAe7^&M2Lmi}E zGk$?rg?7|20Ag6!g`d?zPYgXvhQLfO8&A4U94w7F08FJ{EPlKV_S$Qhj_4e}AY#@i zITtGXnoJPZpd`LS3&2f6l@ZGCNwF3Au6-sKL4)QbHYHE!!kg&3EW3zfv9e>re&Ms~w*OL7b*Zk2fLA;i-xR6b-={JSr zh+C5X|Kt1u#RbSoz=2z}xpEiDVodGn7R7|Nx4$jUd05}NV^eqyh$|L-@c(U5)MtC! zUB2yYwdt>)8mMpq)j;_xDB{Ii7bL&(%FHl?UPNLl&6l+_Ioc}=hqfZ(ekYdIf||>h}-=1hJ82LiJXCrS@3@&@-eZ0u=-z z9lXD-7l<=};M2nfTO>x~5-rlV@_(X}mXd=I6}s%^RhoFj4Ftr13&JOJvcbL32_0gd z&L}mCyMZ`ug8f}kj=?O)X^Bac)T~EbCJ}SuF~R3^>PCxUO=iw`%ZXbNXOPj(^sF{t z3M8wMxBjfo=NErgpoK*}p8uK0+-=$}e?^UzEEy;2@)OtsaQ?So@c6l*=6{69o+I0| z#Aqz9eGqast4DIpE_eW_xlqeQDvHsdSD9`+grgj|_5gCp{aGDEvdb~;S`a@0b9Dg} z39B}VwUw}CdZ7z3Rg01``ijW&WJ6Gl;(a2%auID6cg~`?XHfZq8BU(f0ws=2R@Br_ zRL4W_RBF42s4az0!smjmw0~3uHD1yg1Lg-;6v6*UdjQwYncX#1_glkDx4{hmWFtmu z3Mi@Kkb)(|POYZ@i;*geteDBA!oW4lWZ!I65MAB89;awHg3HlU`&0B(OV14d6LOvZ zi)u*F8iF3&YHrH{?s-atfhIv%J$t1-&jvs0>~sLgsPEa}Q|@`Y|mAZM0R_EEqhciGagCfo`rpVFOL2njiNBX91j!>3M} zOf5O;NTHNuLk8k&I)j4;IGFk{cm$>sMMYCWkU;SxwX~rZ3|Ebj+$HxoIr(A`hLF+5 zz-tY38&-rl7Cyoj0e{qvT)QVZpmnKx~Kc&n@^o3@>wXXqgV}m#aC8QoW<_50{+t3E>S2 z7!bFZsO9{^@;{=?aJ&Z(*g`L5lbWzIVKZDLUp6dsXC*b1dsI^6R(WUlyCans6LXR; zsT{!7J+sNuxgGvvOlTA%YqWimCqkv%37T3hmarX{cz;ot%?n3;|E|P$PhrZh#qgki z?3UwsN@!>F+>b($c$a}LdhiNj8qXP`Upk*-E5GrL8hh$Rk)`7c_3!F1wWs`NT7L8D zkSl(PIDf(h~O>Ih^tMwTu7M#n#zEKB^{;D7aO zD_GYj?sJUgDcnp3;>E@M665>bheLOt*y^cc?wE>fj4=TP|BBB>%~uC9+7@rfu@eDw zb{Sx1;N`nHds+Erl+u@&w_}rKpp}99Uc%o?=zCkB$!W7kZGS8^H+oVQ z#R9YcHU%O(@g;&@?ZFN>hmb@_&-Q#=j-uk@IUIfjE4pGMp<8Aq)4q}s(P9vpkUkPT zUrTehVwtg;9krXG7ri`k-5V+O2up#^7+V9qrd{Di6+7orBM91NP&J#%DX(yqkNPFa zqYNTWXMvQpMPUy71s5tN*yFm&!1fnS;OwDs)~MgdHHB2*@bFotKxHd|1R|lbdN;wS&36 zC^Vt!c%e9f#t+Lfr5s}~BgqpT;r1|8`#Ndmk0+da3NHbbvK8k!+QX#F9$kMawjS7z z%^l}(o4J)6SP?WRY_4m9f_-JerGb=l)8de*Ljzh@6dA5l7@oUR$bGp)h=z$fYYQz9 zkQ^B=B$O`3-P4E(Q6I~SPJx@%JF`{{UiZ(o)w_2v*n6T7rMEo~x)@Dcw6trfUXDvd ziWiwsj=N9}2dPZFo7WmNSeJk8VZp@1UlC@Qm3o0b3hB%TZ+SDqz*NOc+*uPYm{rFP z8J0N*f%n_%3vkgjQ95+CV9hge70+9QZ_@0^w!ho97%!I6n}DHK=&Id+aEDO7?3Ze( zFA{B&i=s|uMeE(@jeGJ!pF6#x@f$mwD7m?yj&ZTE&51OltN_ACpr?O2uhNW?qMhF+ z>IaA}6dss!hx3{bWA;mpX6w-c@(`L>?C}vL*NuCf9j>AxN7-&knI7=i36JeIJXw|n z{=MbOX&a7$u}0(JW>YiX4}Z%kRbhMkKU$ut=Cay;t6N$T4V#2v{i3EtnS_~w%J^hC zH#b^CICHoqd=kux?@WJI$ydWCJz|lh$%B-=Gt!arZCwaV87X{c=>(|{D?s=Y z*LZ}|0+WQ>sCG1zOVTxszYyNxWvJYA|xS2jutkcS;&7y@-)O!3n_Dsh?*HY=m}g*wLKS1DrF4 zS5xS{>{=3~mT@0=*I*2U8WMN>`N$-nhQ2z|IP3uKG`GFvNEyEg&LWRn{4BPr}->vObdslIrD#K^H{2!eib262Fw$gJ!9yL z4CQc%ak7+gQ=lKZnk%Wu@n|WYabrlKb?=J5@hsh&Nt5mulzkhFCKo&EpaGb?NPVGm zA#0BHH`+(aC3I&zHRFqMMh*G)m~pkJ!THlyD5|H9fmPA??2VVIC+H!7l{I=c*m&t% z0@KxXvs!;LtM5}{qkXcuUfOvf^_OmQ85@i3w|P3PLM(1oK3$Jx%0XSqIfI9lBa^s( z;ANRRh+dfB!r#?8L~Q-h(lN8 z_qKoOhA%dKaLZLA2JkZqwXkq|{$%e^`~nX0vdB^J+2n$Pk~&<~oZRQ5ZT*HXFMWN$ zsqE4e=Z9w>>05|tQKOL?yu$|7P2cMHi~l_N27dKmGA}?oajOLpj44Ui21Kcl+Lx4- zxcBs+7d2rfUBR`478-rt@D+kUkDEVz4E}%RJdRsX>?~<^V#_X|JK^G1b2MCKxKzII z0zq)mSNm^CbHHOPg~>0_>H4dokg+F^+;3q-0XV1Pv51w#I8WH0{~%Qb!B}TKdmagv z>9c10uDiQBJQT|Xiv3zIbUukN^t}mY$*f;_i^4laS#1%wljIPWpi_l}82Uozc3n?B z=%TWl>j|MLNbuNiy1RlL@UdB<2~1gPgzvU|Ma6eV5#@Oo9{J`Z14q(tgtJA-QB<7< zH~?FWsjg;iVvhIogP{2--~Yu1NiTmuX85qzc|3~1_iifWs&*e`-26H4o7iMy!v(4G zFa|(V0>S`J<7Y~(W>fZq`ZYSVN*bTK0Z>F-kEu>`d;7rQK}L}$*Q}cMk-LboH3j~q z)iL$kV*jRDMg6=%lEJB^R-CT4mK%X(;RlG82+7g`SyIXmVSuEzxxcK1bFhD|wfkaB zu%U#;VqzuuUG;vvh!1UV`^qn>RiwhFhQy2lLR?>9@)jJaI82!-VJq2u(TuTqcWkHT=iF(%UIchD7#m#qG(U8MM?;Ga@MkKIU^h)*Yo6 zt|q#$5!3#VTbvuyqbCLfju4F-ocQIugr<%-k#t=3JKDv(6`gq~$&7!aP^2L>V&d|L z8}IYHIEVbFgr_9fp9u|z^bE9^p3Q(R&1y>Qg{2!0u^Hp$`M4c&b)}ySH_(IPCnbHt zs~S!%sVe0pns}k@rtCLeDoU!N6ls?SN55P7>kRNJ7}jkvrTu0u%yrZ89@p9F?$iIEp+vt8@n<#G zTpPc=4braW*@eGt(ETVOL6;TbYpteJkg_5C5O|x2Pmqvxuk(N5IYz-TUP4I(wO+v} zI<7~XQ}FF}w;@hy``1Nik9hah-)l5L^dA&NQ`XX{v;7?ZQM?B-wvB5Sk8Cr6^;`v4q&_*U$G+iFnUUS@du8k3o>Lq|-Y_dB! zOKnkJ|5!D@z(gveC>f>uG@%8WGQ)F6e|buo0wX}jc8`B={nLs4dzOd>MW1V`3Vs}? z+eF_8X;^2r&qYEq(3fKGOc4)9o(@v2sbmJQ8S^sD3Gk8IRT5^QD>gW%28bc|1ze07 z8+=9528Y-Z0}d5HKLk*ft1)jR35u^X3a>fF2jzG|<{+!Z(v24;Tp1+?gFDm0pu__A zl2uq2@R@%E#JesV_{=4U#+UQVHtr^CEnV*Vf2ALu6I=UEQH*_g*GM>xYvzd~B}J6+ zHee0>xZ$M!^%|KBM~P2^Ef))2@od{D`8)En@q)kXj1EYM7awk9Yj6PU%&x?~=nQW& zq}?68?#HT~m|I0T(|P)?9m&R(@ZGtWl%?0Q(};h}DZ~eqFKFEDRmD-mG@qL?rEo}E z%77G+;gD!#L}9x`-eId6@{acD>2J{A$K8g*1_tXb1IVTAs~0Wj9})p|rGY4901zqx zpS~iu$K7^qlG;@ZO$84e&tBtIWGC{w?jaucJCeSz$IaXmY;r5RNR=8@Ph!wJV8`6` zT$F#jC!dFvjiDCZXSz~q1`EVVXVP2nY*?`x$S`J<7aO$z`HRTLN-THjuU0)r9mI5&XF!v)tv(Od2mD+Fw0br1XBdMqhy>v2Sbtq2CRO;pu;T!mI*t>rn!a?@QMJ%UI|o+XYV;RRuby zbAh2b%;m6&l!V({Xz-xD{}ts$qC97XwE*b4e5jc`7G7-Us9rI^N;Xt9h;YsKACwzF z<8*lE5mGJ(G^3O!qTztneBmQ8%=0=g$}Bi|JL~WWnUy`E0w>b9*Ge5i=fDQ0g8X0>!n*Q z^;Y`_->kUtiY>#zhHv2!+uZ}H-6S#1xdRiU%%TZ}H;j=fMOA17tU1OXfrZaNzr@e*5?Oa3>=E}!I7Uyc_68#jqP019vl@f6r+EJEJ^Nr<)|aItAr3y4W7%OfmBLcxFIbU!i)d%i6) zmBjN?-myj*ZhT28nLEu-y_)Uu>6j#?hvg{K6X@LGPXAYs@^CnuSBvZlJY=$HTd z|M~y^-~Zh~ytF|N2lM-nPV$G#M-NAjj%2fT9u7v2)VVI9r92#!cwqF%Q#AkC6)wDa z^5*P;e~4*;pD@~1we^30I*P0|egKyuxpU{Pe}rNL{I@?o7~H*cN1g4xcxBb*A0K?W z^>DECGd)~6B7SRKC5FospacbUj)|@v1%Uc~bby~c)M{Ru=~pKk?ojxA`*Z?yBA>v` z5Xvv!&~d(TH*-MS{mkU`V^GA&#-ry;9|Ra#`43|&nVwx^ z)@w;5f-H|WJ&2&F=XRA=(0&NNT5xZ*o1b(pDW(ySK3so0>1>{%_M9<2v6Iw!w$1rO zWmpR0bxT$?#FO`gQnq*mvmbkSejDmoB*X4K>L%cagZVu#5xAoVOMzzq^HBGH`RV`q zQxAO-zUY)e0=)Xp$XlQPL1e)E{v*VN+@3oT$)_|b%84nzI@!2;vY`MCveXki_SMP8 zA5S*ux$=L}!)h*)@Zq4E(?7lR^uI)K1O7J#b?1K$s?rZPc_hMgP)+EcP3h}?{nNcq z{eL@A=tLm@p*iTe!Jzk6N8OJ{{lg!_sN$q)3^t&hk)3M=H{IqH8UAmU`f0V~Gr@et zYvMQ`rl&T?WlH_gw;m3%)QHtgC+`s9)KEam-X>8PC&fQks0FgJ%2H zNEz|X>kF0ZGw$`_Y8EfY5o9kgN9DUg5!uhY<+C!}4VQF>dq$Owa_O$uE0?!ME3jP)CUJLIK{4}SPscB#4a&i!nbHoJ0#fO_eqlZzqWeDQy4 zawPbtf#m*S?+NTA;lO_*|GpEI^3RnX*{=|fB`h%k5e!QVScL&dg}wY}2?BX*Qpz+3 zg}YSAZq zftC_h=?S{FpjyQrR8(!_W5JZH50rl<%49l@ss7_aU4AHBCr8FpMD&*hHwL%B#K8hF z`*56`zQqSh^%^TCR=BGB@rwuz;5btBbgK#~it%+fTmn>&QQmMqPcz>6@G?p^x{fXY zGcB{)LOV=Ru^orsRxB+?VJ{bmkz1i;9kQOAUAI zrPA_VBpExINaGMgcQs-T46*E_5eqVSc5Ve1_;UVBtdPoG5~Gu{$bcVIb2WsU5#<1R z_Yh2uyezVeCi4hhOI=EO+9Q8oB%~fS)4qQB>1SVW#ute>cDpPnW{ zi5<0xyR9X2ZYq}B6eYe0(-C<~(vS%vIu`iy$2pL-vx~~K(lR=l(7J!QK~_vgI}E#R zO$LA=>dhpJBb}~C&MNfKk`6g;(4Nv0YJx}Egh&+LB##=G%K=UCY*4{r5QEh3J|8^U zWhOqJqr*aF(Tu3=6r2|upPAG;E3HcHP8vDp(kCf?i_Iz413%ONZ7nJ-0 zFY%n9^j9ABdF@m<*CcVa#SF4yu4 zC~wW%NEh)~0I=H7d$+dFqRU2#Ui_Ucr-8~AEUd{;*IH0r*~rXwHl;3iIhRDDdbg*> z^MV`YwRbwoI^X2|*-{g(KW*ssQMa;St2Res`is5gQab2bV*!6d^eoj>2zu~DD3v<~ zx}%AX>|eH@Fg@9UY$kN~n{XHvZY5mkG{e%2O^W@7^*;tMC*@$duy7QdYwQiW;H9}H z=bf)xZ>oE%nm|CyxeM3c8o_o`2Tw$;rkS|MVGW_wa(|Z&vn574P92wj-^(GcH{GJEhT-;iJ>m!< zm3c4{Uv#cTyfyN>UmWSW(Xm+j}%T0p7O$_031if89QhsuLcl`DrepY{1_zD zcgXYoV2KmCeq5nW=no?YYD?`|<03NwZXgW@C{M1+qbiiiEoDRlQ-IrU3MSduNTI@) zT=PUdmjr(?nu_(k1Kz|*ZA}lf_5FWbS^lh0b&iL|!dHL2{n+;Z-OPTx{OvXN<7IxK zYuS-^BRld^C)1_&q$@dzOvzjA-*RnAT#P*_rZ#q53pJ$p0a(GJA=y z%q@Rf)IM-;72Eus2DlY%)e;CA>p#vp=hVs~pA~7tZElPDW9^l{QqVl)9*CF~I_a$9iE?{>Yn zgP#<-a8qCE3z7#A;>YK}>D{?==OcfaQLG=JABtF-TkXAe_e>semT8mbq{d9> z;X&*4fXFVdw>=?Up1ICA(yg8(SZAn!s+Q1p3gJ)yC}Z`2rjkzH`Pq8oo% zS20M@0!gyi-2ZX8m|EFzH?7;TC6FPwQ zu`pFVZa+FM%F@_nk*_Fi{JvC>H&~zTt9@MWeW7^*yOZq%1*w=-L|OVAw)U3=V*=H3O7!09;HEu1Ka+>{9GVenRWN9+ zGzQ619qQDTt*Igfoeen$*bBVRtU7M&g!4qYp#E*UQM*1SVE`*J6ZVg-I=!@*W-Cr( zHM&qsY3YM&00;5rI73a<7Wv317*Z}+Ed}+j`WoRzp-l5+oM~%gCk204&uVCz_VHz* zihNW6w6AN%`Gz$@X#GCDgH31wSBx%(c}hJ>zUd_L&unn14>-Q`B^PjVxd4CxQKJcmBt>nQ6;bz?P>F|r57d0I-Rz0D zl*hSbP&dB5%}lqZQXctlI)OQoD5~933*{w+}k)`(OIf`5@)pvDV5ek&cUVpZ`x2HCv zNQPw802*6>i~WB~WT>K-&GGe~SDP69T0Y^0E>BHGv3N=OV{~p|Mt;adlw)!QYwvu8 zNgMTn1P>g&k29Xof0P$ zI&aE3^oVJlO;eu{l1~_0pQ07c%dyaTO)p|8r{Z`F6-|F+0DP(D#W|{2d+M0F?)s+I z-7{*;0jKa$4&j%deij&OHcq&638x~Y8#Y)8pNNV37$ z+Y>hQfi+9mx-{oU)R(o!vju`#=%}^&xe=aGAbIltfN zfaNDjcUr1rcd9(RvU6i@Pc1Y$k;w(`u#0$DV8ig&BO>!`w8;}W935B9(saEr4#ae; zbEiv+4v zpA&zzp{=l}fz>+!b$TCFNG~&bV@=OI!&v=ydGKkEx~_Bu6~FWfjEuiqQ7Yk zxCAOy;bbIV&m_S@y7ru4{$*qKAq^$~4t(4dNp{NLYwkkY$dm9q?zmjheL`RO+d%ph zVIe#5wR_RQb6RiMg2Kp>kRpKwT}gFiv#oy>Fk}%v4z5;P$;@ee@$S16uvq7TwBwR@ z-XT}}90D=!0D)$8nxa(Il!O;--iE!IrPaJ1(UJKBbVuTjX_OVC0YLHwwj2-SgM)+b zpX~ot68HIDcs!S=KOLD}b6C^HF6WK~r^qAl9n;c45SH|{g5l!ro+TMTu zks&~K=vJ;3^R0koat;92W`SR`h7a}hkDOoI!x=|y*17*)T~Yk3jdRRo0!Re4*%0etO^2GjqcPVwL6(?Z-YIo-*@S@r^jP}_?w=qH=@hnIGC}}g`7ylXDElA zTVn|4mQBR9W88_B=Fp}s?s}Mw>+E*)hYvpE(S^q}MclZk5sBud`KBfCSF3+N^wj-3 ztZ{t7U?F{V#B~GP+egN@_6OVBVDoVHv|vN3!WD2yn!6g6MxPS5K=hLpZ`oWt^u?WI zqTOVq;(T?#0U(D5>@qz?Oy3%9DKhD5)TJmKwQmTQQVUf&04PkQnPLe+jI<`b(AAvL zyBr8X__F%roll`;wb7?s>o|XK8?K+!xw?Dj&Zq1rUirdXFmrC#RFsBHiJ+=jTT?86 zoNpExb!u7@2o3GaFF*av)(g7{c(2aWEK_HUp+fj5PI}1ZvA)mv@19(}#p7bU-M~Tw zjU(_6EV8(ZH!5|UY1y&HeR)TOEF_6i$? z?+bm3OeT}tpo+0_;V-aN!?$l9W7_*?Ca3y&I}ADxI;Ro4X^=9PhaeXL=+fl(5PnLi zgv)V32S2JU>RK7qaCRHcz7OUV1d!})xAD9#^Paz0i&Wa!a*6?!#i4NxIUdrpLb45f z6q@xyjs%Xt4D&H%zfgbvH?MVa%ce4aqZy_C<)@z`R~H4=a-9*3cC4UL=}({-&V_>RE772-~r&t{mHfAf}^L`OWtm zPM%pB`qqWg^``%cBpKQS>?0X#a>ylqf=N-z%Vx5rHlLt9MVWtΠ>fU7$HM0wsZl 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%0AmKKSN=NQ3{-cCBH@+WC+Qm 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 DcXP{$;(`_=4RS1I`fc}i?RacGP#Y) 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

9IWT8spF&pcZqa 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%0D@LZt& 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

GjvxE@s;o#g> zM>%CenRGaXtr4e_O-@5ruOherOf(1{zSdm2uUnsj*MDfqU|4xv?A}pCrNV-f{;9sn z5aM8d&a3I_d^$zGHsq;S&juL`=F8S0i7_m}b8dimfmli+qaaQv6|$U`l7i#`$`GVD zd|sL6dC+q9@7@g$|7YIMvZ-bsXaIqirg$rBZ>Il}JYxqlBH-mBa19$@HWYT@X>q($@{{W^Viy#M56{{Yab zlb5aqzhDVr4Uvj}2xU5Sr{j<`!# z%APv)k~FGPQJf9XZbexjLS4IF>d7R$h`*tl&a)&QLPF2xNetVDkOEE%2cWyk^>7gp ze1DrRHjU8;F~#u8xz6cT5gA{&(&Ds1#vlGVj|(C0jYcNXgjAqaTM_UNi}$+<`UJg4 z4~G$jq&OlJofmU)arKA#4bkaSXKxDl>~;7EjEKE-FEJ@k4|}BS5PS2|7?f5XcxNx+rkahgl1F zAtxIY7H;p3rGwfY}phvB?;r^pXHR}(^6zixhGex`;25?M^Vt?${ z+~v3S)QP*r>*y?uZuNJY9!@uwFVY8Kv~Q00-1`^Q*8XqNgs-;63I<bslFSYL$W}0^4TP72BIFwx+a&5<1OQ&COeI z$;!ZHB$tu>NuIjEB^VFSqKg=yF24`!w~N_FktE88B)PkkQ`us&A8~~MV7CVgjtJxc z15tZ1ATfLsm|^~`8IQBv>#eu?ckCHxd-)>$QWwBWq|Ft_KKCH7Xc2AVxqt1oXPTX#wjn!2ODqsVz~)6B zSfB%1w2pVciJ}S^tyQu_HG>bZK03jhEBWq5RQVRJ5O zb8l|cz1wme$F(+izn>z1$od7qUEMs0vJFvmfFLB{7b(&JDA^leu(P`o-L+9&)vl}p z2$_!1)!a_RjIZWu9%G(IFEFn#@vXJ;P}S8SK#|^>9kDH4=dO4TWkH}Ka|>- zmPKKvby?Ys9d+^_N-6aZ`d_6s3cWBJJ8I)BE6Sx!=FKEIZ){y|4BQjTs$80?&J2F- zey7w%s%yRHMn1k;(lFn(ek)HMl}$CJujh5Wv^%5GGS^cxFZ0w?L!)io*n2~I?eH=y z((=*{3saB2ZGR^5P+4kgs7Z+bwi{RcBNC`0B^9I=4$bH3w-tAyeo{Zqkh%RacF1a~Zs2 z=-uV=ps?9&Ufaj?$A=#C&{*2=4>53iA3o5?FY>ZJnt$rLHr1~l=Ub!egBp>|@0C?$a$RR-@$P}?zpws7Ua@grl$W_lXXcqw-Ck}Q}o1(@~K2bD7<$k2%ADtGb#nE(b(k3^lsIbajihfAnm^YcNtD?cy z=YLC6(DOWAJ+I1UHdoU!H3Mav>0D{6USxS*UaHOUi-V`b13Wn1!d{OTx?bjGooACF z{eC>aRHtQemQ@Rt)!6FF=v21j^PxI4)3Qp{MB8kt7N*va89Qz@Wwp@tKuxY{LvtLc z%Pg(u12s3;-~p{B3sp#g8$Kxe^cv_rQ<$@?G&n7Bc(3ZT= z^<2Jraq!fAN`!!4(~Dl?H|i^TcJp*&s+W42)mKSfnIau7i`nVM79P&d=<MPd@xg-MPW*Gpo#ESzqY@sQt|*4KPL@qazPRPJm1 z2(D##0DrZ zI?s31Kiqz~b6i$gQE$3Wx9D=<^Ox2raPkYCo1!NE%8DsnJr)XiHmP(a_uevl66TrN zmTXW@N}^;4l#3M!r6D|f#D9{z!K`HCk3>Dord4Unvsyhhx+(_hgj8Wju-%`U%BZ8m zeYHC?Mg3~ispL7H94_21htqN~GDXtZk;YF(wlayvPevr(wgyU1r^Z^7s(W|teUaRG zkleY4HB6g@DQc@o2~VvdtVuA-Bnv~odx1et)4>mfyAmVH%7XcCT3!};$>Pq76Q|p(S+i4`L}wyK z@Bvn7oi3KpxbI$|{{c-TK0+I7LWQoIO6N(gi&+Di4b^CPTC8Y{&Parm8ZC5nj?D>A zv26iifrmyft*Pv2Qh%Ac9@%O-I;+n|Vx@v$&NKeFHj8DhYh$C8R%V(ljdhRDo5{#4 z!J~Jmxok=f`c>pq_9n@S)Vx`*6@Q%-&zF`6`#h_|u_-?d<%Uu;6z=WuJhRcqeBYI zT&VH2dp9PYwFE(%6l4%q_MLm^YiOB#mewne<4IPG^m3VBCFV_CX*;y@v1471;#5{# zm;!6U7jMJoZ`F&YT9($Rx2MJ1BuVK1@yPi4(;Ta}>iZSb0edLs2GsSg!I2eR$}gLG z*}!n%cdk$YUVn2y$5WoY<7C`#Sp)As3Cz!Lr!aOalXr7CtIrdjR$}X`+{i4B<{D;& z(BHApA3vz*K^om)TE)~P6FogA23F`|n(3UiX{V?ybfIU4j=r?l*2V;8uT4l?cj}ss65w$6%HWd$}(hPf6R#(cFoujwlsfwnp z%EBniS4Lzr&jNEhIHQ+@tIG^nJOyrT8Jo(yVt?VGJo$mDp$Wi>gS;%{WBz59XZ4k* z-?GB@WJh$Fc#n2>=oyUc1{1!fa?TSr^zEJ}8QiP<(w zY@UItBJ0DTZEG|L+!?r~@T(QZhTFVW#pqDGvr}ql7oJy<86pZ@ zF@IaRAtf~H3uEhS#xk;_01DySp*o%$_`i6bo2P^ZKgFmBUO1pLUf=eO&!fbJf8*JesC1BFVm!8Dv(3ENXbXEC~Jtf zy3&QPKwN-X7GUQ5Wnd6f z7IzT8G;5M;b6usTU{_kAUNm;j6RJxl2l)494cPb@4lt---l$&UH}ZJ1v|!DPi1&qG zsHVt`W#zlErc&n3GS8-2onI-s8-GlLa0bG4SksKiW!feiFQsTklS&uU`MUWMQ{+cz zIKHo~=f276Z<|R_J_a#0&rQBG6>S$-8GJB7_l%YnkzTYh@Fky{f)wBJEUSg$pxz`+ zm5&E%nnO^&Jba2{oSQsX7rG)hxp?$(N6d6yf+U1;m9Azi4QO7$Sa$4_b$@g^Pg7aa z>)0N3)7gBndu+F8?6b0(WNB&&KW%pR4cvYYl&#Ck48T+HaaoZY1tZXb1@3uZ4464UfQO^y$tEtzPM{W{W66qzMS+z8k%`EhUh-V7ZZYthG$#v!);gV|cnD8X!0w*5~mo zF=Z|dbZ(f~bJMej0bMh|6ItcyC~^Z6qaq)?c>_ll>3FdwTQ$W{9ko>?Q`FVfvdoH_ zufOPv;3#U`-NW%fjk{Zg&koHpzd9~Ek77>aZ%k_hJAWRkT}*@wWELs5rWjjR&&!4k zGw6DLZzymVNwJnZAQqmT#kVRv>4%`uCei5j_K*H1>}+obY3q;J@1UMS8zU*aG!^gN zF&W!@JbrW--u~C5F_H$qx_OxTvNCYNxuI4r{<^_dc0C>}5{lrcH$JzZntoI1<$R#V z=~bZ@*?;t)xG2x@t4d$0OEa05C4_2OMZ3HE;=ro^0!5)}NiHS-*JR z`i@F80OQM`Sc^v*0a2!FkP&-i23S09p|1M~02jG6Bu7nX$0}2U;j%8Lb8tpnX#ZR2 zHOy)c&gAGLxJQQ?!&1a2?Pjz}otafoVKrM2(0?j=C`K3Q2>ROU@spZSKrDmr2l}bu zYN$ni##@GoE|$5eIqo0LseMnpQYPvoPnQC6H0R7hCmmovn|fYWkQ0OU?qX{7+*Fqc zj5dXBNaa3j@_~XwMc@SXe1rqUOHJx^?$nUH1W|#t=Kg@?xcmSv&gE|+rqMlDx%5XQ z(tp8xUywzZ;c|)s@lJ0Jx&U`7WHm z8ROT9pK(HO8;feC?7X~$ke||{d(faZx5o6wfB~Y9{ebRT`B>uJVMn@>u10f>wg-1R zRr3t?8^yWY#^_Yd%cEo8D|ggRAOF@qKfL7gp(t@UE*_Ao1K4S!v= zWS=g3ht=W!(Xoqwbj}Z?2j>=IPVr1(Iga6J((HtxW2gOs zzeUcN{ku=_=KVLzysS(`yE%+j=b=;$rKZSRNiACv2D6K;QROs;{gn z^Av|&m`nINJS!24*3f1E*+dl9;x@8O{wkqip;o6^@IgES@4_X|vnjho=~+jNmA*`f z3du9tLuWCKzyanN118cGWI~H)sWJ}h$WfHuqi44gl#DQasE)vgRce_nO@E#hCSHbU zBkQg;8&M?l!VWV6P*vrn9nc?Ie0F4<@M^7E0LoU+brGG!&_yDuS^^h=w8)LIN?h2O zvl4E{q;WS>E)Ddhk}jtXXGuKHuhj9mVdt$~S|zjuh8Q0o?tXu?yLWu>{QINV|G9to z{Pp4UACExIdRCN#m`n{Es(%x5cjV>eib#qWe01y2vI5aUFBjniH7$Y>HV%@Bg#x%Z z<2k^cJspruLebQ9q`(44LpAlQWjhGi&7>+Xee`%m+>GmTnUKs+>S(X{l<*xpfheNU zexNdS1Ft(>&a5^S9OpH8xW;}zUmxxtzdZbY|H-(I-7{yVnVx~^Ie%&+?ghW{Sq8OE zT)hz7dU{SVgD{hXkk7)S0j`8Z?BHtE?&?msP@RA~UCdkHsB9}^TMWl7ic&3`YC6{z zkqo*^UE0D8NvjgTNsL0cS*+$AyuD|y$e8e2AFDcKAUG+q)D=0OaSvI;UGPmeU>q+7j+B-;xt#>H9ZfwjG;(1^uW~_lcYk{)Lv^Sx)mfA02`Or# z#F-jS4bi*mswo0`zIBgxR|5E?=&_cRR#~1W2#4|p5juTLp0C6dRfbZ6aQ<|N1X4_YeQ}`f&f~<^iPOgJb#AA-RG60>LjzOY?kZ4uCJD@ zA9Iv|`Kp)sLYwEAlJaTF!$?#8ZS95>kJj^9m(>M2GxDFyp!wSr8dGfd&%1lks!2s)`%cXM}> zN%WuPTGVr~N5$^}ybU?g!{6C#1|ceve;_(zn;uJ3C}F_DT;~P|Ua&|#GxFi2NoOYh z6qHh4B4mChlMxmge_4g!@sUH*pez&)9zgnGhf-CQFmAk0#CG{7wwkaGxzR-g`eY6` zM>vblJAec+QC4oRV2-2)V*@|2Xq&!5$ZFB#b+#lUp0yYFV6&2<7v-{H*3nfx2Ep$T z>_X@pkv$r_AL$&*%I&>lR|4|uZh{i4!8Q{HNRWh@WO+{Re=wv51tcReM8_JAThYP@ zBWvdrMwnHaTpNboX<=2Dmqk!t-Na;6!3Vl!eA`SI^ARXLxy(|tIvu$bl8QFPHC>o0 zDKCLvY`%0{YcH3 znIhYY3D-7fe`nb=GsRSNHTFQa=N&Cd@}ayfOK+1Pj8~Mif()YI+VK||0*F)&Sv_$c zp+7on_v8v}mOY*f4dmPub&-{vNlB*qb<4HUz-l4 z&&p?`zm8u549R7-WJv~h|9V= zsYqPO{3NlHMKF>uMX))3`4DC>!oIPv9gu!Te@5`YM}ldOXmyW<>akFJq@Fn0AHW^0 z!>`M5_77>85s2iGV|#?XWS*sqkm>voN5XgEk&i|9SfMX>k4M6$l3+YU(U2o%M9c_S za8)L482%_5G>BkRK%&?HQS@j|QQhtj<#xDye~v*qIG;Sd>S)qGL0-BCgVlDr@v+$k#FqQr0xn?eXXI{?zXLI&5k0lDXt#xl z+Al25Kd{b~je~+JnpB^$XP;iS}A;>VOC|Scrm=R>r%VkyS={($u&xh(Se+2T{ zdwSqOj@MoW#)L8Uiw}oX-Yza|?7_ZFMnW(S@fA?lt4nMVx_{+ZnKw1(wi1C0un*** zb68WIH(W=W-Z8sE0k}3+)<{6G=(1er7+G1rN)kfqV7d=0Gt0{2kvK>lV$L&+rZ)0Q zhL9mu1pZo4jh$HEdwM{G_O<-1e=>9I$A$Z`;~Iq636hc5SP9L`y>ptku*ChNV}kkl znAk<8S9XwIzE>8OV3L{(RA>z~H)owVyX zZuia{wfS`5EE7{-8hM?Z&UIIWZgp$z0Gt-JezWcxydbBI8Yhzbr2fmouY_?}lGDb? zt0RvPLynyg8YhVe+HhQNe}Fr3S1?gOV%Pk)h=&*iv)C79!G(cRF*!WlxuEXZYazf^ z_YQTsaq?>T51hyj{%4@FbSF#ydAc#)qBrdl(=LpK!qPV%UXwfcgtpzJox@(mgb18H z4hT2~P7W>zLpaYAZ!l$Bd3+5god}P1axlx%|Q--e}$+|H@*&!F(76~ zFbX^BA%?)rAE`vqb2y)2YH{Al6T7b4mAK#$(aeu@310 z_&8*?WiGRtGcsr{NFim57cvFGW|N;KbE9F&vRcws8~Q-jf#zJ?ZjDAiF>`&9m6fOE zxh_&<(SWm&iz8=z)F+>)KMX}+M3MPEGNtksQBD^>4&IeFe-`X|gAwgcA4F`rrM|{? zS7dDMKKZK~VugdkM;J*nH=OrLdjpF=Nz*cK78Fm`wMxt4GuZP0vl7G3_;nY6REtH1 znZ*2*v`%>-@eASPvzt-n6j4K&GVdfK&F~6VN|Cn~$0itq>f9vqa$yCH z`%0GytJ$KFe~oC;@%AvDY_Zfe4BHqoh z^_U{vbjkaIjY7CB-;pU&0z%t>J{!A0$3vmcM?ED3e=qKi@J5bwFyvu$aWDRiv&bWe z+%-lIwwhF3M-H&KDS0at$@0$MDD1ZqMQmAT3qtf`=R1ZsJJ~APFiy@dl%BFH z9@Dt2O7f5*cSbiUJb;W1>)Tp#1uk=4n6RTmwa5FXULGDuax_XtxO9S*wc>~e>T;e< zDPM|+e`cX`h-ptu$Q7f^CBA(C3BdHZ!FhOi4ExNopIip%ytHc#<(`DOh=aue*vK!Z z#@(Wq;|K#x7Kg5NUd~oymFq*GZl^dvMX^w_6CLWody=G_gTO1a!z6l(XC-tvX4YeewM0 zSpBb~=ilQJuiV50XZ5J>VAVLC$YiD#P-!TiybF?1gHlVBtiypeWECpp)sdSGnP06s zN#Q0@(Tqq=uHhdaE{dv`885HR0so9DfM59^Bxib3Wz$;@DF?M~tQFiex$#=?XfiOO zf7DN=e%4&l1dtIjnTV}K>Ez+Mu;q!{}X8}jcVe22a^={O#W2u&BgGakwEBIq6I0Zyz?wZ%saRX%Uj zQH?x+Dt*2GdHVX|frFH_)_ZACz_!EUf7k7n$+MY@f1uot6mSfcF2Xu_qTapdvo4(! zNV78>^5jZh#v3k06@uRl*tj2_QSC$lYl%G{-n1v46--b9;=w4OKv6(uM)l76)+ii+ zhC*#TTCP-`=`PKyG!eb5 zZx$CE6&kxF*d(WV5T|l033G@8e^*%nLfw7x*AdU7dl4A?+Oy5#@^fhkj(h(QF0XB> zGacA=h~?w_cKQzX9cRkkjKgQ%)3>9>-|Qc&QOkcm`bYfdLHf^;8^?}1yFPNKZ%6-d z|NQ63o;UW-dYL7nU4M1&&b`l*JD(?a@ADL1l$WL=7uAmQ;?ZzN=Z#8^e_AhB597%s zS^7vNPggyv@VG`dQjU@c$JNzX!*X~}xTedK?{?Ifp4)d$W;^`G)JNw?Rv)P`{_z?G zg~q`(do3Xf3AviJzgj#mv2zp@7%fV8QbzhGR%=ExQz!Z-`nNrASiI_=mNvQjVEABo z=UpSGWetT0Vw%-1w^QOce-`D5{@1(U?QmvlI&OJgQ<;QEde{57&JHP?M)=lt)<{~Q_i`c&h8u?(Z17x$~paYY4Z0W|he|7A~%51z64~zt- z4GE*|0wTa(Tw+igQ_pxm791pyzSdl)Dt=jnn`UFnNsZoVjoKf*zPS7P9zJKlb#TG7 zK=J~hTo_FrUy&maDvqPF+j8Pcj*{1kWUzqe#V(8B^U%=IYku$2MuCzP*D8rJ$$ZE#C7M44x}gweYVjef_!;pfme}&4~@5uGp0x&nqOrVMg z2yHNALQck)WfO!nrYlfgn*k`!wc2*`TncK5s=KxdRzSa`#x4(cu&rgI8dzID!6ge%fkxZTI@$OY$81w#;CA}>7lQS6$R zfWg~VP$$IlAffY%m7*wI{<&UR*Q_EsFUl3)^w8L_G9p?Zw} zL$Qfs7KN-V58WwFz#IH0+2U~LNxqRv%?ac_caLKtf9?7zu7cxwjfsl}zDK!WQ>3k` zl=l6`A^H1$Kkci_{GN+x*FOHu))stMvA}C94PINw^tP3X!(aim>&RejML}P!iR(g` zSd|=*|J9{F*oQ zpHDZof4A{NegbzkE!6>+Godf#+Jw@sJ&Sx%WyrdQ$VSy2s)z>Ycx{%%(aQ>UqqOIU zdrSyMA&wS^D}ZHg8;V6KK{1TnwmNrgZ~qWiOW)oO#SKDH4rv6luG(q0bi{v{A9h?W8cyqg{va!=CNFr;( zC?qZanOvJFW-fZOY&sX$*xvqzl1n1ke;jCM4*jKS3ese~6T5@d^v4S|E7b22Eo!Cm z@bkydgEGbmTQ1MIVu*(K2dtbu@jN~(;_SpuXyV9-Km`Q)Jc-h}JYX@SWux~6oD`f2 zL)Mm*$T-WWo^mi`R^ER2cz2KJT)y!q=@NKA>6|0L>6_zkv)LR+1R*OKG526wWfSzLK%OFJ(zpe5NRy^Hep+6R39fUC zDbTBWr{VaPh>4z-8m>NG=aR)0yGfY2%0zS$EJ-?C&PyE3gc`%q#9D$$Lfu3uQVu(= z$kSzkt)o7sOw~+uL|8D;hj1cF)h0Fe=KluoS~qV zD?l9n4s%a4_zqa^o^FsVzVhPxbi>PHsvF?60jFDlJSHV|ed|>Qn59z3DPo`wBgmjo zofX_OExB%`Qa9Dd@q835l;`iOjxJe@d0gzA&zSQyE73mW0V`s@?_Qf4Cq~ya@8rLw*E*Waq{|&ZfwKcE$+7E@Cb)_SUfk;9yYd zf?8%oC2FDelJi~;jQ9&Mv~iJE^s15zmYPbgo3E>g`v+B__X@L{Pp9n0xI07vO*ujC zU$prgSw}|Q|Kfo=+byW__wXnxdbKHLGn^isK0V9Ik^EZdx7JUO;ETFwHFD{&EB zZU#p#gqMdXQd2IVkre1c<8LL+Yr*B>%CWmPz(|gysk6G zj#DkbW-sRkuIO7-e|w{zUO+nG8s+`1WDm{e|+s!4Hl_9QU9i)~jP?n9f_kf^|SuWjR00N<#M%oQ5=~yE7 zsNFJ@gHFMw@%%1AZv1E_BYBMCq2#+8-)4kescT5YKuLDHe<2OLJDw0K+`SH#O)A$a zyX`6Ocht-v!sw7<&wxu`>`F*()kRFYbZ!WN1;;*+s2EwfFg5uf^X!}roJW9*11DRp z?;69X5e$gRjNh9#^^V%SyS3h1z-miV06G$DMe31o)kmtW4Z(>Z>IEU|Tm6uHwTsPr zTWU8=1CQR`e)aRqLYC?Z8w9>ERGas=+;92gPKKy& zLM8nr9SvOKatuG3-xQNe#2@f}BRKw$koxd`W0ZU-C{n?j`@T-#I%$>(GvZ%8)~ZAK zH|mDH-jjN*6ZRUJwZ;Yej>b;(>uX!Star!~q!RH&e=gh2S!Wwn^G`nUjjLP~XU7Zss5PYH_}*aM%`Z`6aOKhM?XGMW-bP!~4vK`5yTp*X z(tmrKe&c4|wrX5U8)k))m(c;aui2Dn3n=eL>Q55J-bvpU8b-W1Kw?qcH^@fSs`l*R ztD#VVe`}rBQk!W1B#VFwcb8{U_`hAVhqN3QPIvhNadqp};^e(mw_U3qDp2pdgYd$H zE`^pR;cAloX3KQ{H`nMUg}GCro79WKWTe=>t4=pgC0Uw^e9Ej7djKb@yC@l_RnL16 zO8Ag==N$HYs<%~FLB9|Nw<`CI+lI;wC@1Zbe<9<*EA_ABMn&N$i*mKt_nHl22Md1m zuJYi0MYr2^!1sDLi#+J$XhgF0xw)?Lx8oahCu7DTeCv_`I4(ms+NA4>g0qve&DMSO zZu@1c=C&`J`@u?iOLh6{O_EO(Md_eTidwbTf6thZNSSlyqlijr1W)xrtorttQk&d3 zf2&v9=PkDEH_SW4?z??IiMCeQ$!d=qm=;~X8OsUh+=(34Q4l2tAozh+>G!>cdMU|U zT=(0jPS)iTl^<&D^T+sO?%aZOKuV(M>k;81Ze-AO2vSO@)>+ZOnwpjc;#N^HWoank zbBHwe@u+*;Y*Y=Tgqb8v&+ptvD1v)wMa5<1Z6F4StZ$ExUxZF(wPUwVlKI64qSX_4UOhUJe~Ym> z->Lw6{cB(d_;T)4P#Z}QQkO}t>RF{{&b`V^v&+D}q25+#V+I7K**A+A%`Q<#7Kwdo`4j*;qB^fw6vb$oP-w9x%7h1*Y^8x zI&D^D+yxDH($ml%+>qf%o3;BI7!_LkiIlZ}|(=;x(f6nNDR$_f5 z75n-8@U-}Y)3e{*#)s;u5$>~PZFpTIs=?s;J_X|9SORv@^{n*x!=I?WCV#V{4}Z?6zu_DV9YS`96Cu%d?LCBbXFj(lH`MbWydUxEn5#V zsmcaz6Xzvi1R1U=2zc~*f2O)+=s5kRAF;{*B{X51mzPe%C9=dwRD-W=VYZD*FD%{? zQS~?Fa)4ZVCHLPVFf+GhU)5g7h-&wMTBo@J&M9q(-l4^F0xT=4k<}5xdTrM`>C0=> zd`3pJA`UIuU7=WBx!V)+BgRQ|9*4P>2fW{o+=!!GvoCJ>Jv(zle|Gggdv#E7;C6~4 z`U7dQ-4os+CjuoZo@YzkL1d9rF_;M|!O@mKX#nE^clHEttfY{ID_QNamDDkXu9 z4&M3xgI>O+j!95`gS>1Qw}}z)oM^)cpA6L#Dg`ZtDSBW9%c}e@GlfQYZVdW}ki*<* z!yxt@vk&ZvL8wm4>Fhe`=FQ+VYAGC#UJ@w5jwI zAV=W%#hb=^@b^Z;MB{{mDx1M_siE;u?MpK;yDSUzQ7SIV9EnWPJQ(IL zcvn|RuG3q#6F2bMjHiOE5DXMU;m8F+6~O3-x!X4DJx+PpcO6XVL~+ucY!_lvJb#Qw z_zmhD=3XAMf7YVZVOA1Rk(IgJ_BQ1NdFHphy@Tcxt|SbXS742K5S5C}q`ll!=Tju- z!90RKx-^xP1|gucrl8pNw(HL>DH8mWmxoUW9$7;r!MHN3yqgCN)rEZbUHGHFe!lne zNZlRYp~p`*+~>PTd+LijUxW{Y2EVTK!jO-^wd39Qe+fXQ$}ar0j^+f>Wks~fHP?Ti zWmC>;VcnT)sY;4W(ZC@tE?n$^fVjwm0XM1676bZ%bCL8FBA+3nj1FQv9-kK9m$lhp zA1T1^3qpV)`w+EH%R-%KYnufznpZ=$%V*B$R$s9Fq+JG=S;VWMyy3KPg*V6(PKi+R zrh&WRe=ZX|yv+5lA-o(ogr3$z^;A#LnuENX5G1k^?5#lSOo|@y^9ZcoX2i6*)^C) zm}+uPq>V*=sEH}2bI3DkTIJIs13DU~6zT%{e-wjOJL0y<1FzK{MOmiQZ8uR8|B9>c za2RHaDp-q2$z2#YK2|oCc!61J$_Yd(k>A}N+`Iqz;K3Jv82<53W6G;U=5L~Nz=`}= zt{4{;?0`w)irWB1Cmp6!GtE%9njpe#-4jRVRK?AEBpA5eupOv7+}%Xjo1{A$OP34K zf2JIeB;Vf~3;1sIZ1k9GNxuOsjq>~oYUIIO8k~KgIEEcT1#Uz_GaO!QoJbE%v`!5d% z%GA^0mOHu^rb35AQclTd0;XZt9^|KTe}X$|eD}fd{-s_Z2F64k8=p)N7DHI@0lE25i3`z zC8#=*4EfB|NV0t^_pHXDVb*UI<@ba?e~{Iy&EIXc{`_>SWsFDJlRbZ5`xoYOa!{Ma zEA>|W?yrNt{`If%KYl+-;(z~jfB4r=*)~bkV{|{P%UVkrFxyP{FG|bxuF4jw8hPHL z7A?t^qFc){liU|b*hDtfg4{wFZp-&VJku8?qx2nB@Qa(G@0%za+Gpzclc)Pccd2YF z_hZMks0_7QW8AbK6pqphgTO-j5&wX{e8p08^>TNn{sMo!Mf3!tuoe?!vbk+GK9`LTlHv?!<+`>f6d^(HueMW>ENaGWC zMcDO4B#Rth@n#Fe&)s_e|CC#OO}`L$fqcIT(hO*(q%jX9VNh|$^kove@ky45m{4+{dstu zD7CKngXaEA1J|2m;JcL!La&N-0>rnBz?w9l>5aNVxSo)d(a7Dv_}8v)hoh^|>LKd? zK&3+3O`>Eo_SQBg;r$?ZCpn!$O9)eF4B9P(-)@M~$`o5^WaP_iMYQGiS)W18;aW=I zV&q%{KLfvsTK*uhe_U!s^meG=s%q5KwB6LiV+Dfa&+THjRhQJf2$OVw8e7E)u=MYJZXspxea#kg0tG<-p*XgHOM%EM?5Q^4bbpg7ANMejIPRbGjTLAi)Fv!}&Lq-{(pqsiGTLy;0c zaKz#0O8k-R{Rs|sH}n&D22kJnP zqC76xcwsagbV>BhjygfQ>gbtCvj$^a%F7;;;m1uc{4msv@fDW>^4^Rcb%I)JY_Eoo z)k3F+o+YV1)63SAj;*sn&Dbo;wq^^`yHQ`Q5S>%`i5qHEZxJf{n!Jci$?k>+;RGAK z0%dv=f74Uu$y4Mrl2NpyPQG?({^(_}30{TQmS^gBCwhU~`ATh`1mpG9r(37Rg;gh! zwMh2!E1CwL%*vEbhiPnw&XnrRP(c6zAVq%878P`^4VyeVqcrUwzx^9q@`UI7@!Q>F zdXGyoQzy?|s`Lm%*;J(Ej}Td>yZ7p}V4~bne<$BVfO%ZSNJ&z#8mWWg0=Jr&$Vd=h zUfisnR8K(*=h|-NvycliPP3<50w@&$tf3QZ`b}XOvn45aKhCd^&sRIHtu|NgA~}6C zd%i_*jqUAk%S#^CGr3LSH6X6odWCYeMSzU$ZFl*$x7DV0D{ z+jc+x6=}_~WSppj4zd%^h0ub}($5WPo<#NxI-?~&Yjp3}fg7^t|oEIp_WYs3IwhHb@iUZ+8(H+U3^peQ) zbVCXP#`{EkTboKszba-g`*E7^kwv4_}~GDz^83DhXeaE8uGp-1Nt8HJxWvc#ob#Wz4+P zDSpefSqADQ;g4df9H6QAQ>M*nCtb*_Ql>dPwg8ol+ zB;Dk_$?3e9orU@&GsgRI_{o)~Bn92?6e&X0OcyAlb%P^vjhsTMe@jY{Ez9MO-!qk> z;x1>ugrX020O#BkZ{Qwk6pZ#W)+kzIARTves>2*jM4Cv^o>N8~Z;{izP-_srg{ID2 zVy!fy&MdF+ts{|OvBeHWXOF>obhRXs@-z}c3*ErNn$Oq`*+*6CEkoe_x}qi$A`@KY zUbkHEX;VOeM76$gea3U>W9=_ z<`wbk7-tfD)|?jQ8XQqnkeo8Q&g|J$AnfR-aN}@9$l=hLl{&ZB5~=?Wb-WI5Cca1< zW$*AC99cQd+#PUhp=%xA#86cVL1gxD(ehXMShQYW@hsZG^-G4RA-{{#NsU% ztYuah=c>XIe_zH|xI$pua*LU%E>bc`5SuOjIf6@3H&D`SPx`oR~rU zfK!!g&=dH&4wQVTQ(QH5oviVPf7{tZca`Xjh|0iAWvTGFS9YE) z2Xy1vS59bb=S7zqV;6?{H?j$W?Vwj8E6C2voY*+@ZJeQ8rjcACya8S=EiK#qD4e(! zznDu)%jLaBXojUiEu%sTd?zU_uiy(Oo6lCRb&X%t{ij-eJGg9H``!xmBJa zGxx;<*VSd`sjvRt)vN-h4enoCQ#s4kqv)IfA0Yr#K&!v)4G$euJg&W%NH}*%-EYr2 zO?@?V{C}uNMXOM1YX;ne5qbzQuENxU8721cLhB8VKA zt54Ne?ML7-q@Ql9y8;axf8C?>sjuKe7mz^E6L}1Jj8lJDafAB-yM7!NC2$aUkAkC=g)E($<=nbaOCKkbwOr=_Q^xTaV| z)Hp~&u#tC=ov1)lyE{#d;=)ZF1oGZ}ageaZM-d*po=JZ7odRF?U2QpVM3DuYP(@t2 zLt|B23kYFI`NUm{fTcjPZwQ4_Bu<*&0Dn$IH@1pK6fg<*A%NmcYF|G}jPwR>6H2L8 zlsNgtoljc?f<==1a=jfR=T15mhWwFQnZBi=>QbsI{johRhb^hPf6LwkQW&EN4B##O z&JXgZ?jRA@qM13uAuTE<6go0fiB0HJ>T)}-nE8_1NX49O1w(+ohaAD zWAR#5FX=Ta?Am)SBAb>IB_&{E?srE)G_xk?t9C~iS*o%w z4M<{ef-kYgZVW(#(dNlR+;;jS-JT^NEwZUl5x86mc?cqdF@hYFk9^K9j=SpDVb%Gx zI3dugD#f`)yV>uS8MXWxqZ_yYMtyejsK=rlU1NHUt~FPDlpK%Ztf)z}kAJ%}gqlO5 zk!lc*RkV5-R0CfrNJNM5ftCmyL}oK{amF_`B36i*jF?J&5Iv@EZ);0~n$zOsFD(tp zndhvU6DH;ir|g_Ia{Idq9nmZ;vd(JBnWCFXy=~EuGyBPmpbjxRW@~ChCRS&Ux!!UOVPEp8e|HovtaEP@>tAJ-P*DUK5ojt4?smpjNYe_u1`JnvT7vw}m;}ISfq(!R^=IRO(0e4geM?N)Q-)$%8|P1 z6!B!CVg5Ln(7!t^bDHZWHOVq>W?3 z;GEQP;s8?X2$JvM=m&zc(Wj21Mb*2Zf7AO;i*}a~R?YTzG5)i?U6kOEAe(C|?=Tz` zr;ftqxZbgO-5Gg6&qth-%YO35D3wF^nG{K|zI=9RoJet0>jIkT+7H7XAhQY%-it`%GM(;kOpfx_7Sm%{j^x=9Qz zV(u40OyZ9t07=^whu?sCfjyoU%yM0kaF(pS+u>ivgw`^toF#=Pf(CqAP_ZPSzLxl* zFp&=vd4%n>8h?7kR=y*^NXu_uo!}W|74#I{opo&ziczbXA8@F4(Su$ZqVQfjfsQ-Y zGKL2|fs4JvZ%zwwVR!(xnrEhh8$&XJTRx8q7B|C~cfd)~Vm(T2P~JN@)hqug_*j%v z?)ceWZ?^barqxaxhvA{rN8wgVeH4DB)W_pkov}YG&woSJ;)r9LX} zQtG2}FQq;v|5ECsaxkUdi-$!O7uK=^0))nMZ#ffq!Vy5D%@G1Jqs0^241n-JU=WOB z#?A>-(1kkL59s;bS!MVwoBO+4p~1_$ijh$LibSU+yR<#%WJHC&M>#^e#Vo-k8KqRr zBGHx6{D132HZ%z^{zSWpY+=qP0dwTif#Rt?+xz#=)sLU}emY^!!&qEUy0;+Y!P!m@ zj($+`7Pc=Pi09+1A+r}r{K1wuwdgu5sRSgb2_K%&{ZF{4L1s&i4%~cNabRLZRbEDm zCa*J2$Qp$%q9eQ=HrOYD|0K+O92|8kzzaBa)_?6YhfsKSgdF8sU#Ur{NKxvAP3)R< zoGmLXig@E34vv2K%(Zx9)}QG`0A3sS~5LoZ3+k=_9XO zpn)WF-O=Ix?vrQxXq+)z>(~;91C?UygSSQ80PSwtvrA2l;$VEg--Vv@ejV?XhP_Xz zTz|q@?f*}4bBHsX{Alt#@pFs4s7}GUIdNZNEKlJk9SQy#^Gh7GWqK73-MwOKpiU~2 zb9os+3Vz*dc_<>3k&L#*8*<_ubKggoFW8^t#W#rzM@cR;a-xg@H z_ud3(DOGQ?-L7|mEKj&7O_=fJ<>ipw9)H8KnvDX(+q%WGj90d!t@S`be;*>CplcN> z-PqT`1mFG&cp#O^rJUgFQGr~F7r~-yP=SP6Nq`E9VSNKxhd?QVv(paTPOut!D*#{z zLUbG0-?!_)iW+SluEu`(_9~2iI#O5Idgk*g#qXPk(e@ zMiKw6a{5l(UV!tgM1y*l0@I3tdQ^DldW>EO8pLS5fL>dV)w>-e&+TpxERVe20enX) zRdt=o_g=uf4rXBBQ8@uk4i9sb<$6ox-8&I>?4M?QT?wE7OMgU)7nx9wyHNHesZ6|^HySipm)&8(#KX4;AIvJf zP;5vzjgL1Y3{0i5i92&LzEvl#jVf~v4oBTwfQzn)dYl&v);tqeMtqB!hQtQq5Wb;~ z#mL}zsDaeKgs$5C2Y09?mi@AWh-?2g`o%r@!B8EQ9NuE26;~E3;o@l-+kYGwqo{C9 zPfby0ImPmw-^N450F1l}@UNX7@Yv4wwmNDi2y|;`VzI}^CCtmXH`(DjsvIoaE%nMq zJa)okyA4m4Rf)g1T#f3MqhP85hZCfuWa)H3YXUd>&yHuRy{xX^>I1EahE2k-eo<#- z6=CQ=Wqh(+7^@FmM{Wt9zJI#nJ8R(9sR@o^PlYN zI&{~x1D%ZKAfDkQv;>D&9$A=DKkUiT#r>}-7=F6(!KbMb+52(=7$Ilee)Zta9UsPj zr-Y$p^s#^6%SZgXp;oFNtt|*x^}|Oe@dv+#vg{UlNp=sPDPEzlRy~_lT>at}cwZNt z@7B|Ct-lF1%MfK?^nWy!9sJ>0B2WgWIFfkHP2FPTau3Mw83Sxj3nZIIZ8O0M4h0<3 z?chPX7W#HL#9$S=fpcT5w$MB7TN0rws3wckYlu)o%B?>inIu71`FwZK);3WGaHqNL zC07cveQ$x67C;ZxsAvmj!pBccUSc}b^FAwPF8fMWfK%q2-G9v!DKYx12#K;;pS&Bl zEzL-vA37wmhnaT7EUipv-Miv%Jxlk?q)qn=s+$pvCKo&Ep#hk@K(f=hNWK>IH-;^t z3V=J~Gehu55aAv(t`0Rge|k^RsS`ASXubB~c2+KNNpTjY&H_-U7uTGDY?YnBE)c!RY+k;7J52IW?wKIqQR-~ z8tlBSIEzErMgWg>a#sL>v)#m%6>TcYV(Cr1<&5Ih{C_rTM70juia4xKi6LjzN?MFR zNtvneNF>FRGtkxEXJ)?s1r9bVeJp->#+9dBy{W7osuwz|c$H*n+#vo7jtQ$%8Y6VK zrIqxDWPD@>$O4We1!Hr`ruh~z0=%3VvO1B7Lto_gL(`3<@8E@7t`u>Y|3TWSn8A_#L+%9j|Im?)A~Oe#4iS-Yyu?F~9AHXCLWZh-sl)(QSUi2GwnU z)$@&iJ^2QH^~ zU4IP}GWO(=`z?&fteSfP#Tfpmc@p;LKS@rXzw#>z@03-&MchunAr7EZx6|Hi?{?ixJ?Nvd+v^FgCnIMNv&VkZ z-4)bxnVRK59h<7s2;Xh_T1YWwJGk)3Hzx?3RkU`1X;bE^%K=*t%<+DH5Hvp(RRi#n zUJ9S!#a`#}S-szTly?UkzP+vHD4oJ48-E)vD0>5A05l~X5Ws2tOwncl<_@+lz{e$@ zmBv4F78lAI@eB?ef;@^m;YL9Y&_3qK0;<@W0{_zL1n{_o{hMaBmF6u#2IqFvSR;77 zG;t%aEPM~q619hP-609`Lk&1G+umQ+!Z}#iMdrsj(x@`&O1!#V^?tmF4{dMzntyFn zW$^kGP%4bYjHjR5IGZ(GZq*@Pr$dRt0v>py%c;+;kK^6?PST~5Heqt_knV$D_zZ&Y zR}gBHmCA-PY)t552xBgnE<)kTnCz8yQCjunu|tDU<3{(;01&81CH7R zw>a_fyn?2VI1yqLloIb6bM`QA6fd4e#T4Tx6lqAUn7Dj#>wTV=myrJicz;TQ{h82k zfM>Yc)($NkdtvFuLu|$gJw9#+tgh6t#Tl?kB*~b}NKU>)cDH0e(n1m>hNyr|ny6Zuo zU+zS@y}jECCz7VuUA;V!ntwX(ABz%?h=`-yAO$bn%)KUoURRA**@>`^{aL>$c-PZu0Zpr~gSqiGCa6&uXf1sE6;Ssr&yKfBnZqZ_{v1i`-ny2qFp8R_R z#L+1vea%bYjiPtNHGfw~;6*N>mELgNexd)$u6a@Ce&UtFBBU&M%!^tti0<&s$9^2~ zjBCdR+q`CI!Ft8>jUu2eBv>?E9@gG)+<3075mB|JLWq1fy~u1?-TYWJ|A2{9Mo}_K z|7k)CG!^BqAN}PiAq6Jr$J#%>^-m}E?|C8`6uqvkD)@1nZhsTKBfzjw6^6X2GSHW< zH3s70!07;LO(`?T?w(g!LERQ9L4}(PxMYJ%2*(Kf0xrgkjfy`Z$R*AL?)Fon^&oPj zU3J(NNKky8QFzTUJ}Adg8vxS5k4ar6XR-qagFDm0pv0o-B&)D4;FE@SbA2}Og#(Dj zm-E85?j~z3eShxyf2SXwfvrQQD8|0L8vst@YPZCZk}^WPjaUOeX*sEXy+#&Sh#PIW zSm=sp+eYB;$j`e|7){_|YuB&39bWV9Rf_w5fEOpX;#cd4p_eYI21>@m*kYQe*?bv|C z$)86(aDS=)m9TO(?oE8H#{3kQzwuUq$Gp zQJ(XX3pids)Jz@=KkQ;u-!Z@n8Y&t@xaQmU!Uk|bs@}Zcx4$l$z*`@C{olTq2b9KH z^(oC| z+qzyM^Ny)_6LWKAH=PN0t>M@G6(xGaYVUOhd-um3<4vrn+u3gIF(uRx`Uycno|+Uj z6!GoD|B)nWG*ZXOy*oSV@c5bf`Y^eBXMcEiApf|hlH?H!(oQ}m$~P3~OC(p-NjT1; zbl&}wqr-i*3rYK#1-KCo5bVUElz?wHhRI*tf@%AM*`K` zf@Xo7Q8E~*=vp>)6Ze(qcpPA@3X{tUT|r0wuJ!io-pJ*zkp7bS9zwWZ)IJCzlUO~#GG$SNqJ1Hw3+)TPCm_nN~gAZSqi?(A<5$+ zDWeF0D#fZwA>!5Bv-V(qu^5d!q$K6p5hmV>>s)(MSVC;M0tT8{K_G zj~~9Ps)z?^QjKkD{mMHYZL)GTy=b$e{*6Rs?o0N?Q(&LF2q`TmB}5y_zkl(l7KOqo zEswe&QAZnw`$;K4S3!_c;`u4>SR;fRUs3{dXT`Z!vwg1_CP^?4coK7+Lgx;5`oDve z$K&z5UgW36!}))OB?iXG{67ow0O9D^l!+()}#OuDr>%MI! zcK=On3ZOSekE`<1nnNLF6pW;QpyJ+YUdX5SzFrFqanrj7!Gr0Z7Q9JO!@qqJq@7}| zUQS9Q!ai}^{fSf}E)tQUE9t9kDM?1|Z$MP?%3?X`)_kp`w61$8Cz>$pV&6I>CD)Lw zxS4M%(LidYgFQ%)ihp9JB{Az2xy3V*T@}IgqcP`k>@&?~27?F0%HLPG1E;0CXd6|l zbX7yZ@gqORn`K5un>duDOMN^#d^v@=)OoiDq^~#Zyd*Tb3*xq7S1p~IBeNo_)`xa2 z*W;zkL)e=wM6UrUILxbGd!}Hrv$08Ya?@>PiKOD{P zd5Q3XI15XGXDH^O?*H=h|M{nZx_9T^7rin_3ab8O)XkABiv>)hYeimcH)OKi&J(|J#W|Cj$A4_Mn#rgWg*mbw3{U4}T1!ij$@_*obyU zcCHiLbemV^_}@J9)9T1)D)SYuiQ{~jp4yyBf%dJ3qklZ}hN# zw?^LaU*x`Q%pG2o^=;S>joLT`(njHIS zVyjkVXJn{4E0yYaUYN+1<#xZsdUsZphcK)tK~QV-xdCj=R4qxq(-!63NQkTd(H&6= zp0vRdafxYgUXHtbo#iH!agIwlw+c6}bBKDUS$|Z7RjCbxGv4E8(@yRKYO_mM2vskgbaFA|+b@0%MuI;Y3HA?rPsL6W4*a+9_q|mq z|6J>d{R;6|swE~x1j7OXF&%l9qU$&qpD(Yh>Q=%N3?{w}wk-P?_hli^!@pp>t%Vq%4>x*z`# zp#dC6R&Wb-B*pl=8%_agrbutNoM$=jeE2a^Hu{b(6lS8f3`W}w8QbAVD3hBqLVrWX z3AcxWIv3ZRB@KrB@*>B{#D$-z#c4^X^%S~wCC=h{)@$k#x2Xp0ON=^cmArMY41>Me z91d?B`Nny2TZ2|9@LNj2E)%<*AiVz9Yvf_y{XZ?18t&L@rRBXyGWIf&)**%-Da0JO z#Iln{EXd&5`5<+HujjwS3Mt(sF@HKiClcUYI2*#vh%i9jJp_}ZsLDL2$vlGBQda^` zd*qXZ)T1`+>zAMZ<@3$>A~DDArUi%vLh>wLePDaH3eLUH>Rox}uu8e0*3{q?xImOc zhv2j=o1o>P6ffO#P}Af>t$=CZd=JXGKlI8snXgGc#bOJ-~;mVet8B|Zt$ z5qU?_kO?9>7WneVIgqupi_)~RDmog$+Hy!MkQI~B4wv1wCP#rGeCuu@>2&CoU1t}r zlt>tKpmh3Q$eScIA%Mc0VNKZggW2k{n=6} z=byIpdd81l@fCNrYI`K6zt~&u+7>S>xT}|_A$pN%N(4Q4B9zL#Q{B--NA_>q&$yo- z-Tihsj2gERE_9kepA0=6y_uhmJ16yt+&;^)y)$6+?DE` z5U!zE`pNcoOzl+MsDG@G=v?L>&d_3!#g{!{&D`aKhIw-NyPm_gWvtVZCe3%Jw@R7g zW9~*L>cnkPF(a*>g9QKX#Rc;>~-y_fWgC$Pn`f-K2 z>s08AK2T>NpMPW~g&Ro2L6s+$|mz&{X*9ueTq&{=eJVkJtZtjs19?U+6}5vlMi_CRRC4VW%{~@k2dyTKmE&r@+eBjpbZ-xU71hObPGlVye(XvQ<`nF~^KO(#>5S^W z1oex5WPO;tD_0ru;557s!6TTY+$TLa1*(Av@yGcU z_eP>hkbe|zYFDbOOZeBAJYQT>$T}-7O2}K6)d+@6T!-Q?R0HG^@j6CLElfQxQwJtI zD+yIV{il5sE^3Ce%qhVv%>cTnB+(>7Lxw(18cK|&0#*ro1k1vfc}9&8`fYbd7jEiH zeMRyBLj2?sH939VM3^Oe-~Rfe3>R*MZN|r2K!0T{N<_E>U?yZ+*Vw++>f17*TQ!Q; zO^QpnR=zXM36<$ockc}D+`03S%qZ3m&<{l{&8_ZUyL%=NILow6bCP2w^zfi_dZ@@Q zKks@%`aE;JaikA=l3<-7FP6RfzU*3O!B~*{2<>tac^pKSC$6u9UbkHzGP$%=mZN4A zcYp8|lc}U$6gpRFrm02)A$N!BZ)Nit`Y;-?kf7-E)_Ou?h2N+t_9DOHbVWC^uHzy_ z3xH&?x&PyOF}1ScZdxC9;{k_nZ9o0t;u!wr!(}nsa_$Q8j@ zdfa_G-%AF0i}l%|+Q;=i>3_WAgIz^zgp8TUJHln`tkxx+5i)^2Vp0Kn zxinge=V*X|XqTM5u_SK1E z*M={fG;B*m{-8)MchBnMZe;Asl#;EHYy9_aE!*29&@y1}`Id5~HSN!5pd4E(PJjQU zh5DXU6H=C-KJ;x3Fc`K}slfs8wdMk48~~RebI|SDWc>HtnpT$JvceggWYVhu`6(UVMZcetv2E(H5mp6p)RKp5?8Q`k0oBj>C~aEhW|zbtm$-wdUGGae%RV zmB`$9Q{U3zv|C)YLXplKt<*AG8h-?oLmm*R0qzET965fYSpRiuX%zEk%NDpE+O+L$ z*CMP7XYighwF&nMZvQB{`CG1rmpBJI7kHEvi{~{0VB{U<_s$kGsX$+EQ zI^?M<+fYUdIvX+u*bBVRtU77!g!4qYp#Fz;qxQW_!T?rcChQ+ub$V$r&3{&$#%gk< zmeSG(*8mRU&1sIDsx9)7Q81)huv!Z0U-dP@jY3HCWSVPhVWicsH zw6AZ*-4tCYG>2BL3D-5aW1 zjx6?1__n5i1m1O(4?h@+6tAg(VAo(})1@i{Z+YC~)C}E`0 zLRJ_nIVD`_aB8W*YU?UJ(#hN(a{oQ4p2zp1bzN`M?dR9uQo_CPN+?0I^^_0y!1Mc? zJf#7FZ+eORGaFp$BaSb9$qAgCE`Y*-$kBvDlA<=uil}=`$izdx2Y+h5*lqSiT*}wE zk`d5m3;XU7|N_wSA{(i;#3xgb79%=6{K%+tWGKA9AO}fI{a@ zxr82Z*5qfIM}!n9*Vd;4(F z=73Z9D2MRN&;OD#)@+<`=Msh@WL28Lz`o+h7K|R+-M?}1a$-=^b8JV&L`bs1*bgUc z=ml$*uyrlwM}O3pwZ^kArm(yBL~Xh&;K}ca)Mj({W!?8`b9e8FP;y~rWz7stvJ}7; zT$MMF?P{AAsWtBLrIKM!yXkooE4K4!tZ01hS8lYC6= zF-eyJH9M+PTE+IW>r{Nwz8w@8N3leZIVd_z42@$9vVUeiu;uMukVHXw&@LVO-V<(l zBW{p*1@y%)KmW^?tPkXu`pQ!88FH9_!|I$$>^aEMC+hp?9J%%$6T$Pyy~3Q|Z*-{T zCrWo#sS|gqJiM}VV?LZ(Xmlcz3*KQD@vx{3!*7p>%(KxpPvmfPoHa|+^};w1(+8b9 zT~c&_Y=66OLV!oIllBBqfkSo`{cR1lLy0A%3B^PF^7Fr1m8m*)2}&ZU&6cp= z60UlS<|z87fCEGUp!Q zs^l$`TAV~D>(AnvX?)#*N*E>bTo%9ZE@GbeA?t6Mt^wkGoD=enx=>wmklD(yfojm1paFEhk?3( zhc%8bxLC+g9dX{k_V$r6uKmIGHrPCzJ)N>4b?Fkg1m>}4KQP9t^`ZDmdmK`a8$rOECg{FG1$ zC%u9e{$y&9*UG4d!`m?Sy)~~OfMln;^+wY&Z@GgtPNj@3hZs;=9DfSekl`UcDFGaaRe1FTa8*i}iHVnE24*vAY z0=fdm2;~#(wbe&38M)<9n7xhhMsq|PKC1JAqu2OMlXOKz-{UeOK>`ppC(t``>9~4j zG@O$pBMb_A+q{?}n#dbnofRuk-fx%jj|HC$NRVWlrJ`&EKKX4r9H}C2OAYbRgqU*< zl8JS$kxu$$QGbm8z+{)m2x5OQ84w0rqpr*8j+TR#THs`T=`PUbKv&WIIE(*yYcv~2P%OVQl=HRLO05ND#xg&5OJIG3<}!8Ky@b*Tw`T1|AGWa4^p7cX0lijt$~ z$vHq|Xn*sTO%3fv#3zXpCpuB2k$=Q^yhRDi4$TBDpDaLep(I9e)SNRAmKv>*)^iYs z9$LRcY*k{F9UA#%&N&T4~k`J(x@)P<$oB6&%U&ioq?-Ryu931K#ajyNkXDX z6*trK5%7tv>(#-@rMcSXQ*9)bi&C;+JFpT%Kzk|nvM-`>cvvYqwM$uaeASBF%*Ke| zb|tOKA0R2FLaH4pNb#)zH8Ds?SYCco7U#g1gp`dAzZC!?%bn`GVBgRq-N<^bSAou{cVL`S6?P$gsd(I)V4U zoaW~V8-$macV;yRG`u^oBMa;nNsvdg3rPhSntwV7umipP^Lj5nCeyr1vshn|`}!vl zW?n)gp52?MB~^{s(8yTbSP1^|ewqt)%{D(a*b9%7t1*ODew7$!ReresYt7b5#)Y(;& zxmKSIyY~8f>C(Dqvpvkz`?{+AIR(FNO)R)sSHTu&tWf-YSq&a2NZ{EK_OK$pXN4s?X^Xr_y-Q*?UwjOUXZwPZrpWnQ1 z7Vz3qQI5{$Rh~~+`KPaH|0O4vjDIeMsm}Ga)`#9`%Ntj+8>v5fotA@IrSGEKHz`clQ}C~T za}GdHlb#sExLyi+-t_uWPDWZ+nBAgG!!>?hAWDb|stBmfg@y4AOR1oqNtg&Kkjh+c z`TYVmr{=63ej!DL4tEb;$HR!~v3#JhxRNghfhmaaPGI%2Nj$s@sDD@=jJ2pUAJovo z!Oi$-YnHC6y*Ww}sxf~Sq zEC42N7esw}SaOLr_CSEnARbl%WABHcV^H@&Nz|9cq{xaP%+)~;Ni9dpJ27;W{)O+sw{4lpf5XApW3fKT8i^f-({ zrhYtb0!0eeh~0=hv8gNuH))r7g{h0Y|aEQoToPR9r+Igzi>5(FyF_= zCobUN;?u*_p?|hJGrp}Dy0sB2KBAn_6&!M;_634E|L9TcY5Y;n?CkKHZHcp^=QHVV z%f7JIA|tn&9NiN6AaH0l@u$}8`Qtgz7-WQAXQah_z>Y>>=>VZ1N4y+^@X}hsN$CPK zCCa7o6e|RS5)>R}gZux3-OjsU*MMlCvl7 z#fpHa$z)O%NpD1sqFWL3nzzS|Wxne)GY_FLGLBnB#;e6bkIH!20f-m~eZy76D7?t# zQpz>xq3E1UKx+ekt-G@N?lzkzmwo7q#fxNIox)2)iBU%j?k+i6fIxG!P`f&g7KF9a z@nv=-34b?q4m~jljYy<}KuQV)3I{|sjcHyL9Na3a6ogC6VHrW)L4PpVo0;YnYJZeE zOI?_gM+GFzGTITMpV3lB&Rr*&H8C+s{Pg05)EaO@CMnDdV&TrWqS%EK#E`cmb?IWh zZ($Y~15aWWc3wQ&ef9)iXJK`hymEv56&o!>!G9hSS5iuT1D#$0Xby2BELt;nwgkBW z*X@YlTs$!;Ropq^<>sZJrC6S2QNXA{0>(}vdSdI+aTj!&5Rb)y@{-kYk|E?AN&-Ca z4wQ7J&wkoNB88;Z28-QwmF21e(RVIt!xA2@|Mjg^W#Zo%e^8+uDY0LepS{* zatNb7Dbaq0J4xtA4+wdEECPmWK{D#Yq-gzQh`8pN)~6*g(^B`RJ>iT*L6_YpJ{J=C zCX;A;qQo_TR}L&R3x%@JPTP_P&kv?KV+$pd27+P(hcFXWs!Q6q%gbA9>$XTckbhyy zRO-=B0nbC2oRi7&vR_A|cK0O+u1-Fm#$DedKB`L&;M{EoS_m)V>Ag-%N3Mp;e_3CpHEZz7XR^-#{32VJ`UMmz@v+|JSc6_X?o;;B-D zCmyFIEHCenuKpKY7V2dQijaPfYP)n)(@YOFh_@RrrL)ioO58=u9#v9vX?C~;LkLmi z4UA8)k=!w1q01TYW`(lk0)G_)b2=Cnr)E;>GkiP@O9Wudr^)dB5$X}|6bUho*#rm_ z9m7@)r0k<|70y3;6X-PIA@9Uev*$8&J|G8-#|70YXSRVr057)1*rs$`AJxyXt;Q6X z0PWEgYvSzD2SIJtOVHo}Hz;PM8_+SB;tJ_1EYXW9>lN-5i=OaVV1Ih$F}0;vir^wv%k9}P}ntlt?0~ zYcd8rhlNZ0P-~_%6@L@U#b?)HE0>r55*gVzGsNvZN}7<}YbHq7oO9D5^YqxdVmWr` zN@xBtB`tIQ02#HD40X0AqYFdVKA9K9Q;*|GI%1jR{em-k**r*qm2BRx%YB55D=qWW zYov}u)oCb6M$EinNVppY_&1{&vl=(2p$Fo*;csBb(}X6$1_2fH9QR8KKSv}G{*dQd^pcqezoTyWx7>cZ*?2@=1 zkPU?D0frrsC!vQi_~1SbDa)HCxl{QPT%zu z$k;xULJw`~jei{EPRzFD?yO~KFe6GYlBbos zJu@9#+5Q`b?Y8C&Yp$ofj*i+(bAk=v+7;9B394lbRHb{P+=M#6AQS>9yPi+z5< z?splw)`Z1kA3MMUkj{9c!OIP)E3F#(ozGRkWf6xk|Drr!NVcU(ixk={CjQ{VwYGb zLYR$ z@_)rZ4U3|W0%}=bEk1ny}bE?!qb=f`7 zMRuiK!1HsAc3>{`=wo)rJ&ocE@=6OZhafgjQz;2RIG~f16RMhgxikZ~(>}BZ4X{j> zdo($1X-iy$lC?-yWM+sCrnhytn>6x%^M7@EOU~Olp$Rwk-d?MnIqut9=F~O)w_#Pi z%L6bP9Js_S;+Ul&fHuP#t_}V(E>jbk6FwamE`XC^9Z2D_or(FeK3aHmF+M?o>fyG< z;4PlRZ@>KN-L=p_ec)6|iK$KXP6&3^l|aWm&oJ5!Kb0#Vi!5y|A_0(8;4cZIZhvs! z1wmy)#umAVWF>L-vatg)WKB~VrxgI#NYvoKAy__hLnJ`JCKVHo>@38V1Ad8|SOMjq zu_k?Fdyx$y75}{x%!odP+N=7mgV@iAf1L5Lk1rTU4 z`z*Qe#PCKdv6FmmBqa#7dPhm#hq^$xMb2*ade05mdPV9r7C4#QDbhaFLN>MFk9#dD z?Vai{1f7=r`1p9N%W;zSk8(_y;ONxL2OQ~rP$gxxcu47uL zGY|K9o?Tq_Zt%A6r)dB?`+vKKe!DzOvh4f$@1lG9{#il49NNr-m$dpc3MLC1B8UMY zGX48*w~LK!2Nuu4kIQ{OcUTQ?VpQ-dXS&jBi--2(_eM=-eWA@X ztNymLze}??;P;|sa8FUM@`UeteO}jd8u%tjGa)BF)@V7GVs_wm7JruyJbtQq;2W0> zyrBUeIQ?*qfm0==M|!}@AF3L3KN}2sy{mdEyM}J_>_EZVNHoP67m}myF zs9jB+=H;GYS6tk{=xksO9a#P+`>$|o5{ijs4ssAG!$QWExLdO^Ek3 zGNRZT?5g#?-kY-xp8bFS=bn?CeN%8RU$Av-`^2_wn*;6&Mt9tfK@9x!W8Enbc`*(&f!J8a5n_#ADd65^JLE9n$kMiqm6GeE+ z(Bk-ixRKEORsqWGweRTMvwNJqF`P?9@b6qw3#e7Kh+F~~2C&l>VARW*Z$k9tor9(6 ztydVBtD7&FsNIm7O?A?vWYH^X|LCzBxqyO?L4YkvY5GD=5%{QyYzDt;UoRT8NaKptz6B|FiCUD2uX}h%@_R zcNec*#l8lxtiZ2_f|?FIn4k<>DvI*x;KZHK=}H=wSIZZ1*Os9hsP&D`RMe=uBg!9K zahOh(q)MePKiNf)kcZ|PxS_gnC*a*g29dczV{*sBrq(_rS<4=z9{jLwfwp4ID)_L} zvWli~ZJPuKp6bE%8oMbH~{7Lu}`11VzM z=g!NH(_3Zfpnmr0-)?&bRFH=ZMG$rCZxjel>E6mR7vkW_`zEN2dfnjBLEXL&U!KiJ zR+czG+Y3sm?P2V5SBD@<*>{Y}uWz)aSm49C7b$N_JZVQW(V3?gl89tMHgAh^rf@oGsi2fl z8LW=YFJ<@lMTF7heH#hX2U+Vw=Xah`OY|K)?F@oyP_TL^H6st?%w4?)?Up3tB!4b| z@bwFh1lv3FZxWoMY!HbEXnI5kvs|#d0rj91R&GCPVaH|-5fL1%K=4iY=)4Y-z=JmC zzthjcPUM4U9+Yw}-|05=(N&1D1^Li@n;Xu)O$Aoox3p>;OGq)rzG>C6p$5*{jw12- z1R!Odscu9G&G7dM3Wqx&0X4$hd5}@S04L@YD;JHDOLUyqS>^@1LlR2HkV8yKCD(TF z33ss2LyDQ;`FvFzw;$ZD(1a;$3zKRspW8!8t)z)+?lsIJ8R?iZ zcR#r7;!!Jt$mR(QLDl4(aBAW)WXSv|Qr>iR@vmSwecH(KQ9)Bo0?R&8f*VHwu2Fj9 z-?c4b;pK$ttk;x$DnD0+UQ{dY*bTY!SeUDtTyUx6(?NSA*6`KMi_8l48E{nvQWuu) zqk+ux0VR@cGFl#jAZM=Q*^u_TpoOdW#+fD*O9n%{u(PEJ(MEV)?R*(-o{!%HvI4($ zb#_h4k7Y$@CiuQPNlVg0Ny?D`g?t&%jx_AyG>yb#J|=!Mu&lMmCS_rJ>kVKpGlgKm z8DU;T^hkriqVa01nZfezfoyhW1%Ks)ywU?6TNKGN@kpR|Dl6SKZh+b~NT3zKs?FYE zT!8Xnk=CiBJN^ktvYAlvKQcz!*g2;gFESC~cl7WwYMclX5TDJ6e=1W0^d-Bzk3}9! z_(Lx%hLYRS1ZQ`?9?N3rhwyzgQtb^E3Lxn@YJGO??W$a}g8j_r`P29Z1cwJ!Ie#Nm zfK+l0QG1wQs`VdTh!;Yo=bB}uB?lCanwnczj5R?*1HCQ@2nN|fSt30x6)~$4lV5oKBgU4nTf0zN z6dYwaf^vkkz;u9j0+rP{QY)UUq(L^CaM9m;;r!FLpggQbLnGn{;5&(O0>HeA{B-2e z{T33CHi#~ES(mciXpSokb){AqwRzF`y==AIVJ`WF!d#rdl&Gl3$XBkaJ0^}~ii~VjMO-DI>GODV~2DmAV5nEeUobF|FdSvDE)xiq|e69os zsF!Xw6y=Y)ZC+6MTMVw2w&(%&jkTSf^^xdWrQXg=Qx~pp@OH_5?`AnKeT7MSntBM^ z)bd~0UVq2*)SX`(^)sZuYT56(0^$zJTMe+MNC~FAo|mQOT|J)04Y*TZr!q$!V=<@3 z8`C+8jpCmow#FPJi!{Rr8*++f8ENF>t)^{Rc#oP_*q)NSzcTVmW3K?OwW&IZMyBt8 zZ-S=o_U>QhHG9d<7l$DRT6~T6;w~#1QBt$2DNEY&K4)YJ_IoP}QfUWWiYbhLZ}IX^ z<5(#M&n-bRcLg+b2TiwtMdMmb!RooNC`7KO%c59u54TpYf^|xf!?h0paF6()+V@`F;nJ9^cGN`b z&EC?~PBaX z!1C3$x$#cx`KqR@WPLrWD$4ooek=LsFl+hZs{c*mg44Rn-895h(p2$S|L-Q7Qj`OM!Q)bP*ux z?t3Dr+-pR3$j@~mL4fKu&PE3wNH0(tfKspBN1&~x&6!73L%#z6*r#&=4q>@Dn4~<# zJWk#D@z*6?cFwmM;tF?6KOW=PdW?H6LDJBHFSfFGV^BmDfQUeL5l}eISr7NTF$)56 z4~Xc-W2aowT(8H)7C9CgzR3A{VYqDei2X?}Y;{_F)DD@;J)H z#~x}GaBrm!vv-97+t}oV5!b9Gx`osrJk-vdE!xOj65iw%$;RVI|8QZL%Dp8tKl6Iq z+l&m-6%?=^6y<-MnHgk0y{91rkI4=w0^Z{LC7OXCQQ;=nR@o*Fw>l<_t>4e=ZEbBk zgm@IfLI`>6fTTkyiIYrSHZ+nTVuL~bVjE=GM4gmukd)sSXFgk=EhOt4I{fJ5K;vmU0C<}s zEdCG~ALTK(o<*r|yx~>W2|){xw48C4%247`K!B2l0c`6A_GiX zaT`n_k*kOtvNZ`|NizkEc=T+CP0@LHS3%)&8yg9gO&66-gtW1<9sbcc^_s8r@A4eN zzyjIOxvHq~l)VU7?k3w7w45LR+dQ-+{9!VI(kyuGoUN(qn!j1L9d=4Ygey8gvZrq` zK|3n$+T&Df9hI#$*m&3o)+}(}dfQtmv$nDVQ@-yu9nC`!U+o%hbn!2n_?v_CC+E4D z_q{XxxpJiQIAU12pLxgG-G~s4E4&7ohNN#VffHfZLX>7V7#}|}Hq;3pfE&>?-`#_* zWIwNHe{X%2)?|Whvzd_Ha@7M1y{K27zvOUyoF zbhE#K@O@XaYAKt}Tu7=N!axPHw_Dhrx0XJ7>iDO>1hB01Tt5Z4SiaYmmiQ`FjgD#( ztm5#PXtq!8S5Ca3S8E>HtlS}mL?7KVxRAK{&u!0sRx8FVXkEc9Pu;7Y&1r@bU-8o3 zR3kR zdQ<9l7?WRk_P_!m?waeTQH#DnKTz;R`ve;r2G{{zhrf%1d<5%ExPuH+}jAy6O-h9X$=_hA?t`{?b+V@%WxI z7(_!H%?8YvJEB~+cm|S8Pr=%yaR%*RK&D#|c46sr<+KT2=RCPfmRHDv1;_4j>(bTJ z)Yax;Eq*-o+VtF|d)b>_^t`f$l4B(dQgkEJhIV5gFog;J$L3~9*LAy_hiyylO4}RO zf)US!pezUQn)+4Aoi)W4V3rC*;MB?xe*dIg4(XojInP{0f0Pr9vp&4^#bovO;goMx zA`o=ZUgVcD%_wtBz0+i$O}E6l1|gA5-0wd43g8kQF3HA^Ziv^FzDSS@Eiq-lv|c^0+C_ETwqGffAOK?zGdSVw|kDR+y2?o)W? zUOLLJFP?Ea^-c9{?nT7sIQ$PBFq*Fy)8FNwU)n%~1c<;If37lnGSOCtkdpPvNrv5V z=@ueZPOO?1%7rocA2Qx^FyC}lRGG*vOD4XlwRbFJtZkR*{Ol#Egg)7ssE-ldDIjY3 zC|)`M_=kKU9Qr7bp07>2dtKXd!d<^I9u>EoEOq(}ZAa@`?ac=*2DNIW>L(E;na^{T zJ$?Dx>4(_235J&1EiGoxer?VyxQ5kH#orxemA>nH#iAZ2#?#0zMC!gOt!;OFj}lNS zY_IeDPFWqTma0*BWOaA2?iO(1gH=d4)pC3TkV%|A`iW7K%PI}MH=pvpW@fuO%vWyq z_zybe={u)SP2koYCNrywgtnLFo<%XM)~t@v8I{{ila|}`IA@;;=qB%d=%^A8c@_hC zCfkI7bisFR^0bZ5XHL#rq% zWN4W~rj9JSy&H#*bZdwI4<=w&J4`o73kF>&j|h7R+>HB%J6Yw*>d88uy0!Z7rP-%C zRot%qu%|xGi7o zQ!rH|6tHj6`r~Y?{lm^lydy)g&HZv(vZL4mD$s>)yN362`u~k0dcXW zRN%8v{^94^&-aa!;tk>B;m587zbUw9Tz5+TGm1BXzOe3}+kgTDy0!?fdlj~kKORtF zuv`7Cp9$#9b|6-Oa-24LA6cGk>6{3!&pEQ}ztfRHq7)$gfG%C$DQjBi9`9Ln`!@lJ z$D^x=VyhBt=S>Bf*<52i7bT|UDP+Nh5KfvJ65nQ*mh3RkR_+%>^4juVeHfA-4#thc zF$xE#1d1vhMezVV1)O6mD3S-i4e~5Cg#TDZ1D_`_~6#%g>%LChhu>f$)$>AkU!BR z=dgj=Mdq5+mhF7(9|d)i$^t4ihuCvi{SfH;0uwbI!(g3 zMpO|pf%LhjAm2z)50}oXi-9B`90#rFimX`rem8~2?eElk<8w4dw@cCDWoLfN$4zRa zW2nga{Sp8yO?DhQ>JaeptpB~A3^hm6GTlUZBaGNbB*dE@($hV$KGScVc=M-=&6-mh zJn_}GMd(+{+JLzdxqH#$B)b%6NefZ5DZ?e{JekX>c7pibo_*w3%X;o4>NIa1CeSTw zv4MVssHcs|2fK+YSJ+W4>HNIAQnA>&-3=)GCnezff@R$BFGk3A_F3V?;tvF=>0L0V z$a_P2OqL=czY^~DU(27xGvgb4sZ3JUheyK6CdHU=`}iZcu}4NL+Fkqz^F^BB7o5UV z)ze?!I&dn68CimHQl9NaclrGhVg9^vMixpKt>xTjH@<7m(fc`ReK-XxkWpoA7U>0xLNgJ^m$#JHN3dLp{wYCF79A&!fX02V z!JIj7BdRP-FU%i^R=F;6e7SR>>jm(Q1?cn1IaIxi7m1Tm3^gis5s%x|-x;KS=F4(V zBuw~vldTRZysX-&nwT%W1n8H?;a9NMgtyn#sYi~Oi}@ADYAbpfz#SA?(QmLUZm3iJfipkCdi&*%URNedjLP18>7@$_eI5W#NbW4AD>%;v^ zWvkN2WK~rp7ojusoy=>eEGD*=BYn&(il@apYM(yM4%t4Xwe0BC-+X3$%nv}fXa47x zWgp%gA+&gkzK@>OQeqM$EC^7anpN9d*GfA<@iwe!ZZaZ&q&GQ?A!Exd_FkLQ*b~5< zpKg$aPk>qCPo1aYiXUZT8~wdb7FnOcyDjCI*P$a#$L6=VLTYNx&&tZ8YC&6wp@@pp ziv zR)e|`)_ud_BmoMe8-di?3zvO zJQu=it#xLkRo1BVDV*_fKUQH`PI?Lzyr}dkN(a--~ zIqp1`nb;_edXm|z<{r@9*Fhe6cx1%w&YJdzS!!6emV-{Fai86o6{=-|*Q@{|18n=b z$5Y!eP`W}>#}rOgQ&xf5T3k$V)Hj%W**L!H=3;HbMSIOgX8q)Yp;4Y&LB3at^7)$m zy~KLvX|jU|E*vGE+)btE{jz~c)2vBT>r7+zHt5Sfop=P5R|$Xs?z7Gi@zq$;XB;r^ zkZ<3=(AvwTnv#Pa`lid;w4^vbzWw3u&C@7XCLPmvXSF^)K5>omxAj&PR7UKzdX8z~{x)zB(YtsYHfXuRDb}LSxM^e5%Fn>p zbZwUw--luhOB1plb`gin{0o5EzNsyP-C4wG4JfNqcn0DdHWDMD z(Df{oY>rPLK2eoh(qm^^%-nQrWM;KVQ`ycUnR_&Rs|-MI{x=buhoSC53cF?G?u~S3 z0;V&=NDUbIsD+t&YF%|USWEMiUEtJI2+xn>;=KOTL*Yuk=0eXEEI*q>|JjPRz0x|! ztP>iW${V zUo{VrS{xwT2-`3r)3nL$U!(W!%MO`0ftj_s0)mbuSy~~p43achQ%Og(8i!d;%4+e+ zp@6W)XZUhqN|7}qu`;;TEPR~&o0PNJO%0Ld{A-c-CIxBgZ85NMx>?LgXI$Me zPiX=*OMn1N)v4y8*s>C#2O8B%8>eH*S8sx2lFq0W6xN%^4Qm?V;e&6N6?UhgwE)O^ z%+?a=VRX0KKZVpLmKkV=WF(HU^kJAc7Ab=lm#BzDr=sc9TSy{Y9526ZF zv>@9$9yc!R+SpJ7)!Xg+&@P*M_ybDdvy<_aY-Bxd1PTgTHsPOA(#g8N3^(f)EMJ8w zZ06@7mela=vm=?e_PwxWg&=bD{43!0m=5%r&O;A-afaS|c|6`Xzs72%gyGIPGv_$9 zMOUD}z~9ANpwq1&JvY-eN8gBg5NMj0GnyY(it*Q*IpD6>_jqwpBBEHymjJ{>2oVxH z!TBZs+8B{eT>@Z%Wljt=|M^#s>sd5votINYVUX6>BTv?nPoU-G#2UI5+spA8-RCv% z-&ksLH-FU@s>>xzpk&Kgt2Oey%+vV%!zL>imb>q!mkY8*u291mN}c+urJbrkzBPV= zQso|B2@h2cMa&TanyBB)3;-C8l~G!3JZB!8yRCv}537z}EgCTU1tlJ!Uuk5?LW0Vf zRJBX)Sc(6df>04^deL(ZOMY{EV;w($Ov)~8n$p6Q$11g~d9F>(Tb-?Tb~@ep#8fuH zIY9R7&l0R_UYD!p_5rUj>t*hh-(QcI_^6LM(T$&uiHYHh;2qnR-KGb1~U+F@V#neCobiLGePJI zlBQz&eCh1pbAQKS8neyK*Qc62@5vCyDQ4U~(-b^QU_wxj>4)Ri6_1RJr1GvVyLao> zo&gRs5|f5Q$x3R!lL0@~Em=AnVW7H^l;r{1vY`P@Evfy2z&-Z1y8O&ED=Wq(9$=5Xrxxc}rvph>771hWE% z#;J9^v#ObKTpQ2xPn_11td?gT4gPkkfj4QPb*q?Nq+kSZp9ZX8#U3TmQxusP$s<1z zNzc&z&J2J(tye--Tg)trbyrN!5o*A>E8LIBD{z5yx|NMm)8E$rdKtYkMb>mp9KA?i}&Ima<{RqOBjrdzB{0BW>?d+pvE9soJH0JwjNn}A-CU_!25cA zt-ut(?ews_xf#0p8s9vg_F3^h$TlMSFx$O}QTx;h1OPfj#Ius$K4$w?hmU2pUB8~- zhtgcpKf`?*9w>g;QDgYPGtQV>EXqPA(oS_;=yHlFzI_^ZJTTU^!7-)0T$B2*i5~6T zI=DSszo`?+NshJ^w;A)7MuXyynWTw5#li>kui$v-oFi9pTNZBresmQ2ydSC)f7j*Q z)nONMp94INb+Db(KITek`4-Pojpl!lmU84%Oay(b*CnRr1atJ&1dWqZqnJzGLRt7z zmE}z%Gx1xpzk0xgKK?r=JetJxWQ`nMargskYGmfae|7Y}5R~jyODiemPj`oY z6_enO-Di^-BryGfEqm}g6god2(wGJ z7$&7{h{4=;S`;8*s6L0o(S4MB>QH9C{U_wFx(B3sF&h#Zq=d3X_%Ub3j>_xK-ql#DP@-hqmy6}vnJTv7h4L! zE(M`O5QBHcQGf_>wlnYtVJV+0j{6_({ly}YPDbl7*X*k9KwB^*uRS;jYI6AHAoj0& znu6J2a4rF^$ZqZT_KUCkt(KdI+!_YnLN*`|;udF;&leB_$Mq%4iD@o#T2Fde#jy8I zD8;h*OjK*}jI32>j}r=GkaOpr4ti`Cr$c`btY@K_(RoF~LOo^?Ym^oXuP9clT(l3Z z1C1sy=^kkPxKiz&d{iP%7Y`qs++>`jAXjcpqw&d`mZ}J>Pn5#Tp5zSjHxgz07argR zfbsm(CZ&Vvk~MDSf_?!9#V_k=PPUuE<}PamZ)DN`9p0DA)c;SLPN|@=DGhvP-Fyp! z#?%clTwjKX-FlKzdg(lReV-nV3hHCm7XbarB_l1x+?7h9Rz9Rv`2erZ9$E7BkG&Xg z&TGfSzhgFoO4}!I&n&h4cL-G2#tER`o}A|8(=cS8nq$pJGwOg3nkB$Pw$>+4LV=rv#%??xF9 z-9~9~fUe2~8J0-lzAo~wQA37LfF=KPh1P%b#GKG0qfIOkmyI2M{x@JjznPaWudA-8&QmTw<%dL;f z@e1OiTqHJ-3fZJ}qj%EMXTk`Grf@P-hx2l|V|rICIj?MXh;fmNi(-XXx)Ot!R8-CX7fB)_XD<%9Vy?17!=X)sybP#6ABao)%r6e=oh9qpT|ytp|@26 zF39tEE@inCbU-m9-e4`*sFPeto&?^50^wm+N5UVz!~PNToE|r?n~%kakQjj5-QH`3 z_cLW0#ED!3UuB{$}@HeOhlSRrJe6uQ2*-)QU0jV{wPvoKwrWUz;03-g}O=VGpcN+0Xi1oPXNhVC^#@ zsk8S-*EFHS>^W$;smRi9(XMQZnSP>MfP$5F%{6+{!OOQSxCk(OYwt-XIosID`6?y% zB2@s9<`d8g8o0klo-bl3UouJidbV86I?I;c({J3R#=${SYHeGzwB@xP=Ut%dS#T-d zJ5CsEUD`ms8=6fxXNqJm2?dGPM;>P=b+{K==>hYo$9rhtW{vd%_5`OkI1ynO9q&Uh z!S$;b!%Tm_5e+aH_COgDsIopYG-bf-Ssn&FNp-qVc+pEM_Y)(AC{ zDN9c7^|aacH1+j`2pOZ_x#j)x67pHXGi~zfvUXkknGE1_(|yk~mM_tDz5JD<(ulM_+f_s-~(*efdH) zxX^%G2JI3YFD)&AMV5Z}OI2R|cR)Rs2zOB|>U+8QA3mJXcn_FizqN*|KE!;Zm4dH8 zP*9v`j{Au@(&QiF4J24TeEOat3r3s$RGuKjL*cZ^Ms4w3Tm*= ztOtOx(Gd44fFEP>$a2*_w)(9Sd<((XgV|f;f%gAOSV6Z3RgPEvt&0zib1)j$+}XKJ zi8^z^q#me*E0J=ct_nR;0hFMj|3}gw8ReEnmk5O&Bp->u=&xov;y2+gO4Adhlu0Wn zmc5&qJ;#NSEVV^XfnEe#j@4KD11g2%l0D!OMWETzdBaPcfF-0j_HQT?D`aq+U`cZILVdr^KNt#w0vY|>nDqeE5%&VE?= zm|7y9bUhz7c~Djl~m1B`fr0>*1^gRO>>~*vS=57ncg| z2Ryn{Z+R1yoFb(_qv}&0f=d%`y!*98`%BG9Kl3;W=P!3yNZcJ&#c{H}qKbr~9OL*G zJUbb-O4AGpk|YNaZ$7r>LcMH|uk-_UQ_n;xN)R%De)ND3fCrfRm2cu^>;aK1R0lK7 z!x~4+p1Ak2ij8KBD_3W#s6N6gU=D*SZ2hwmB5uEq$tOd4KJP4RWaGd=9kUglM~G1b zguI-S%M{OMb#zz6c49RokeDRY{CHi^_H;bEB;+B#_|!P4hDcG_Z-FfvdHX= zt9j~K*{dPnP)#@gm{ZcXq7#ADAOXS zXbO-xD9VyBa$jGZ2+!;LUJJ8k(U{YVJNC*`O)OV3q?rv0rtAq(a5WXaw?b1`$Tw=y zuV0eFwcPFNoanu=F2?R|>nHsCFb92bq(@mN+F|EB1G zZw947V>|8wy*!L<)VL@Vpz1_cu`eVc8T z6!~4kFl4C&_aQ`Kj=O{yi$OQ7(yn~;3sc+dI)d&e|HKJ_9vM1^V=YNt1%G%FnEw0qm0_4^&10Lp6!}NSU6iQb@^yIGtONogQC>Kp7o3%E3 z+@K{6T@ScDp?B<)IbDK^(wl!Uw8hv$Kl`a_bFK!M^rDO;=*JIF$Gp&jxrGXY%m@XV zQkb2E5#ZOd@Hwq0BJ@0!F|HQx7hy5>DItnF-UaK#Pzc{=f{Fcv@+5n^#W!_iJ%lw} zxdF-G#<4ixOdEb-k_U2&@NndB4%k?Zf1(V)d;5iFQEq+%x`z4%VYnwJ&e7P2Ep$qe z;#4SiHW8W6-Yqo?SPJh&G}4{OqGO8b4+wG=o#c_YU8w! z3P;a@SQGOMQ9$c1XIgd?9>%|bDJVGkzpnNZaAzJG_-18z&5iY>C&BcbPQM>0cO;b# z7*@-uW$1y(ssA9ce=wTF+n3HQx_zP9a6de0kXi|^9)^Zm2wBCg& z4pEZb0Q=Jx_5t5llwY~xVTvTxp7RRuwy3!rCXDP3q_7eo-i8U*Wdkzwxj61!7FLdj zf$P@GPc5)INe9clu8V3TU+HT^Ze{z`1Sx-7MQ@bjNWvL4o?LmFlCytmh?A5cCxBKN zatO8ueJ1`0)h83~o#DVo_oC-iQi+UDgI@*9Vb-3K=9Zuo@B+nR+tE>EcU+gNIW^n4 zk}pw9Nu}oQjB1P3>k)9U%(4rmc=SX$xzHGd@(*Ibty`g$8*}c4<;BUxTvZUSzdH?S zc}6XaBwjfZ8Ku&ja~VUZE-54<{Q-Sgv+hs}dx6W?t=Gm5DMnN%E43n*w;ss0zs|`h z9}9m+5PV>D(ZMLlL9Y?QZ@s0Ox7#bYy)lX4bE)*Oju!(#5F&<(6}CuGJj&Wd9Ehi! zw+uCk21lOS(Q_~%!eZ;9(V10o#S5MDH#7muhvKk;nStKT-)-lPTcqyfOB?~%^J zQmEFCe>{XPt9m<;{23sRwcNNg+8Awn-IbZKo5V||{~($99_*hP3i~r@iGe^ga|j?> z3n5(3YZn#;EUH%-IQjKcbNrzKK(jk**Rm=_Wx zWB1Yr*1ugdo5pyFs+amM-2lwVHT{XhdHGoz)+8`CqDAlv9!VfiNQNbaQHBfi%Xshu z8-+v&uZopPE)f=5*4q2f131Tu&(Q+r7OSu=#}GXIRPdq8i5mh9fv4H z4*sg&214B<%jdAaBOT7YZY&g?pIpu`4>*OPUplXKJ504h1;mtLnWUwk+DU4Ct-W36 zC99J(E6hkp5cWwQ&n}Lz%ae;%+Z7GjX9gzHJpu&-XM9nbfD^PJ&!*@YXwkahYxk#P za0aYl)1DBm0oz13vj9R@!H}dhmswmE()!sP?NGM0MlHZ(je@R3Slrv?=t}t@F-pjn z7O*SPGIX0z2MYh*Brc1>II6@K_vsjPP2ah|5?@kXmr!y^W5WtwaM{Ps+<;6dNBlLe z*;f+TLXyGJraaqsnrVn!+fo4bD{@SoIN5>Hzb;irXpH#msRd|yA`SSA@_Q(MK8@En z;LkDh%KbzdG$*B#0dV{@`W^=Mg!{Lq4?J&emy-e*T55MjMaE4Ua+lB@~ zYKif#Yxfu+LLoa8a<2G24IA8!$Qu2Gvju4yVH(n`P*_eOyp$do7LEb?4kQw=i{Lk{ z?LT0{5Mr*GlUd>M&&+5xdnTWwLrIb637Z8y-g#z2;w|b2stqB^Pce>RAVPDW<-0TEz6JL-;2Hr~Up(W$Y}fPAb$xm} zz+k3Xs0rC)1OC7kISGGN2)aCtK(Th-O+#pZ*=9(Ma8oRen`7)cKoKHZUM9J`^rC<9 zlyn@L7@*)t#XMMmR{**W{(1jAZ3=4nDqiV`#ou`CK`|SA2<6osV$}t*mhTsSpbY<+ zjI;n74{TQjv@K*v1I7@31J+V`w&r8`3wr|W9M4&h$oFT{p|f#z zAe`OQSDt%wSKk$aRUXnFD;I3SuET=0cz0Jo3YesyNz>F*ODuz)Ro|Go=(NwboQSpJ z6bzF#QPPeGSyu}2--(}~%!RwN)5a8J3wq23f^7v-vz3){Z~|SCrS#<`nH7*>LI#i^ z1=l8^4~{`cU*O6b8VA2BRrk#p5M~CYu`7-V;c74**~gP0$uYW|bI6^DC6A|7U(IQ( z0Z)AJ@6U4h`KNYS{b=2? zPq0v1M6XjwV?w=-R66_!f5P&qpht(w^tp!qdKyGiBD%J-8)eBjmtjbN=jw(NH%x*` zifI|P4wf(=Xq`cSJsXyM9t`<$Dz~mjdmJE*ueeKl3WqX0)Qc0HJOa&189*|k0~)2* zRJnplJWzss@)PmV$cG7IXTXicPX+CU2Y}bKjvo0scP$MKLL%o+HSlnGl}yh`1sZMw zToLy5Yo>uoB}@346}iop8|`h=rpY(V)>D1nt-QnDScyk1d`VP*)DbxhX?)jBv9I~J z1zvsvpwmh&y(wbOyFfrWNI6zBV3#12?~Qr+-0%6}k_#`=?`JQ%B?9W4qZ?Umi{ zkUCn8U$5wHp}x|FTKI6Y0!~Lo)G?panRPlFYAD9Kl1?7`#OPs^VK_W4Ls=j}+{i1B z7(E0nn@AC&b6>D@bq4kl9)MSOvJ)8-;~d0Nm>r9@eO}qvf4Q?qJ&~qE0p2n3`pA!E z%xJIpQd2$F>0Qj8+X6i@()j%ap&`XgOgcb1N}J?knU%ClV@B06S*l<`uq1NU>ph%) z4SPZIvr*}br~RVb6fag6I=iF3t?7k4<6c!M0U(j z&|ZB<`QLe5vW_IwPjTC`6!6r~97>=+h{ScByDZ`n(-6xg#o0>E9$=XtU9eLVy2fA& zn(;dUGX*PT5aw2g-R*XWra|;~ExH9m$zK)g+ah)%6}o`mpmOxaFz1*FHOVOHUR(?qdbDxRh)$|kc@F*Ujr z3rtPCn>nno7hp9+$k?u=n(B0w_vjBYtAH!o7LGm>IwtQNET>RBl z5Pl@eHhbg9P5PnLvN|x=qJ&GE1kAi+Rx$iWWiBg9B~FU&3m`JX?5bp(F+Q2g#;!La zR2ty9lDvH!IAC*%i;g8LT*R#D1T*Z?&Kwwu)pj8vqJ~vW?8}V($LQ#d>d$iMA`Fb~ zOXx^*>CZS58 z(Out-nll{RjtZC9ALg~47D6y+@W-xC-5d_*4qdr-sKD*8Li#saGh1Jl(SSI ze^k-70hb`u;$n+WDd-ztkt%0w+#M|YYcX4;>WNF$#~^5-sw&{_J!QVus^s230U>L*pQ6On}!0gWbKwDaN}&0N!!y0(7`p z5n$i6Cxvubzr{=}(JYs@tc*rxecGkETDg@G062HEXDpSkdg^@nq{uBDph$?LedR*2 zq4<(>U=4&0o}5?*#SomWc}K6upaz!N(%tGRBC5|-4@M;N@r<|p{x*l{b{MhP4e-0& zrv1wKUtXyZ4MquKq~VTnW@w2f*C|qGL57$~D1=F(lhYz(JA)kkjIre#F5(j`T(s0d z09W$zk#i$n`o(cwMLBiDKhMn75H&gFwm#5zX4eKKc-^^82 zzjB>bT>DOV9mgWVN#Vq!fZid_I@6B=7hzUObE4T$#K8?Y#rTJz3)P|``K4Lnb2#_J zl1m_PHTJ_KVI=;^{0>NK230L2v8BwV0KDw&3BraOdn*Jf2Ha6)-Z{@7y4rcuN+$cs zNn}G^av?xOy=UbNFOquHGm4nh1;>`A#Da_pnUNL$zPp2u`#9zER!Q7KC;rnn+%}_C zjr$v~-QPZTBOVfIFVM^VW=;CfMyo2YGo`vmBO7#qybM9Qc7?3yP&Wd>YaITcLckQN zOMoh@XfgWOx%RH1CuvI6%NtF#{JCj1e=F(;>U^?ZO0wbjUr|+$hZcPwv42c{m46@* zib44+35_C>%pW9`P%b)w$DN+HFhH^owosix&(Wu-;=eR*A4LbYPFu0$ElK_ex$#oL z>2@Zb>}&v4-+is|(kAUwnlX#s$HF}SYW|Jr;!jRPvH=x;kLiHlbcy}B^FJ#)74 z3T>UXyJkRF_aWP4|9tkfU%M;nOdYi9hFoK9X}2H65(0_do0YpHoxts#RQ|LCsjCkt z0cKW*vXCygRwLbl{4BMlsnPC?QPn6TQ>^(I%S76ao&O#OqZ1AM(@{z=_3~vwxg_yQ0aF`F`#qlE)MqzG1_CxpT?LC;fV`qoAN}=%g#mQd`K@C zOD`Iae_Xr^RLu2-K~P})Ma07<^M#`A(x~)|^mq<3_-VGZn7_amTWVFWP+jvL{9oaf zqft+ooEj4~pg{}|T3LEQ9I%>_SM*9Y-ZBfn$H2Q~jT8*W7fT|vcX6PW%6&PyrK(+F zaYS1cw7r@0865*!7kHgJ&>jW?wAWt+R<%v1vc+w!x` zBNwpG$!VQdh|RI%lmC-4I0ywBK&-4P9{)tcc z+=Us9Po}_G-r_@3%F+4l0^?+u$_n0%#tbPX3>DtHHAgmvdE~KaI1jk#Dq)yxENd;UnBUCR&zzBi zxG3a%4}D8>IC=T=Z6yY7a?oDmlT3~C1XnsFaSj2*5A27312FPY~Y!71Jx$|{aKm1S(dZd{`O1a!Su1i*@_ZwG(T)6ccG`cY=n#4nCoEL0`z+4 zaNBy6hT%Z+V|_ItU6Tqo!2r)a1ZDf<3C;)oY>pobC*gn=6kRI`u{HWRoySe>L=%?WiIfq)w zeyC?I`v^Z|fxK<@b>*;eP?87&5?0SlXy4Fv47!EE%PID#^siK&(v_&9Hy*dCCEi_% zq6W1rIVw##ijQC%342m+a6B}P%Lf}eUJFdON^^@ED8N+j57SuMo!#b97p!)H)$RWP zS3s!0(AIY2C^*aKCyeHGot3J}VhX&MQBjC`w!#o0*@}>q+qOD7%)0m+3gf4?fuTFD zV=-(d&9p@QNr+hF9vVA~Czgb82$M7;VF(*Zk0(V*!4y$($21S}1x4Tu?W|tjcRDkH zsuGqXUCaPPbZXmw2R~r%xt1G zi;1SK?u?1vDQo5#XSR{@&++#*ZToqMonnh3UW&7`(?3grKxi&$fUG_YX5*1gt(`E) ztF`r9WAp?P8NYf2qBwZUJ zb=6CXovI@-#2MlQnWsGJoUnUw%2;&pTBOp${Z}o)>=qlSt|;YwHfRagyu`AJ{WIt* zxOG47n(%&3s*2+TDG@}r^CQYvfjvLMLuMp@ac}}e945V9Ic1MNCvN#Aend+I>sMa5 zddb#Ajo1^5oiX;y*yX#r)V8jom0TQbh!qQ+lJrry#PafUiZjN>vQcHB1Im)n2AoCC zDHpRzdkd~55=3W!Lgt(oO53WXKp9KBp`!$~!R?8N%_=9B91F;4FI!8W# z$8q2W&~H+HCy*^a8r5Gh98ribD5UnrECkW-suhb?!_}UanAlly9`ekX#*c-~lfl+T z@Yv`X_NVv%;KQH@fHxgSw;*L4=!`))YaQ8j*%cUChqw|nFqxLU5%!Wrlu(P_V!QNl zM9CQ-$q$boDUl1IshaZU_@xgDBsn90;=)-HpwG;OsBwWHF&pND>qmfFCO|D%Ci-cw znvWn_ca;5+qT(s#)m|h>aW%6V6Rg~_j#rJA|#Q&HaG;+iH zr@Ias#D?_LBLs+-)wx{2D`h(-eP}A4zD|Ia{Y!2*=s~K9L6VF9qacNTTHNrX-w!jq za*ISozJr7`TlG6jPFhqX4w6^!VkvcVK`)wn7`$n=GT!Dn3Dzx&akaYq{`VweQMg(w&zj(=#LwKrZLyLN&V)HAc~hZ&NieIJzO+6}`mE!Xw|15l@F zd0JB8Sm$7WJ`yq={90qssl$ar3mj8MrSe^9Jq4roy(`A>T?||JG-GAx0_6{0}PwyNgEZ3)|c-DK%|HXNwLO zXdYA&n(u*3qkbe{By>H1Y!lSY=9x>0*yU#CfR=FvbT4EL8QNAfo$`7P!qIzRA5H1&qL#u z+@N%SYw#$-(?~LLpr=?<7k5J5RNYW=i!Qv&tzi8!9f;99hH$6kY_3_j152&FDg|JK zlV5DqkH2kQ#b0X8LY7E%Fl#21GS6Vqax8-*Zj;XA;lzAe$-z7bpb$T@p=yW=j)(6ca*AeO&4NQ_zh+Eo*^rmT#Uv ze03m*x$NBz4>Ow~iRT1>Lj2C6m|iJTOQ3}N>J=#;2Lf#);ZL@CI=eNr-WEk%2Mobg zd5Uil)4os&)MR_{3e|mc9*)^^u3;4ckC##}pk9lA zvx>szmzSUW&FsQ}xK1SzUvejDd7!HWY+cxzJk3Rd!ZPX(FWGYm;ljd_9e)YT1g2h*gqo!vghrE&d6YlWLmz=#ncs~8~Ph2@C`EX zCBH^0KP&t;07U)vzyIGsrgexKp%!a@h%-y1)IWUj#0RVVI8E{jYl3D%A(pMLi|N3E zOLA(}hO3M_DGV7Y$eh5z5C)0T&NeP_i+0Wg6^*8OgXuS;1R*N8`@#SWNw?xHdcs}V zDiR_sfE{VXU~r7**g7l3InQ+da2ELws*<$SA;dE_K~Rm@u#&7VGfGQwqa${IIT$+s zI;^;otg*Fa+tg#*_V$UKwn*%`+Xf$g8+2^UvKXt2L3AZHRBX0zVm|!BT{$pXpZNUJU@h{0bd%9)D$K(q@} z^$~T)p@puH4H=VC6Go3D>ZGWDs!Zp)clt*gVAR(dvkAova8?nyAR?s`@(d&;l%J5S zupb}?RFvuKS9LNh9o&k~ymOQ<{7)7H_3thB@o(;vQUn;f&{Yc#62+|ai=J7@k`wx0 zdv%ixQnG}daeu+Lq|^fJfA8`>g0ysAp^4Ab)8qu@oq{bRhJFNyVvSvYQ9OXjNGUtS zfq0AmY;dcCGK5$bI72MgGMr@&6Ao5}{5W`7{lf# z7yabw8-+-}Ef<-t2~16rk_1pQE<+R?9J$%KP_nJk7dko?8wy_swgo<~OLQ=b2{?<~ zGj1-%ai1Q!5|J)Ask*9vk-QYYAT7XET~h3Z;mV74c)<@;e?I8UgV%7LDr28Dmn-b3 z{igYrSIm?~C}8L6G%t`U4}XoRU?pHW(3Br=n1TRKP^K*TP6Yyof|Up)O>E~pMLFfhjlp!(Ut%UVCKsjX7?z`9uQqP1 z-+uWuD~4p$qbaSS!)TdyDAF884gyg1IQf&&h4C*E=I)$-CLY956>DAfkfI4^C`;IN z9w7&^;W6q|@BAc48y4aF;B=QZPM#EZOkw7_UOM+<;cP>{At z-R5Lci;VueA3C;$m+%F&^^br#=e@NjTkB{+wF!De-T+FvJn7M9fGo3xit|eSo%`eL zLfau;YAHK^IMc#?VjX+N0guzQ&h@TYg9TwBomgKC?FM8cql7^KMZk6r+M=#iaB}v` zieHgrzAWwO+#v54sn=rIcPqNiuxa5=qJtl85k?T1dwVhWrRvEJSvqcTk&XQuOC6Sh zIWvxq3t0o2uXkUQwulek?7rtpP>^x}BoNakHz%J4j26%3EuR6}zeH z3l6xxts`9(YM|knr6G-z2>|dLcXQ|H$X0PCRf4Ly@BFkA944@ZJ#GR8-DRJL)$Vrt z>SzJXCC182fu2A2RJctiRoW?d+z#<5e@UU$yL}b?*Hv%izjnj_?0-jjZFDz$+l{u? zw+uahf65C^{4)G~?I_=urHp^;s*U(3I>YkQtAqCIo%YUO+8e(5o<;T`475V_irZ0; z7?8cEOGZIy+#sfd!0q_p2u>Ys!WM7&ejsFkKcgI-#qEGao-#q0F_#Gpix&L7R@T_E zVtO=W15~f87!xny1L~dHB)Hf!Dz^~V>EJAXcNQfrizIHev%mZPxUw*0&%)ZdR=>*u zlz9nP{jYz6(xkJmsBnaR84Ues;ScKZ8^Ulv1&_bgn(yElssbVFzB^C}&5|=Ij}NmLa?^I%+4&L_QX&U)%_M z6^#)L3}2JGEajFL^3mqXqS@&C_()EY84_k!aO zG%PBX!Sf=p0U8}@)Y!*yXbA$cGwig~ajzVQ1v#)={`F{op&ZhT zgMvbk_OR?TR0*ER8n~(bjqjN?$I_x3VrEJ&_6W!b7mm#8uLdhi@^M(IC#;i1Jl-AI zV7Jj`Gg6G`Xd#)Tueo*-w?PGzR==PEO7e&=)zdU#dB`ce^q`%w{Kx_+mn2#{THsni zM++!fpi9^VsVdOlk8;oDIU%iox%5=va(depv;=JvyXTqN?>a;?jYY!>@R^#_@yjkMua!etprMs6L8YgEt`rq=v8`th z_g_g6aoHvt#RYxW5nx2Np3!|_k}5Tb0fpok!A+&GMkcu~riQGWd7sXrU2~vu=xksG zO2HYNxouuK%NbouJg=a>7nz1E_q0QIXuU6KUS|&rfG68p_l(4#kmLX)Tb|w`vr?<& zsz>s}QmEgPYMPY5r6nAHY8*)MdXT3pq?I4UZr)GN(!LF8l4p7e0*eDk#L(I$VZ8*N zbg9gOi!*|PCFMLo%U;}EmH7h}gaFqpIh+j-3ha2S`;Z7SHWhI+NR*})M?RC_=XM^+ zh8tV1>Ch5Hy1gf>1YnWS9d3tns=<|{*^HLX!hXD?!;A?2#jB%#Gv|W9Yp<`6zTTtL zLQyrBX`x@%G|;avQ$gpc0Fc1j9NHY(Shyg&@F$o3&RYjn5GvGW2|n=x znCXf00@TlqjIvhrq|11#+?_9_#7kU8_VBVu`mmH5AhLRY@O_D8q|j)lLv8GeD#~?4 zR*Zf80ZtYh;sp#S&DGj(zx>C#Ize4Ba8cCyCYriQ#k#rjyxw*94I1hUKTB?kFCV`R0mrUw!nl|j|?m2ThZL+t! z-`z^Dt=6sSbekJ+>Zo4E|Iginq^~lIB55VtqNF4# zxwA+w5fK3fkwgHI0D=@f)bg)h-G6WS74D1aN$%R;a0URuL82sA)mq&tGcX*S@f-HH z_g>39&;W9Atd6Gcd9H)X8Rl$fI`!SJze&j&N9bs)qYArwtES2d6wRF^D7=GXjC?LB zSGY-kM{65%t##Uq#}aGhx|^D5-8nI@9{#h*`#Yy+6Z#=k!c8Ygv>q7f{H4==Fk@*@ywU3uCCq#&^?-e z(XK)APH+c{_FdKKOy}jB)rV15SJ61h?>DXzv2MN+s{;biR+hT?u|l@k{ju`nHrS(y z)s&~NeVO;^A8Rr`=O(PQnzE9oLpRv2Ay$F=2VdFR4}SUPFguX}tDNezH_ns0l|4LP zlPy|MqRK@N&Z>SJ9&m6cNJZkL40yj-YM{5#oD2}xNo=gN*E~eCEaN0-a$g<9RE%4M0&=&D_ z=D$^B$ryX!kCB>J8ZHrzNivl=Q66HGs2JwmufL%fohn7t$D}k0!`t?rtqq7=(Bp5p5}sM6jkf( zz1LP7Ofey`VHtvqoP0sPRV_w$`&AqY5c|^sL0eu&3sqSJUWS&9pn#gtyL?qovS#=k zl&8{gQiOq^J^-z8WWg#H)RhT2ThJe|xYekUjLorGI=U*nt}Y&+KLp=pR_Kas*& zX3CM0FcRoYh9K8h=gV2yRIVVD++~3dqqRR5J*2mYq6DxZ+PMf?VJ28)2uWa5;8hEQ zW8y!r`1!O%>D!8P!Ft($!!gb(I$q_^cmO;0sjCjAkEH$l60}p#jDZTC4`R}BkdNNj zecC#*F%M)KFqc-tX~fUKU0_(f(^Do+5)~BJjZz8@Ya^_Tr=27cDz*+IjbYoE($9=O zqtl1T^Q&!yDJEdX1B&=#3l++N>VYHAdJtdB+l8bBniF)EVE z-z~CajS@c?4gB$8->lPBrY_dZUUO+;3d0THg4ns!glJ=IOZMV3NtYwwco`~0j)ISQ zVtP?Y!0*6JFfV#S-x$yPLc5YWfA6`-zl301TvP{qa6x4H&=Pcz#+MTkZ|yOrijktv_8y7gtKX$eijH$YmY0((V%iy$@l`=12Cnb@|$VBe1OkQDK^%0&VtDC}gUOu+9 zD+udkur=uYvV1%5GmG;!VH35lUa~kDmZ0ikAF)?|J;sXnB>wnM_cstNz$uBuUe7cT zMzY_3-`aDj^+$HSbsgV>HM7oqyBHYerkkW=;18w0Y6A{!#!k^Up)~jk76LsPJ>1+InVx27r zzdmhJoY`l|d0iL$ulsbTkdk&>F6a$h|2;rjulAOFpqEEURQXy2mrq*s28}LYonU-_ zz%ZT1Wn<^_D+e&MY|yo%gDHpMUwla{CDfngj)D>znSxw~cF8mBoW>P<-@RJytkh`pyj}C_D*#JhUjwk@AD=t2-MH#N1h)`m!vFHg4yG$ku~cxeDHv67 zL>*fucMwb@RjPGAPld*0^W& zsd~4A>EXBt=DK`ST2nE@3=mEI$$R+c{-)3EVelNc{Yu8ER%iIf&GIrPpv4K((c-}Z zx_a?FYg0P=aE=$iF!F!?%iQhH`{=v&+lY*PHWHmLzLXuQyH2=ir`WZy*7%m+Y8sp8Z1=_uxSAEko>*Z9f@EGVEHL< z)%O&h-fJ2i_w^TzhF#AJ5lX=wxA7o0s8n4xd%Gt{Wp`ucYq1hJKMAsWA}h35X9ODt zwT@RmqZo=OWXZqY@t;b0w=Rf(H9x*2`2&vHR8vkskI73R=rtP`ijWshGkaFm@t6v; zy+mL&&C=Qt<%Z);L}ivRC%Xt{(IcyB>diQ3micp&-663}MufEY@9R7vrM~ETr@cJz zcjJIucJy+{g)F<}*_C@j#PfE>)Q+9ns`tZVaAxz4(II4 zHS-dAsetjfC1C6&63F)Oc&6sVZJL~2Nb2iYcC$|H+ttl$<9JqLJ@)34aJ~EWw+p=j0sU(U{|r=GJFa>6>u-*$s}&?|c~Vc|0bbH;e$mxj8jxmBTeGXdK|GIL z!7Iu_A5u-0XiPOEro7sJEWtzU%}J$SQm9p&K8c5?FOxDYM&`k){Cz(uC+2YB<-LCd zfwvS@ij>D;?@EZuMTQ-FDs>H9vIncQze@g8+Fdz`EwPF5D6Z*{!SnmSZ-lQz(+#e+ z3$AE`F{Bv;&TV%kqrcY|bj{bnU-yVJcFlZo@9W;`>gr*>p69cFIMZ20cYN`%_Xt0E z!N;#x|6op%SqW+5;aUd|SFmOTbHY+5|ABi8@lCB767`?f9|*F~++Y2}WfcfLGfv41 zhO>U0C2v#lt2Ntz_W^Dzg;VoA*I>qr>v;*KL30}a$;jjr$bv7gQ#FwdPi7av`vlCe zVc81Upj8qBg`+ut!U9Z8;Cz}(-Cm%`pkvBJLM?828M!7%6c7YrdR!I=hbRLAmJF`( z%Nvc$Il}R7(+Vz;aVbOtZGpr9dZkm|o;Try`CMG=OcsuVLe8JA3dFhRLr^l#0eITc zy|{blvAWpeJ0xMCrZF`h zm%jZl->cF1@x>acW^@vPUq`dsGT@IdM&7Uh3)6d7MyZ$ZIW5^Q_2bljPE` zz>oiN|Ir`JAVClY(-JRx28GD3EjygM1b7%!ML96lG(828c=rxH5BxC5=&+($??C(h z`OBsiGuc49L~DGVQPuVeimG<|he-5A5vk-HE>P)zw@-7CP7-3`MUfHq(*0r+)ky9N zfDdOG6FD9(Y{qGJ;UfgcV-N?>VBP)caDnI+aF84>to>w5jSd%HmdSqnmVf9SE*#Ht zmNLU{d$Y;m!Y{wv^6<|N7JT|{3ewYTj2lkRdiIK9cI%4NGsj!aXFWaT7xds7l*3S9dS zSm8~*^hi9+QZAir^KvY?)h32}Uu?QE1Mk0lWt~Oe@I-B~!b_ zRc4XVwtuF@cTB5eiPCTafJn}mqm1V8gH_OfLKpd{x{CyDisX-``O*=@(pyS(#lYpn6&4)PD2|fAWg$K^nJe1>Guew>tT2JWV4hJ9~V8_5P!1^~-405A_d< z(FL|RDLRu6w_Ko76=@45{r=@TN$)Oy6b|woKY1l_Ev(Bgts6H;i*jMj+*`Fj`FVAs zy2J0saR$58m|xt6*l@W}QxmR(cfbC&y!^Lxd;(&v<>j4Zl+GsjcTt+<IG1@8vO_u?KXcAa|8(~@$SzuA% zHL>HG4=&^wnvLJ_H*wIB?CjS&tZ6{j1Uyo4H7+HFqH@8@Xf7R8lOPE9?zbLBFZZ~B z^1@#IsQqgC)YjEK<4hy9mk7ZCu1a>SVS#c7S+50q4a_Hx*jt=V>gs3ftWc&Fr|soi zh-%ZaJDXIk0QNlN@@tQOmYsKcVfD$#zV>Ps$-+7y(xh7w$q{)|(#)8EG+R<$a6BEM zl%<8y$?tQX_00`Q;^)%Q&9OCAiIw|?!VaIAtLqB7=vM5tJN#-1wt~yPgad17xV#_k zBmNo^XUQ-39wKTRGVJm%-?IJEpzbxnk4o+(EYHKZN;nq^WVA(pB7PYX#>kQ-FC7Q) z{nbc+=PBg{C|c*9%O{46Q9drouhga3gzoqaJ}$>TMZsBq&{~saHp!;uPpUsFaoFe3 z8449?B^tZDyj@i@-d8B{DWziMuli9?Sv;&6igHzoc=6ci&0!3I?!9`FF2>9Gh#4AWcNZ@j;eTaEp?$V(+RJ`B!~JaWOg^m!XfQz4S*0;ph(nG<75n+v&6Xq zpJT+LK;!H+GBFWKaiGf7EpS%M}0z?=Qu;6WE1t+RBN_Z+~$roi-~HXUM{ zR}!ZotBfe>z@07MmyFbF`#adWX$3wcKAmW|J^6RfQ0M<4vj#Jm(YxrCq zD{l!peIuFb%VXi3#Hp~Y34WYFFhp%ISH^|!Vjc%lZ1XyZLFy_F)K(9&7M;`iX(zZ_ zaWbCyQH200g||HpzQ_ig{c@5r86&JKtf=wmpO^{3rwdPFcHzcU<~R>6p3FxEk@=x# zM`fI5-`JC_!Kg@aGJo${jHer>;3$q%R{#T6w*1TF!U4v{Ikyi8{jiG`YVeQ0GCx7KO-cc#NMH^@PVv$RTa z@{7ojg3RI}$ITX#9LxojP~r~_NoXx~rH5CdsXBsJ#fbo0+<$C6Et;Ot{qs>y7T@Hr z**3ZfUu|P*W@A>>1xf(z*PF$ijSv0$DHAs72hX8iXkHz%FmTJ2_Q47x@&cqV|A6$& zN)ZnjMQj!qP0n%+6b?*h!ih#Q9y{k)~ zF97qg_A1!K8+b_;{`K$6is31Ylt$jSx+M3??sX&PXG^YaD=|~gVEPr$x28zs!Q37a6lG7xG^)yPW zQ!0*;K!+vju`L-~$o7m*>v{naJn(K9;lUG-($J@N)-a1xncPKXoZBM&H9JXAMUhsM zzRR}COIpYg3NwLdAMfCO=V-lkMvUH`JE>T#Lu z{r#DscCfV(6CNhXfvr!}alL-iks2A7N%gO6MV~Ajdn=+tiO%E4TR7*E0@*4y)&-oP zi_c~7E<-7_Cc@PyAs^i5xK8w6mvtM(#u;ZulYflz4jLSj{u9$gGfUU$LnND4;%T~K zyXb6Uy`GB1W#^9R&c#O<&dJ3kBk2ZGMruj44QzxEn^IhP{r2wH-~177jitX|>cMRH z53j#N>u-?7BP!U_zHamrI)>-gQrjZE0+Ibx}*A6cJ0}Y z(tjI?iqt7oz@9SU1*ZD6Km_TDI{O=9TQAMo5a;$NU4iZEARJzfYp@SOY3c+6Q_`<-SjIh1cioLzh z(2jZ8+6c!6w{bV2^1jzQLeugI8d%aRZ7v_ z9_;-t(6`)_kCB#hPwv1VeLN%py_0d|6@Ox`2+ihoo#Y&~gCXZ-e$h^wRLOBIG` zlwsW1!fZ^Rl>tB3p}G9&`tNgyyQ)vl+$D>-L(a1LsCt(4-dmJ8q33<>c+O$I@INe( zchCOwC;KmB2)nwlW)>{{V6`$ThSf?I59t4kRv$$YAx`sgG`1oC{$#Y^o@vYiD1QuY z=SkqLO!68Jy8|UwkI9SkAMRc;p6D6UQhMO+fsH%g(A!qV1p*kVW_3@>&j zozIlVw#xp%Dm_V_WOx#%H?SYhlPrrMc$(tFlhKMd;t?|7S%%rUqOXZ0$bUz#Sz=5J zeb_-GgU7>nBNO=YWy`;g>xk!tu8xS{8HjD>s3Yd6!1ss(3}-I1#v!sHN*VFrr+G1u z$v!Iu{Rd=Eby8%E@xoN(zmMWNroSX_F{kQxzy3z)*fJ51=`8Vva;Ch!P9dXFxr^_D}UHphZA;b9G_-@%`b#mED0hbk4aDTMumgWHWmJ|Oo)%A zN`;~r%}miWs$P4Sll0x*2jp5r1F1!gw=E-qupX zfT9*yM0>D^%vXQnEBO&@A5~^?{l`8IF?WXb%=(XgX&p1~FsBudhlw);QAK{#Y8TP| z2YPSG5K#`E^KIIGb5GcK;!#B0I3cGrc6KR;Et6?cVZ~gSMa3Eq`$V+g)@G8xk)sos z*);&S=C|9_>>fYv-WsQ(38Bv42OtI`x)AdVP}+V74*s)%k-X;-*vpO$J@pbqsh?Nx zpvt4+q%t?3XC)l-+0>kmQb(Du#iH33GIf|s@{_yu9>GKjs5PEqv$w) zuPBphTI7`!N4xExEAhCd8bM5d(CN6bfx9(x@crjBTIPUaoy1>z@6yfjX~D(UK#$L+ z*q>;Z(OYDrt7v&$X0^%?5!cgzQlZ{BS!-BRC_5t3S!v`N6`EzLj8ksY^-LJv4QmW{ z?4LCDvmzS1PzXS5^(}E&;$v}o;gnjCq;38T2c0_ zpsYIIAk4@9;1c$^s4CPPkOyaR2qUse2T5fP_#?anfL*bhTIGV~_MB0DMp&vxiv+p~ z@K10e6z%LYTEIFD0$N3;aj{CUmd)XUz*HA3-Ci*@gSh1P-0z!j(@dZ+ZDl`KP3?J; zC}3bW)SJbE-lri^q_-^gT!xf?m&pT5lc1B)XB?Fd(ZVWagIZp8P|Cft2j*L+zm1Re zK+5`X;y%RIJt*Fq9OtLgZhz=AF$g^bdVhJD_g|iJR(W?C=Sc>qU3k8oaD+1=0jl>V zA_0~xkiN(*vjg@xh-1*DMB`;3cDKAtGq*tXAMT*^&=G_D#WRzYe-u1_Xzv7ejC+FI zGMr5HIw)%ZrZ`Me93qRfFzmYMnWP@}Y4iS4AmQyAerkW0T?}WQZm*+IbQ(CjkNnRnKqrHhFu~YWkS&?f|G0A3%oUJ}G;?Kb&sHUIiB_8)O z9w+7ItiCWncEb883$F7si(cxJ`ZX!-BOmc2ZTIVl5F|2<-D8so>>z)tFSCVeYA|9{ zw%1y{(Wp9mtL$7~u1<$F1AaI$Zg-*OW!hi91{U9v`SGE}GoANXsAQkXeo0%lR~1e> zVlO~Fb(#rK0BZmw!-Le;wc4qcC1*+IiJVc=I~|_@L|-6W0yEwH(fOzDZ}80Q@g`Vj z;f!5BMn67!_v?S&TLnGc=Zv_2h$&khG@Syzk>(DGZvJA{=|^nbWZ(D}2%qJ^;@aIv z9_W22_A3dMlC6R&dPYSkWC2_}aCN<#ljQ6$1@}Zx=nj(^?Hm<9o~@>!=86LU%;I6= ztITU4(PMcslS=I$RO-}82>~PD5*f-ml{e-L2-;=%V8Wip8 z^o%3bhm5D>_nnvwBSDPj^wpE=?J*S9-ll%Y03j(Qj++P}m-cDQmLWcqFzy+Dm?pU& zC3SXx7?iAB08%Y(RbY}=&?mW(>!RoT0&6!O)?4IAnaAee77rKngpY8l|C{sz<}6b@ z$eADhuymMz;rH}5G#L&T-pc<)9si&HAM<7Q4-Z?@w!8eZ`5wM#BlwWUckv}W)CPm8 z#DM7}d5XA# ztqzbdDF+DEHS2{oQ_X)da$NX?ccP1_TM8ZT>Ok^#>TUKex8nAjHbl=@MEUbr!wD@Q$Z)SM>tw{V8gpE@ST(Hb^MRJ35f^bg2YGN)GM z^S(cc>+NG)%@v}e6X14#QlK6|_9JaX%o38%r|DEjOdR5}m`wFk{ys|+^tp}ABP2(8 zB&sUxw)VF3CLBRgqQRW-rb_CUXGf^4EcpVC(@TQDEf}#LAhnAL5 zJIue2)7spBC}hf^GfSon^1@?xnIo-v%TYt|6WYebFVmEN!B)ag5;9K2nWsn-S7OXJ9Rmd8gmK;72-l4E$ zpPZB~^U3NV$lfkP!-hN6YOz&xzuPKuQyPn%C;e^MM=*nbTsLs!4|WhK0=V+j1!L}T z5TPi|_U2*!g?xsXC{VZ}3g6H!3Rb+B5j%~ywO)Ty^Qh63%MB&&MPGiwW07^8%!dT| z7%XzeF^6Uh+FMC1o=pL-fy&#khx*Vm4Cw)vA@r}-1nE}Ub?1)5ZW5B;ao5s`8|qlf zDQu22EFd|5iIb}BJaK>bd>JvOr}0x|EgP?K)U6?ZBsl|c9e0^_*r@02ePZjmU4@`5 zup2;M=Qzl5p4-(q1z~*0R!%W3^7siuguMpg1-TrrV?7}}4&l#xtE+!%o-^JiFp0S; zzY&VU-4uD1Z=%BpmL#Y&gMgA()s4tdRTrqTBpE_~B3foE8_#R+Y6@6kJuP{a#mvxI zguNkXFw8SF#VjJTsb(9RfvhnV5Y9`^KD72lfad7V&URhta32;=ILl|14IELxSI{3e zfh4xb+)x%7UG#~>Fq^n)bA~**P?vYmcNrWT?T@1DuK;Bc7(Qf zCy)@6!15RZZ@H7&@;!f_Kg%s?F&B^Dg4y9~9_mRv3SF4tjT<$JaTx>m-l!`i7I~TIT)xES&dT7)>*F{n@{J^Lk%D(S7WV zY}?zP@(quH6M}5W+uT;eZwO6#)~n*xVW-RAit~<>mx{=V`HxRO+yVhAm(jC(HJ``i zmW*N{%&IP`I+-w3lq@wpysb72M~?pE9;?Ij4Sx+5Vy}N`P2a7|&ND%{s~rN2B+0H& zCJTT+>ax5Ro5U&ZbQlkw)fFVv{ElxKFU~&k0*IUt6Kzqotm_#WO)f#~t+P4FT_%9+ z+6g!+*4h$$w2?&oHiKR*a3L63f;LKo zlW`rZ=<$Da2rWbH{&{w`s~x(s?xksUvk1afcM-6msa%LK?KCL?bZ}Vf7Oa}nrVNUV zU6`}YfJLk=p<9AeqdqE zkQ~9`0(u5fU=|@DT>ud(z^}t%1f>+HzIlI?MtkVZ72(rQM$lBTcM$N2Z`sa|3)ogv z&WitGO@hM(Z!_j=q&4_W=I@S7-*w#~y!Lr5#2qR9){=avW`lce+1z`V3O_VnzH&CX zryn4nV9XCBjc}O%5(X8k)0q{YJ#zc7RR0CMsCAWO$B4M&9p2BxS<9l(eXFx|G_QX{ zj+my^R+cteKryBafe*-5xejMeED9G4KcB=US$&Wh(^?LS5lom38`^KS>9orPO{&TQV!g?Z3_DpcWdf}(mqwU}m9uY*~8ScD<8K)TtGHh!n z5HoCiA=K54S?R)ZFtTz+pGi?bhJ*&y!$M$Sc*-pDcpNeN(TOab(-Vjl=Q`m#lxcNp zkFjkv;H1uKmX0U~{4)~abz*)tJ4s9@^UqoX`SW4^bHx9r|Lgq=zcxPc{|RCylKEM+ z=-Q^#&#?X)Bi*zV$-0_gXG+ZOi*3{K!gv4o|1@9u0&Eme+Vm#p&*r(p#3hv9^{~IR z9u-!d=@k3fY)Q278wEXbe~V_)kjbta2y_+jZ6Csa~!VT#=a zS;aP`C_12k#GZFqLbn=h9d9-6{YqUzWenz!mf5uOgAfDmwbPngytmD z*o#L@!D^O@zhM+Lv|f=Lu*Ksv=#4;+SMwV|rPj8nEY$4O$%cP&$u<`z1lCMC`o&Wg5iif{;uJ9#wv^>-Xi+*xUkh{A zr8d&9HN0}oP%r;gp0Fw6SmH*7-9`|cuwC|$l&b%8>{PM}>46gGryYzOY2?hs2($#-1xzh{e+MM1GEr&n_78sOrz5Aj$B|$?0>RoM1TcO$%~>*z zmfwb(L5UuA%p>lYN49^YDQ+CZVC^i^xAe6?gCuU67$~F~{g0oGWdHQf8+xZTr#Ud< z8P$P39sDu)&*m@G0>2M`#@r$Gx9A?dxvI_2<{wFAe&+Qh&^!{UXy5)Pv+JFDQWxt# zvnO-g3C_IPykEUJdtiQ+>TZ2oSGg&_(H@|FBuIM13`M*yil=|mi0Tnr#<#v9pm$`; zgv?#LQ6bJgj;EDE{%Ca4ijFl>G)Yn_hjYi5H?LtRyB!b3Om_pX3^CNVr1m(vvjHjTTue_s9D0l=854;N|dBf)8Dm5Z* zrG)_C5q%h(A!~mo3BXP|)>f!ZQ5k)nBve!>drxD15X%Tl{WM7><`ThvA~$`G1^(rl z*$WB6=1{_PA*HE;UM~0Pi$uJ3f_dL$mXSyW=Og8a1fLj20I3D!Oi&SyXq0;-hKXjJ ziOv50GqdP((=5SWZ@veN&oipgG%?M_G(StKI%RWdKGA=KeveAHR&8-l27RMf#|6z~ zaX_jB!b@Ky$CJ1Wzpq>5lr=b62tOG>m%WMHh+4w5G}nBY<;3nn?E z!am~1BXS9W!3k9d2eKyE7_FPUgw>9IC$RQV2$RG%RSpv27Ba%;^}uWfSe<)^$RY9$s3^(5i6k+F?3333Y#CcDw2n=*&QQ)trKb-(Tn1{`&GN zgkZ4CHUNRPnxVP4C=v&8b)2|N4gpq2`KK(W!v%N$;er{&qp^n$z+&T7t4DC)2t42= z2>ughY?Kv1d9o!z;Rp1WFap@^?ihGy+Udznv~U!8Op8%E#1&#|_=W(C{|Lm&#|4nQ zwt|10rjNA}{FcCyi^vJ_>L=tS95gH~4;Nj7j!=DOC+pc|cMsMK^XA!5!I+CLLo<8Z zawQUFU6W1Eu_by;E|!T;DzE6HntXeH{m)riP(oEA=!|5eGF{(U@hIZD%x9#!JL!If zhL`He=o`6R#iR)GHA?I}O3sLQrm9hSGNyljV?$<{MC5<{{v!Lh#S183Cw`-+t9+8g zqp~O_CV88ZmaCLo2Hgi9@nocPOL~x$fQK=ekDzoT_mk^p;R!mP0-w*!W8NiINR8&@ zIhO;VxWw}g9ItZA-U9s;^Cux2YI!SV8eBFB#9&fX4o|wGMB1X}H)EiuWfFOJpILu* z-c)rmU2@{39O|(BNDTl)OE#v495FoNF$I%k4RS%DeUCsQ>EAE`2Zhw=bj6*~24jr1 zv*A{r%PU?$+j;jTgIHdyk-FmwH;`x7LU+kKGUVpv5{cQcov#rNpEVcrsY+WJL>ms9H z1P}BtxlVeJF0`TZzanJbC!6i@^y7?>f^%&eiz36dh_j$sK2{OF5jZ`w%SNLzt^8_?e6dK^wd1sB!NzY zq%-{__4`glg_JF_`zgG#cf)@XzPt28A2arfSr`3?S>`wXT664q5q3ypV8fQXf3*O^BM&fCc&AF#3e^zq?BD@rV1WEbc5 z^S%A`=NnslkMEH`K)>y6?Y`dHZ_8@o@hoiRg3SS-CJ+^Fx(GzRNGfEo z1vSOS*>&cSR@mNP4|=)#;(u;!>~C$p*?IAN|8LL!@n-Mk*7MEBk5*Ulf>(Q+^5TtG zySrP@_vL4rR$<5kAMSq-`o{@-G|H}MW;J6T52AZP%!8UUC`K3N?oWpca3T*E)(#ie zDG`qc0<*e+_%g};(2rC%zF&Z)h<-&*txD>{g|(j!7sh3rBe_PCcI|NCd6Dx~UV5Id ztczM-f&b(!aqV!yzV&#Pvlux3x;L8~F8uP#FTdRFT0MT8rZ|7E4px6SSp8xCqIvRa z^Xb;UYyh4ZicFH`@)w>X!Y#w~Yf~V#;K&PItz^!KE7tNCi;G_b6UzL_d@*M#E-jg8 zOpBer=voV07GvtKbAp4}wRZKYe$+S47vo@|7~e$Rrj+OGl&G<-MtGlV-kHKiSVkoS zhg;2}_#80giDQ2k&JUoKCHWd=u}Q=2*pk_BN#cp~#<#@1wl08DJrnch)3pBEY#`}a zCha*oI=YA_*gi{MvQHU9=r zLaze~g5TC~DC~Ac|5wiPHKaD3qR<_R>hOUt{Yg{Pzovh`q7o8xMZ^hNeMP@IF<<=j z6Vf#$=qQ>;)i1wDrnlMBhP`>cmNqOxYS3kEWu8;L{=M6Z!#Nnct6SPKbuMcr%n*J4 zH5%ErS{m(boR`;Yv9bYP)mYiGF=)C-%4Bir@@Bqt3)@@0lz@g6 zndy#!ZNPuO6QbAddN#a-aIw2)B#N|rIU+&(Nu1_fxNO6R^YZjoZHna6g9R^1`t=$Q z2N=z_W?cYDY!g~%&<(aEsI+fYb00zF`ARN_RJukRH zLqY!)6e7ODB7)>f+|XkYgl-E(d!=?u>~7}4W@djOChd?C-4xJ06vk;rR#{?sTm(%C zxOr2ypeu&>cds!Ppedm>7b&DV^}bneHctv0eXOXo)m83^_*>9Ah$b+xzIgjwvf%_4 ztda&ew5X(qg)3k0P=jBgy#c?4RgI=1`Uq8o@yK=ob@Q;uG7EJ*Mu#Oi#XlXDP+$-X zxki6?#`kxiwT7O95t-H+-=wglC*sphe%79a6i1oI$~>P)qknkVJt|jmPk6;z6h?vQ z8j8_9hFC76V~fZ!i1$K)27m@9X>EZWN+jtQ3`y)tzPc{V#@=g2B4Ms`4H!cD!O|;= ztTTBjnkbLW2Yk9dgvvRJvW_;YGZVdxYpZ{FAslvJSe{lQR-MGPxqESOaS`q8M5EE& zrT(xwgD3vHpfr{vy7$R9Hh9wWSEs<>GlNS}60izN6lpAF1nZ9bg(rk%imBu3v`6_V zuF;qNszDrsX#OHUV4uR!dv$>$p-0N{n{geZ$Xw(a6bGvNrt9-m2!hR%ZDK183LAgi zUP!}2hJx%|-qvIHN5o)r+RsX540e;F$jv`Y{5A!anMKsh|Dyj^9{zpa!2qgvGf#v1 zT`cu_qa!#CnzhJl2~CQT-x+Jtji5o0AT}|dqV`Fl8Xm*v{YUcYUy+c(;z>F_$q0*1 z>sTcvSnWfGP?QU`vx%gOCj#@m0-}F9835K%J6B5Ui0rncfhF z6enoB&6o=4F+oN$L3F)U|H=;Yy{%_k8~f-Cy5$Y6ef+1tnBJr#`kQPCZ+J^^H}T$p z|K3>N+g}VWGwXZi+h;G<_fduDU2c}avW8#1?tU{J@^b_PIeLSMbC`d-`$B&-Z~38z z`S*X@+TCh45}1YNCSc6^^Ud&i<}Z)U=KB8D`sU{1D8A^K=+CP?^K@$;e_UKzI?P|} zZf@Nx4E^q(epa$n|2LRT?FEAv@oi`qqW2tI{HrlC@kDizXU}W+?A9>Ej8)p zYzX0C<`SQ6T&+M{*xn5N_8)(ORV2$>c0|n?xXh$n8d;_VE2iY?b$F+cO$Px#`KJQB zq+TF42Q5lLdhZQzTKNB+E5Lg|>4nzhicnNQK7q}hJ8}g#QU16DRS;(Uy#HvGHXcqb zEcNXUsAx6$BnvYjBym8n%F>q72TlYb2wlcM+AG4Mk!!}3UARe#;0}NOs#&+kkMFX7 zeD{YX54>cfI&R1|ifU3+X7dRKO~3Pi3^{C%$;j-!(wQ)w)i+{rn-oZ)u_tl0A{(;d-rHBKq zK`9&eKi>NKU8C2`F3ErB*^-(sHeT%Qyx4oQyS4Y?)$YbtICy-QLEyBrnHaZ-m{-o? z%)H#c_cyP+q+=xaWLtPLtAeqdBvr+b0&ti6Uwr++)b%r%Rgrz34s7KAYNfN6dA9p!$ZWNEAeM9M|c1mY_CV(k=i*(aL6jXGRO4 zy#6O4ndRlqG=iV4^$vC7(WZlkHXCN=Ck$;QhbHG?d1vUG^~#HwPq6vW-gh~=wkJi{ z2u+a;pUXfs$B>PZ1|C^zvU#fH6__P)uiM?Ec8>Z#$DK+3!|8r(9{_g{VrA)ZGQ7a_ zPIHk+Fo`~@JP`&8o6)N z{Kd2iOM3`RoQxqJ5b|+Ls@^+rcrD}dD0qZ}KRY5ac@^6%{>7RFaU*hnetzCRPV-_~ z^^0=6Lg*dzE)~bpXQxTE(t7O*(~fa}Hu3uVWicCMh(;B9uEUO#Y&Gg8l>wCwAKo`q z(oy+d?>~gG^0lXll;&xj#?1S`JtcBT6fgJqAsUqa&@)JLvb`iYMRit=3&81n+^wWI zdC`A@7arme*%E5{fd%J(k>x6H{mk{&xrr}6PBqjPnVqHtfMw8y_CsZfd#Pl)g3Fh} z;|#yBK>?2mt4zWi6=W5AmECTGbUQksP05bOajH; ziz*WO%n>o4F@KBL(#{x$CNt>{hh!AZ5tfDOM_MEe=v3{wUWrA29r0=OERe(R zTYf+Hv9uw`q8i;^acj8ZZJJ+{Qx5+A(S_>iHA1=JJ7qVOsFGKl6z8anCvLlF?)#p6 zMj0&r;LlEo5Pf!kAV>7E3(SL8+~SH^_#X;X`lV<8`IG&ZF$8X1SThSYWK^x7lG^o9 zwX(alzPYp2pNtmVGmKf7#`Vej-HBp^B(HHZE$BL}Q3GRVnwz(PI-b2L%286TnTLn@ zNnE`do}}5RO!75Tm$Ss}30?PFF4Q2gRXGtKuuxW^#FA%!ztP%+Me6%AQo1B|4f{hF z*n(DVV5+*VVFPen#B{zPe!(FoI&JGDV!APo)2WIyF5|ysqO$_Z@Sgb|vw7XkW^RI5 zVBe}aKdnrn~piDM34YAm7Q`Tnrjdc2$QOMcYF zMkCUEI)jUoRtV7r#{&GQ-@kSePFcJ5KbjW;2qlD<~(?CHj}=nv;hg>^j~yL!aOp)iW=PEFE5$ zKbqYzv^u4m9A2kq_6uw?f7Dc*V*NtKtuuk|3?2S2G6!9ke4OoKlwdVPahb$H?MWnW zmtGM8Kmn_lpAi8W0X&zv5dkj&x0mS=0V03*I*D{`yex}x8BZwL74`u9#5(j^*!_uj_wl z=$0S6v$0O=2a^*q9KaKEy%vvW;3C?Z=4Sd(2l|`=^9&3DSp7q_`-pGl!r|^14Jil21-$wA)(eF5i%D z8&R&thExySKGcr3{k|3v_CzmW>*IeF@g|KOiGppnTyYtq;q z{yH60dqG9%Ekz`-#T4;FBY7w)XYk)kW|ngySW~%`iZ9EQ65m4g`VB5}X;eMZ>vVXE z*d!&4{cSdja~HA1nKMqX*rz9;X{FhVL%|ZRG7kl~PRNkCFa-##MQW3jr|W<2&4}%r zfBy)5MJex>un|2|ewg)^1 zY+TY-GTitj`k>ZpV6>$*GDy*y$A?#$*)s<)E9qlO zzZL_JxLJ2g+amWop7GOS1e*Xz3Zo@HtQpxj&6v6tWp?26IW7TUNwO;8&zC;3ut_I> z!6u&vv%qJAU<-fa(W1|fg9Urz6VzYZWTtw{iInW+t7t(nx1+;t1aJuo=r&2oIN*m5 z=Mmxxvc^|9Zv?)N?ykXGHm02e+u>2!7HnXL!3k~;-V&m6eK ztdWk6%rr*Ggme@HQRh5pk8Ju59|-m&HYu@1$r^%Y477Moc|W9{lWx^FnJ+eWpR$UJ zp2&Y9SGplHTl7nH5MJUTog@^JF751UqUcWIj`m;}ucL-Kr*(nGYMz`^^Xwln3XC9m z5dKllAy3TXA&Gg|w{hn*SgC%39!NU+rKukJQ#tCPWnDtwteKMfEKR3&e<0 zyqX(L*7l(3DCY>L0+{B%MwGO6%huau@IEiE#CRnah;mAevUzAVz2cAjBUsN4|InRP zFexhp6qAvyjMlB_b{G7#Oz72BN-ia~q`8|b`$}w4%xzz4^~&hbV8j-H1;Zqd%d~&! zTfo08GGGanh99sY|J(JOF;_?pTziyuL>il*z$o-4I921BHhpE?r04s{F2;3)c4g($CWSJ}<`S_K-Ie1F3J2LT$>;{2pT+J~O4YP_J#lLX((e#SAzI;g` zYhAK>w#trJFtrEzQnEk@J&YpQ+G2mEfrEELnh&zI3T4))Zq?yH^yi=%Yw}u{R%~PD+2aJPkpJ zEmNJRD8M22UaWfi*t(eW9`4t>Bj(Scoz?qpw=Q|d+)S&c1?CV(gXAPWOBuOodvTOd z?V1;pAURcjE{7+`+qVfnFihAj?v|$}HwM;|wVaC59{TpJqwCmHSas-Wgq+=-boNMr zj1=xEt&H@9wW7q$W?4?jn1z2a9%Ky@RTd-@a}wvXRwv=o+lDcg3FfYq1!8UZJNZ@=Aj zL_vCP17*I5@8z;PWI>%)Zsk==6dAVPtjK*m-~6Fx1fmxsnSmrm@&_*Qpl)>~u{`!) zWjjl)Yzrgw10&IHaQ}{_XTwt*#X+biq=`UKO)&e8^My%o4%!*KoAteaKc%j1(Kxa! zVo^IQh(T|iZho_TX?k)|QBa3}AwG6*@j@kHC0Bicfbemln-qFPQj9=<2hX!P$ClV{ z4-v@&TNf8xeB0X=&9;bQo_Fw~NM01_2Mm)cirXVvEvXfOX#r~(j~K}g?@K3pH~EE3 z=78C;*1gfgT-xFHgD8ulE=X2Zky1y3F*5$qA8|BV+Dz#gsgoek?F3nWy+&tCATo@_ z+Vh8_ZkU$%ESa?$IrGS`G&yD+qi)Ym*&pe;En-hXeVAF{O7UGv!d1P@-btnq0jci^wg=Xn>98GPDZy3#T!uko#h zd2QCrBmS?m$zJ*+ZfnE}=x)b@+w@tsH`mPFPZ>Xu_5fzIX70YKl2ZOsRN!P=Gk2e* z`RpzI@t4Egk2kof&>E|gVdjn0;Q}rBa`MI{Q{Twp`Ub=J2K@?u!e>&^I$Yo`rQl5K z|5R&>Z^3mP4<*W~`7iCqr&T{C605Vx8w%;P-q9F0eib#ALqq=6H0IjdZ@m5M4eeiH zbLL;yAC_Zkmg{BWtx^xELfS7U9YZPzRL{b56x|8tc~-tXF~>O}D5;zcJ=H`Hh}tnWEB>;~@uiedvz6mP+R)<_oVGcs6eEBOp=4(SYkNceJ$} z|H1*&t|)<7j7R^3TVX2=xqcUjLS~y;I?RRZ9QR}79@#2?KvGjg8@(s?`+ZFODg%i2 z!76D(*b&shw)Tj2qz%_fpIj$UJ10QfaF)Y9)r%Ou)pE=2A_C^c)vNpQ%xRHjHXP)S zCi14UO5@J}J+n1GI!t!kllgaQU}CA7W@7F{Ji+} zVJs;Jss#*VbG8z(E&?V1p{?S~xJNn$@=%_EAB=jT)nSvUezp^DCSRVDo~+^vho0>; zt)ZEfV?yUXWGc4HL(b{@#7SCFDG?XS!nwc<+=#V*bpmrZo~H=rX4J{GuTSKh^K8bh zn17{RVhh?@{>a*|=>28gk1dWbXl8rYLtoSD9D&C@HzA z1h(~Dx^u9tQd#~tejzJrm1%x~RHe&w?jPn~^_7`DF$WDV>^(e_^jIAVj)-)6B55uT zsz(-ob6fCBI|`6nl#TEGQJ6P)+Epc>KG55}p#zi|BgH&Thaoug{&h=5=e#vn_?um2j(t>)gpo9!AzZ8V(tqG0|fI^QE+e-;#C$Yr5$Z4N! zmVx%oHXtC=s-w8Hv$C+~mlgJ|F5T;Ol+5*i+Vyh1`DJOnE9=s<^h3f!%>vjqFz8cM zlJ;O?(8-f1K<@)y>q*hC$kUd%W4ak`-lNpxLz&}s3RxWro~C}0^9_n?Z*c9X0EVgJ zf?Qk0O&Dg$e+E_5wn20n!~19!ymnSR=%T$wAt{rDG1n5qhKg}Qm_WRdAl(G`c6HT% z+;iMagjRtLrI6S5-s_+i?o*Xq`xSv|RX+)~HZC!x9y5zu>*lON1rm*ce2ps}8%mj2 z1=@4f+@+6CQsV&Q58+MFIwIk+2=<(Oi`@e$7PKXO3buWgpP)=D39mDD4E73l}$6^P-C0TPUI@2 z{DRj26@$`(Wqo0wg>iP!AXsBlRtAwuwwETAt~k(4SG8c{?6jo{qhdJ2l|rn4(^>HN zK70osUV$08iRs4UuXQ}A9s_hsoFJG!aXvgL$cu2shtlm3?%6GmElhtqC8?gSCMP_p znzv%IH)^?3lLGrhR&nlxeN6l`?TFGy>Xq6jEZy48VRLm0RLHSAq7m zb_vJh;M?*8W%hW$u8uRLD0}9A1=n4NluG(I;r$8+qBRb5cViR;!~*z<;>bcjUrSAX zXH~|R_PRIMwL}-hL=t_RYFwcW6^O9Bi%s z9**WK%ukLzkR$Y8$Bb}AX`K`tT&nt6tbH;uHwZK%hH~d-ZZbe_ncc+3C9&Z+PWs?J zmVY-uW`k@3sl1++X+BJ+I8(4cbGf3t)@k$|bhW_FH+ak<=FLO5Yyv}C-FZ?oquwcgEII=6aKwPPw-_-7viWr+{ZD4ha>Cg z%G7G>g^0bERS$gE-$Xw7Tln=|eShPy6F+omG^Lm`|IL;LESgd^k>-~dBwdDoSE zQHV{J-O>6K9*u>HZu$M7FLI`-PgrS_NBz%Bw|Ql5U0*}14s;bOwCD4FzoHb|NwuOL z=p8p^5sz6U2g*&741v#2i}uPRVSmj$P3n2i^T8^(lz5xm zx3eN0QIUO)+CR6qs4fZllvaGsu9)g1o@%7TaTmb8Eob?sIV3*YCVcaG*u@KhS<%jR zu9NX6t4&jhM4UTvx0-vqYEX36EOB9&!=Jp2p@?l9Ct*_=1mBXyGY|=6v+GL zss^*d4h1ql$EgT=ZBEGI{!TXMri|s@Nq0aw z9E!-nHv@Jsx$bI+rvOSeJw8dvlhR%N{)#)L8qK{fFSg$wH|9&>=7lf>ZJ9?Enz^pGt0!82S_r)%+}e zx&qGTZr~%v#!yAw#W=mQLUn$5tZkf$vZ`;V8KCjlaV{%F?oIJ>CRp>&YSGwnEwzA8LA@G40{ zNuto=Bk?Ic1Jaz>n@amONw>dOC!#0*K8u-_;)%Mouj6c%tX(VG#o{#d&+ia2|D$=5 z}M z!SCGxvUw$qiSVAd$Id-bIuoy-gmEh;jqt>C^!KU;Qc?4ryVUwS?@1_kxGZj z+6Qc(@=a=EsFT^UN}7g;pr$|@V7ZUnVv|HCA=KX!AGppKYR)P9Yo7oFw&nsY8YK03 z0^aV9+;W)JbmfyI)WtOk5c+N=|4lW2V_d+s41TenNe!HqIahOYIRJBpIVX~{V%_dR zD+O;0yH8@IqyQa2Vt~nC(h{S@nP<=PVQu8xLsxQ&QTWCP!vcDM65AJo@|rE}nd4L@ zk-s+G4o95SR%(N)c~n9WL&g$*$})%2AzwsCPf514W#8*z*OYkrdz_~f@)v)9oy95} z_%T|T98kPnpnaEJ@cuyitDkli(B5MjmNb?F+1rc$C|dOa#{SDLJbl;W6fbJypEjU* z@VS876!eW~-TCpx4|uyU9!0u2AW*5)U=img?zp$QTW4jmq{w3z^6PyvD3h3^&fvXW z4EvoSF_T6V44sxJeTrN+fHDAoiS$O9gExuvT=99UQOWHeu1qRz$f4o+t%>;5{PK?@E{$P`w!Qyf4eCYOeQIxIZEOGvdh zOY>8%$Pna*G^|01O9U*_qW?jb?q9mQP08Q8dfZBGcj6yN=b6UrzfAFeNZ)LcSh64~ zhoIE*Ftg7v%Y}sr(Et}i)0~Y1h|Qm;+G`#ycHGA62p>0p;X~a@&@-2=`SjTz#a4K*1A@SP(=3nvAl7iIzCGJ``AQWS zI_o)!CzPpi(j4sIMd?dc%0ON_-iGmff$2?)@KYmxU+;uS4f;6CTn>(7l@}DpouC}w zn1fJ3)}U+$F@ukr^3gpxNWF1M)*!hkZ2yti3F0C+Nxv}%9dd+!AC4in2W^@Uv)L$M zbZ(h?L6b2Ey5K(`0E(I8iD`cX1!G%=#X`v%#EMn8LpV(B)+p;nY*N3**Oe!J`oc$d z(#eMG%ptoE+w0WiGO|4Eluwa8U(_u#rYU&LdC@JYZdzr zSt4*f3aynW5Bad$Io&6l4cFN?Q0PgLq0XjJmKCUt5C=aVp$wfPOKzK@sE55`VDQTr zdt|7VrMN%Bbdz5|C$8JcB^Jn6KfMi4MfQDP2rO0*sy3%g%=+$*DF#T;DY4k-DtICb z1b?9x2D=EnSE7i*hCZ{OW-~91%5fxTsAiTJ^UFjncLm2u#GXs?NHvqmN}2Z|L{nQd zGYdFMi9j-P9Ks*ihibNuw3#e`9-O=etMjQvDp^e&IBCZ-iYNeNSbqUpg-=(yqs zcxhPPhsaL%YHGvLmYYByXd}Gc07(@hbI?f35T#*d(sYNeRNlDKf@tUPOV1PAR2mwd zheSo7bb+)-Tr0s$n-No1a;BQrM1NW_dxY<<2@eQO)xw68I$Nf3ppO?{>TngpPJ`tI zg)Xin;zYUhy1j!-aVf#gLB-BB^h*9#H`c}E(RzwV%D-UNumpYq`bNdF)sXrq8FajV$!=Hzd)M=c+jSbX;1d| z&qSb@HcQ7Rmg91Lbe2}+fk~K4+Z?EY&&uHmJ6esaTFHxfmx?4ar+?a&B7ur9hbaX^ zxCR`!(8gFG%@kNVmVes|6mr%VJ&&h{|K3qqOmX@l{s7|q3i?H~C@b6} zQ}d)aC%>9z2GNtze=@kRx<F$4uOnU3Bp`w_Fvh!$BgEvXL$Pc7JbX&op$HA26S3$t_{_6t2?{xvc zZ7SCuZ6t7|hd@WpSNw*m%VLYOiz-EyvB|BYbAeM*V@xtjlkTT@Q4rFd>8%j8=I6O` zHJW@K`SD=;ZY9($9Qc#u&xNsNPD=WgsmEC|gHXtJKtn8|8%GG2^3Fui=3-V)XKXNk zcb7=p;tw0#^u!!~Cv4}mAV29h{~fLQaV2OGkj>F~%n&Ng1Y z>LJ}z07ZiBCmtsrl_N)fr!xVRC`*rjNIHFjPPsFtk8+U=e9@90`BzPrtN_TPbkvpj zNEAf!*F(+~;vIU%{KPHY`%bt|7Mz&R(9*+zb(s`PX zigWBQFkMkLinu=WPY6@Ra8{O|YE`&cClbZ_J&}G7E2XD7g=|`|C-sn|1k&@54qnqV z!qSk{g9q8Ln5j#GdeN-Z`TBc*_*_cE5XA_5D?Z>r70+cvgQBjpB&WQ=Nqm-=Vn|~( z!fKhs7bck`<(QdN55TbIwaYn5zl#qwi+j)39pPG;RMP_68g>UFPv%A9TxxF$*N9jN z<*cdVV=H_Oo_9)O={muwOs4~~RE;%4V(i}Hqey%T)+Y(8n4lZ1M z3`=h$MEzBoe-^VcPc9lu?5xOUmSI7W7Q+jx5C5qLCCZa?Hyk`=w)0_8P78`nGi_Cv ze4XXPq=Yu?P4bi1AJLpBmPfxT|S9kRk-6r^BSmE=a@19KAm?`mQ>u=K;p_s z%Z~bzWf!n8%R0jBGmGbcNphN9AeL00WEb43tjNdm^S@?sStn(7u@dKyVqfyf5k83> z#-IuxY0LW_g6(pqSXPKe`w4<2VcVk<)`;DL5y zh8>TUv4(=WszACT8VgJ;N}&)`Fk^sD7+jdNu9EDyZ?=z3EZd=nWuP)EsvEUcP6C1m zrNkLJ7c2i~gNgQ|*Ms%sd=kVb?VK?ciFK04e)4KDYc`Pq+KxEL65q6k3V+T?QKmma z3_G*;EXE_A;l#v$EE&)xP0pSnTsrhG&oH7T@zoO2*aLdsy0jQcD{|~q7(FCvLMiPG z6N0~MT2w?Q=(Ec)GPjsOls&j?zIv=R35Vj?2P>lOUZ39vR3ou6c@tdJD+GYR zK0le^oFFzKss6fE(Pv&r#FJfdt_^e$jvZLQ*jSN&)gw8JVA6k*&m;d=vvQT2-95LI zi4w{N2?^Jt>0gWWQ+xqGMeO7Wl5||sDdwC>sHB8_HK~4+ zMku_06_H^oj^iK^#v@AyJX3Wd`yO2zazsPsdw4vDc$&9^-K5a1LUoL(5HnZ7$fNXF zvs*nrbF>heOh^merKY4gt+6y`eGf}(&Z>g!y3j9HJxjUsu!&SjU75v$7LSWNc4&Ru zP`nHI-!v+%PmJ8tz_O#S{@ZL&-3UR=+B=MYZpO2?1;lK1n${~Pvq2?)i|}uU-&k^~ z|IhW=ng9+Hx^{~c1W7;w7;+#}hJwC>(@}si;EsS70gV|H#SOA>G2`3xe&1!NY~3Of*H?i-^9F4oSawH3+A8hcF1EaP0cQU|CaVX&lV8k2=MF zDBQ|}hm}4Py;otgt3E>Byt`if{d4EndEQm|bN?CF&7t4#%Ap59+(3-{FJ^8ka!y0+ zDR5gHOpd>gexF1CbTt{1EaZua35uy=2^MPx>$?J0XGCX$Ee(cK+{Gm#aCSkGJ7o=_ z+-9jngt>pW1m%>+bQCUEF+4INvRUnaf@py)@MGB(?Ky{wUlO5FuBr=X2FW=~jRRH1TP&hQUNuaa5Cn>hN}8dLI|gs|MHE+m(M2(f z#sw$D7*Xa|TxdSz3Lwfl?DKI@U)IF606?yJ?YhE+4sR zMUa2(g_NcF?Cr{uu2;rmhesZNNgG=eP)Eqx0-yAZBR~=gzuV`nP&}!3EFa{`dcPs^ zKeAk;#n=*0(^`&j;VRV+7^n5gY(VX{U!m>Nwhpplu!2zCN>vV5@EGhO+s`+*{+H!8 zb$fyQ-oJciCs{hCARlf%;6jCDWVRJ)XiFqMTox`ka;x|(kx{|_Ry9I@#_o5bw1_WM zEZ4{FQ)X`(EM)&@iU+=BW@ibYQ5Sq04{OaxcsGi(H^=EAlg3g_cMYzSm;GDy9+o+#$iH#z1OW*H#m__rl_-E;+8&#lYIIuoyQe_1~J+nA6H4uo16z! z(@F2XLZ(tw%_ft$gdqSU>((1TjI$xqQDn-L4oh!i!8B22?+NF!oyOj3unBJeaOCrx z%rA}45`G==I>L%$dpr0vgmO|5SGkj`Ax+2HNEfb>`}K}r@JJbMF+O`Kx#JFBH5q$0 zL6#Bv-U_Z+4nD5^@yB0bU&jPrr%VQ78k8HZ%M>R!+prWA(;{8Hi=IuDH5QSl;Zfv` zi2j5Nb~}}Ko87}R_ojDs{9<2^k^b<9NxNj4I?5FIUYMjW zaAL%M<;x-LCclQ9a>LmzQ6E^S2xQcJr4x2H9WC`e?Mg z41EDtKN05eExt(jFm#inf?~QR&dfoJ+~A`PRR1u)j~-bcjf6!d_#|}B_e|j-yO|&` zjxVg26yh_E_GG7jvw6RIbN1j!>(RJ~y>AtLC&>u;ap+yubuyVssb*6@;iG-|H{dEr z>$?FIj1jhf&Y!*h2{MflB!FB`|1f_*U0PMe5TEEAdFoF1`1}g4b;1r;ii=-C{Sy`q z&Hs73KtCNFSt<$Aq&aaffyL$>%Ac&_uuO&tQlKFv0Mh_GF8(T9fj=f?@$tS-5xwEJ0T)z%!c)#Gz)xf3E3`BM2*WBlo@E@< znZ}&xa3LK``J#-=lv2=-&_SCx|HB;%U9>BJ>nuZ_il-FJBqiEub&d9i?v@8^SkPo^ zuknx9YcQnhicBD@ep-~%lbA{P_*1Ny$elaZ1nHz-wx){5kAIxRigHL1$RA|s5RoKS z%6rLwWt)1mq=eqGOZ^*CaNT&e4gTHpq})46Amdk*W_N3EAE!;<>?MggkmvpX?7i!9 z+uE50_$p|hlUPy{l5EGF#O{+smUT{4v24e(ok^rr1d&@3A`oBzP%<6&RDSiZshX;u z{xwxoHIFgRb6#LxVQPJseE~p^UajykTbJ&O+T=66eZ;+uga#V%u?!Qx9I)LoV|c%GHz=}r0x z4ofKJ9d!1peMyvnl$eAN4HooPMFf#a?h|0!8`V4Pq7~Sht84%+aR7c@C&$%y$taC~ zAN}Om6p&>^&`+in~FN}(b=S;kSe{3WVLv3 zf@Q{3Q5B*5j3$3BNh}NI6{7N<#YL3?xLGd|I4?~#&WJP6-JDrMb)Y)Emt_He^ULpy zHNjXgldG?EFlp0lcTcy;@gb&12t8>X5%O7#-kEmUQFM};Y!D3?pc#ZZ);$Jm#-pc| z1Qc+w=;n_n@6aaEMZ(eb#%Kr=b6mBO)Eh&GcJUH`W4ANL|g8KqT} z!3IO{EN?TP5#E<*&)^@5(XW48E`>tM;YlfzNvkL?sP=k66kf2R_-A{cA&vm`;&L_H2u@TF0 zZeOwKLoT1&jxQt#ZKXgli+}GpfGE^j5#D zK1(?$ZU=Gw7VkD!OGFM=F=$22j6Md z3cWq@QbGYw6~PX?Iu1$}p^^}R>R1^q1BHOV6zkwA3Un&@EZg}+N8v#*4tGG@!bMFb zli*6#+Z+^uWP7zed`=-3Woalg6>xvig&pwaj0bZP#P_q*XUX}0HRkI(`XKISX^dx8 zb+dfyDEVwNLwGdZ)G>yFoZ;A78m*W(F9oW83E$zgEH3MijKan9!gQ3a5ORW{T2rEz z7l(#71lQh-#n|0(otXWRjVLTN)`FqcaXg|dVglfeFffa>O*%p?D|3tsp_8?7JL13U zn1Vc$%Q|2d(A27ba9MYhb7u&079OhU=JK-Xa2W;qZg1m7+BYNDcMR8iQVd-0%ubh*MdaOSKhFGcLSXi?%# zAJx6Kl@NNYQR#wYjF-3EtTj%>c{7l}Sb>s2!HYd!k5F@DE~ip6-qD5gT#J{yTZNW5 zTfi&;mR6WA;s>P4LjlngC4aT)FN{!5LD08_V2WKe&nRJuJypucpXBhxKni zb?j(U3AoyS?J%m7VzDMWiM5oN*Do+AoSm;wqEkgfK%Z19gKLzlVi;15qjFXuh)Q|u z1XTU9PLDQnPkH1G^pGA$FDuUTT4|^&!*#xvAaBV0WcZx~Nty zOQ&arWriRc7AiFn4nj7^$ztXoe8QhHZ0p%&q z7Qq-BCE6MsD^8*VTYJqsgSgPP87kh`ba{a$kz#3EO@X2lO0(TDK+J(b*u$~?#hao z0EQ-iP)ne-;E}_Y+eI}js_5klyXp9P3Hjqi@HHfCH&M4EXpJW)SU+z@W(JUjd0Kye zy|xymeNBL{FkN)uL1OgmmZsO%?(`KOuSakA9oE*~@(m_rk2F_nYf+sX+gCcUr-N!s zwFGNc_&{2{%l8n1+b;YM?E=V%^6X{i0@*yd<0qpQnns+<_~Tx*(l1I=#n36PR*!no z!BOM1J6iV1M4QZczR~x|ahdjyFmF$P9O#L!Y?$6+f^dX+Zs+F4S7gsq<5OIfg}U{u zTf&14(6rE8`0C-b%}se1hy2ghqpi9Iui1eoTz`^Yt7!VROEp@l`lT^B@gnz#h_a+C zpGbgf-b;y^g(e5)t=e%(zXtr}tiXl+bRAX|S%F*<#cE}=4}x1<+INSO*Z^1E76w6F<*3;U*M6)&O7nBt9 zgANj{afYrG45=#4!Kh4;1;b5skz`A@Inxt(0h2xx=>*ntRW$5SxC?oXQ<-ot#kk5Q zjl}t)JiybeAm8IAj^EVZPVx7Devt1+KaIZM`u+UA-V@K)YqoKiZx_QMOc4rT7g=$N zq%e&WA)gq{rEv@E()pTs@Y1UFXb0y9usRbKrq+~eGOodE1SaVw{?Ym$BL;VufjKEKiKQjt!amB@9}{?}nV>ra7c{n0C^Pm{tIP^q{p7TJaX2 zOiu}SJe~9@pbDy8rK?aME_5U-J6rU}z3r{lURch3&?1HYDh%bl`@)-S)y&$Y19Ozc zt_oDHKYJzod1W^BvaQ6V0xP?(nhsG58%Kq!tCW4T2d;DG$Z=*e7~Bou&?HpkY_+^) zx>SJsHstL(OQhF1Hs1k%yW?K7MlmB*x-gS7295_ytC3l?Qx(`KuT(8TkZ%^gu}$kv zi}8v{TE3>?`V_4Hs4TG0bk`#OCgM`ex?>AX+2c%0K>ajl(v*PY+0b8DIZUU9NwQ_r z)UPP=rL`71rJP>FYjkN`5ejw6kl%@P71`Y#QkcR0bjLNTTAL7mbjYimlt~UbAR7!? z+=9>i#&gTkO_{lBlINLJ-Rc_r^7U3}!jtGE{e*pI%3+6GLc5P#p~DZk{h({DC0eGd zA=WVP z(8DQ^(5=5)HPGmZnbTTT-W;vIiuP!VOT8sjC6#!4QBu%Ua%SDZJQesRn78s;FchHCAVIf9dSZn@?tND@XmWP zrY6~QOP^nVO%x97t1$zmuW|q(dz4F9RNTOvkP0Vr>fMOHecC}xcbxq7wC0ztbQogR z*iu;?Jq=zqBue;g!CoAzNsXjl8{T7!s?-OM=Fyq@iou!LfFt`RL$_lRO3SQHz7!*N!pwaJsb-f&WE8+Na`;7rVN z7O^~abv@eM|43zCBIZI>YgIuYD{issDTg2uZb;ZBgLJG)n^f@!9uX;@K`CU&O5%9} z~e^K>{K zMuQ@M%aT$EX<*}W>tcTBn#L|F22PpOYX(xf!qgIEs zD1;5J5N7u*6hj0$V2A`Q@^^IkPzRs$8;6Y|c1Xu*KJnk9P?iXr&)@&u2N!C-Ml|*1-+vv%XQ3$5$|;txmB+KzkK4 zZ3VhS%#1EX?^g+rhT064N4U+Vi8N4uBanEP!B`GTv;xCT>ApoP_9Bx65WTTieXqRsry-f2lVVOZ)qYhGkv{Fw- zg65?pI>F^X?nNibFomv*m8?GYIR5AcJxwnt;mA4VW?1t8UHP~tm!5i+*Y;J=%EeF; z#o7wpCkG8ur5is&+i5;TEyji?KRX=2TIIw3H6h70(yD zSoc-eCca?vj#n$d2dB2$K)z zV%kz3y=$jIUUl?dJD!y08j%|gq$LApw256@m`LU}q=J_M6dU}27!TNg2+j%VfiBK1 z5^$Sb?Ss?Uj@j-eV<4jLN}L8&LqHCVb1UbiF0icyxns|p>D{vggMA^C7<|`yyp_jE z#g!Yj2+uPx#Yq>VU9l1}61lhqjY~n&H`bu$UCt+jZ&`mIYD?(Y_Pglr#Bn@{n2KazdMN)#bu)ROAIrGT@k8$X)pBwY9@Mya5q> zQa(mo+^d9X*7O!Ak}!kH%-c+pWo~Tl&L)Pwu{|w_US1%OJ)5p^c9-W4&BfZZLM>Y|HqH&o)0(4+1$|-Gqd$2-IEL&? z;SETSaQ{CS?ntqugGLZ_QW$(`Mjm+B)iChd(qn14hdS&((J~PU0!D#j$s>uz-lCHj zvD7G2&_C^*t%O(otRqdvT|?)kRy8=Si<1CI;nmpB22)snXJZC`duRUIOSIomk8Hj) zuX2QVA~BlDZUlv=WTo!{cEEK~^_iK>%sFE*zEs6Gw%vH|dRZU~=Jd#MJmw}|a9%#F zT0-us1bbr9on-S_q*mUU1ddKok~T6yLRtsKs`9xU1h0A5wlF7sTBbdfW2|)5eKfyG zG-Ip2L?H2hEW6rqKiz1xhD0&7G@>)j^&+??&keG1%>%YmDp69kby^ypjX9sGyc4$mkW7DN*5U^8 z)9y#C>};)0c@Cx*)WD)bK{3)}T-hAxHaYlXxu58Nh(KwufT97!f;+C{EJc|aQr=*V z-PvOHY0dIgQc%0~na~V0TwpAr=q)^Z?i|tya)t%<>KJ!14m##b>kG5?@%q(Z%RhL<9gqrT_ zsKnua?qRlY%C&gJ5&l;;XknS^$Xa8ismCQQ@Frbc38PWg!ZS@p*UK6UUS5B?H>~ZWUNVvvw+@d=`X=85xEl* z#uY{%r^x8wjD-Wve_Evlc+h+aU6PHnwYpb-qxQTV@E6iEVeEC>{p}-(4nvQf!V155 zG!Pd5gXP`T1ZZb4EZER?v#UyRgEEe^qrCMi9`FI`8BjWkRGm87`T&}vhX~{hVU3lB zfOPk25_H_ssu~ld;O#Drp;rJaEJaiUCWTIq)}vQcU_`DI!QBqp1AM=hn{`yYgYJcY zJVqWT+paod#SB*>=D!0#Cfr6lrLLw&|$7UxViO zz&L>$ENx-C;_AggT8*+~VhN``;OCWB3pkCbRP#V6c*S3YZB16s{Th@NdV7ITskx6} zlqoGUWiYYA8e`2rXY&WwpLe|ASof)a=q>2*$~)3e{WLkHh$Cg->j1{l?-1efb}!;1 z-sN+aj_%jsBi=m8`$Avbl^N3Hk`sMXD*7OgMPp2?V%Cxy0>FgL+q^iPn&vQ7rBMs$ zX16DLy!q&9y!rEZ^AX)VSP?i?!=tfrZQZklO=F5HK!t{n9&bMSW&CI}-h32)3u`zX zj!qQ=OBkRFaX_3qwkWR@C3EF%7exwI{R5G zC_}uNqpJP!Z$gHUlGl2IUtZ;^?rq<|R|T-BLTZahP*tE=-BtZyR2C>(7tP1~qJXto zu`;mq@yCDsC!AYpDR>6s2)?R+mup*(6&!VaZ&!>Q>*~I^(P#yvmLgY9+EGQ8fv%h# zVp5oJ?8l4rj&GQ`XH>1c;>__}z2{T>Kd$@ochF21{^07J)7UkB33&T_g&%PD#_gN~ zLVLFrS0Dqac{f(iJ(WEgK#Nt=Xa!7$wzE(0KfA8T#@cFm*y@KJ-0YNp_im>9InJsa z=KI-Vu6Ep-qau|WOujKo1QqN^&|bBoHJV8uO>yB5cC4y^=g2pP`JRp%ssZM4E8Cd=f#56K4@Uaen1VuA{Q9|kN^TVorcPxGJ zv{y;&#?6|OQcTB4P!j$+sOr)rLx92tLO$hH{93olPlC%Nv|s$5y<}TK4)^zdlI+{K z3gt1FvKPzC#stXhZ-;O2i9_TzzatzqV(Ez;zU)^q096b>dcd)e|LT zb8eH-NQ(%j#R>*Ku>J- zzNeE|LKt@h~+{MMpT40=81HLl!5pz`0Pc4aW4`+?mf%PKA`#We)FXA$M>+=5KokwrEG~=hyyR zatg7!dIlALq$DjZnpONHVcz_>K%E9qZB!Lf)qr|m-_xEO+0|-!KFAyS*Kbk7PPA{X zX|1bO{dDu`EP-&XgdPb3g~0^RJ{t+um?GE`=(mSERi>=-CCs7FVqCMLgph#4@Nxt1 zy3mtzNbqT1wF(ilDF><+6S9d&9Ro&hP!bJzz!#2xs~xo+q6RlW9}B{1@%1*PBXX~) zB@}Yyf>vDX%)kUeQC1a#_9!CO+59{3h8Vb>aS4OuI+uwoiOyBPb$cp_0x8D^w>QAl zNO}X+m(e9X;Q7qb{yDzKjGi=$LPn!}>NM_{2x}}=XGK}}Sxg(?9R{z4_z6Ja_}aHt zsFy>3^vtcr?};D(@t>}KZwdi)BE_wo|KWONdP%tgVMP!R^pF4ePen2~E){>jxbdNd z+RzsdAcS_;9~2%H$Lu23)`E ze=x@)8v8HjA}f-E)X0PK@j5bA}}}+Lk9(^Z z?Y`gNqmGva2&u$6;hL*aL5Vj(4oe_QYkei#Lbab%NbR2+>}+GDo+VWzU~4I^=s;TQ zVZs*EAgRvCyin96Q!x8S45DxcUCLR1M+?;HqQwF9vz6fDpc^>Nn7-^)aT;yqNj9m| zKDnTzn;pH_6(VOa#JIN+(MFPr5nkzv4SXqYt&8X)tw6K#*|4)hbrq*tm&b;Qs+M^Q z$&^iHbH<*_uoD7$Ts0Xar{JN%zb3l9BmdbEV25yeBfic|4s{V-CS@ML(xpm&ayrqJ zV>OD%|MK{>s&z4`btedw1c1nHzmm_L2o80r5NF@Sw_AwrFgor5A0DM(TBPF;uT59OJ%>W5^6mc}iPUkxh<#Gs~iM zIKsUt=a!?9K;5-Rx8l4=R+XKQ*+7_okl>5$ZV6(d@8k+T}%@h!YkJ=LYGX!wv-zR*^^EI&tq=6}~>35EKB*#Z{v`k!J;NC9%=9Jo2yO z(^HPnn-Nq5>6M*HtrJ0tK|Y!KVgAMb@e2%w1XAFfEcq$gAV)|B{Y!*$P2fo(9V1ty z{ZJG0#BB5h4aadDb^L#S{7Fe%W!HUit3%*hA(bkT!r54(ebg4MHof*5z{<-nLK6rltrX|qOI z7}4Pug9zMz)^0C)X)dA{#V7sPW6$03^2Mt?v7dc(^YJ7~24tvmIb4TXsq)gowa_58 zA#)LmGLs@V50S{W)D(nX^OQXpa^V|Xvafw;H@@^u^gA>0V*|>Y3pk{B`Am}AASB_S zHP|VO=xQ@gSxVsYk;VDkqe$UKuwiv8>BYC`YnOa~=YzMNP3Kuwf-I_{6-%;?Kn;w% z4Yu{%c>#kP|8glDM@Zd9rt>7%1%Z1^jT;#=lnMu%Jj~mP6ekTdAK^;mXj#wcwbUtw3|`2|qgYas z_*6qejHX|4Bsp{t8krh@niL1QPpR@RDR=Z5tY z5~>p84Ygtq--Ub6A-2-fRejEJ5l5qlut;Vk9G&Kx3t2*kezqPR2*XxO7+JNGd0?Q% z9T>0ZnO`=jmPRln3lp5znQlV6PmiBQV&{@6wHdS8_z+J#)Z0^fHqDmb=@RtfvtR*(VN@Tut7l zLX;+_d4Z%h$zh))eF>z08-mzK;B3pSD~%u5$?+Y$B>Am`S)4=_BCe_qJfa{g-iS7L zzZP{CJ@8Ra;%|`CG&hFPY#?oMP+LL9S%duX&!V$pToUp}OFoM-I!!39K^bX|U+Mb@x^?W+g+(VYzVjUpzeGsn$?F#m{QGXZ& z8Ww_-=TmSFp_C5 zCm~kw?nNtU?e8>mSonMoi2|yGqw27%I3*!UcU0Rv8W;HwhsZtR#G@eqWFSnbNt){S zudYg}ty9?~p=tGTJu7YfjCZ60nmjuW_l?j$1*&+o61HD|?QXd6{>HnV{r5Ht#~3FG z?$Z$2nnCfRkd2TVo(jza9zA<((yzR8Pc+o zjYo$rtSK{pD)Mlwj5w0h)*=`5MW=u;RoHt;0G1>XL_Dbqs?&J$BDzo(`Zfh~2kl9_ ztw=SZ*4?UED_igOR)yR^u%el%=?<+BnAW7piJXny8q(fV(yHiLHB5RFKfMhMhQLT(vbgH^61dMWY{UmkO0N)$ba{@9kBPqiHwzv5r`Z&79*EVw>S9hhO5WRTgfI$Up=!piN-mRpwLf58qOOx z2?8}G+?`vFkZcK7Bq!`i5|YbpQTiJgSKQPct7=iW53|);6({EH1}M8$j@tme<;bs*2of&A=L0;lR%XdQ-|e# z+h+43-U6?VkTxL`26dDox;>%!0O6`W<^&K5EzICnlk-h*6t0qxG7gwv)NzQBr-+R^ zpe3Y|+tiALnOZxQ$z<5HT4*ofY-_m2?+1;qeY74Vvh5FA-J@j6?K~Fu(5O_21=3mj#F1@$uur>fQ3sf84Mg@4>?TU zXg_ZdNe>M~Mv2#)lzpv|`!YvZq_A64dzP9KTC)>K>)?jP|N2AD`RJ5~`n`XLtHKUb zlB1%Z9>G#9I42I6dj&^<7~J9EaoeeXaJ^i8c9=&|3=$?FX3&iv@Fl*xHN^RbIw8b< z8iQ+%2-^!Tb#av!@str68_2~GWTz!-io#GTjPw{2Jv$U9F(O1H(a@H8>CGg6*HuzN zlsa|Z@$XS?B{AP@f_=>1)h>9I)WmiJgsv>`&B(d;M~(2! z;a^c;;(tXVbfLezCnw}AFM8(L*JG25N2Uy2*i`@3dc2?^M2L3j&)gKh28cBy>otW!f(d8@1a+ zwbd6Ca|aL&i>5v+PHBVCH;J*uAQhcfL%KJbJG$pKP0O?LgtO%~oNiIIjZ;bx)A-@6 z2oVyHO*ktHXrB+3Igs>!N-d-KxoW}o$cZ^HpI{%Pxb)!2aHS1S;9I)%3p>g=jYy32 zOneAEW6%DfyRsbu2u!HM{GSe9rU^LdU>|!&$qxR zEYFT;6*y}ty879Fl*R30cHX6LQi@5dz2gVknp%#$2ju22DL%kO*;j|wZqr=`Ryqs- zM_Cf7JF?Z-VuZLZk`|8yMt#LwupfEhllI;HPSNtEiLQQ}DI@^+$ipmWN;4$%l`j zPi}`^3UuUu&4{U6B+T1t15DcO-JG;81)E~Yj^*u@4QlzLj3P+NGByUJIEjwpN1KGZ z7sgE)pGTWAAeRWboq`F@L)uPTustsss5r#t1B`H~tSfY3j>gcFccS(-8mnH48A$C7EPpt#3>B$Kx^=U0Pez&negRw!eqNOI$B zR018kFd2?<86EhJHQKd|ZsHY{Edl%H^R1O(t*7i^3}|acQb*475)bwUSyviG1Z~l?h2N z%{z*JHanCuRN~Wi4`~?dTFijKVZ_Vw*ocM4Kr*4L@|fWS5oRDtW%A~z&gV-0C0lax%nl2HP@t0 zhP}WwW9PktJrZRL5LV+D*j?N%zTHLKsA)HUdn~U5X;_hpJeocXP-?AWpIuZ@kiywW z)5m1^7%K5l05%BBZD*h_02w1vS7eH`Lt^#St6ne**Y8W`w0U;{nEnuAKL$9#?tL2o z^=h`5?$X^y6gJ2v?PQJSIQ?jbf8#F_Lw8&7+>KCkes#)xc)6c>c)4a94!t>3aS@n* zN{)w!3q+#I4#wpONNhm^$^^ar*Fi*bFcq5j=auz!0*>LO;v^rm_!C!UIFue(qO(1T z=$jlyl*?4@|Ly~2#{r}C*zvE1@y&wjbFik7r)vXO>vobEbzDCAZjWnn5SMk@rJZc6oyS1@fx2@NnENb-)j+W4g{ zsGF&sZ34G3jV^>o-n8?iR$j_l??pTIzf9dew=EXYg)I0ea{rc}Dpd|j*NZ3}5CR;t$=PWxFje=+1&+pfon{_?paO%-aXSi* zSm)Y~;d=XEY|oLS0oF?81HMVUX~d*aT^*i1HmI#1!jLQ?WrHJCkHg8By-yWLxh@3Gcw)hX@FW{@bDs%RxR zX>c#4DCMi_Fof)wgUu1+9DGUuk%V-AHiW?lHxK>TE``+**6`)g>!RM$f%(2D{RIAz-ZDq;-1{Fz{URF=^PU|($zNI67Q1^$J55`x z%_Cp#S8pJ_-7@Ka*ss39H|A1Sf4>wIu%vXkWnr)p%0)1K%)QV$Dg%`H2*o2@y#k&A z#2$RsBNtobkWFJZZ!aqT(MI6i!3F4Lkk+gR1E+aC`Mc=0aOfzgz44< z=MR3wGfUoI7K1VCEm-nR5ku1RB*q&ydbYB&#hq@PJd_%LI5E)3@Vng8T!JIm#0y9? zQ9D3_kEW`rf`K6l3Nj2la(f;|^-)~2Ewh$oqFEkf=OBUNS>tmAm-u39AX5SHlH~_>-2&OpNmt)6453&`V$<6ExUQYPtwc` zj(+^df2uMAjjd*vTWDi@tI)NBfSaA0UR0daCiho=WBYE>oLWkZn|k(nfeP+rR|gZJ zgUS4)CDuRP>72*%gBMW>;tSfT{%!#LolXlsIwHz?p?$}e`_Y>VQ`+yEf$N$eYL0Fg zw`iI5%=cVvcxfAXJ=z{cp(#t(@0E{xQI&p1dZKyD_vl8?h(Bi#<)+3_L!qTnS$u-s zIPu_ra}u{Tqcg~4z_UrK^Ir5JgGML*dsW9sZZ)z=um&lxYxkmy9KB;;jNe=G6DZRG z2nn)}EI7|B3uLyK(jJ5_S?Q&5QFvyoi>xpYEE_2w_sG|xQrY!U^~jr^)3iPtAJeSZ zIoe1*_mj~u$v0}y$`6w?-w+;8_Olq=MmuYNdRHLGOKA)KDX^xaab3YM!D*!Ci5VP4 zEAPv(+4w%ms$kV#o*B8r)M$|bksv?hynOSIZDMR^Qw7aaIeDy@Nq|Tp3weT*fNmVI z0Bu=?JZzkMRsma3)s+0aMi=gw+vN{K%9w7be&vZ2xzE zA1W1UW<&yNZan6w_VGoDZinZU@>ra|5?;7WCe@79azd1X(+VJa_Uv>~34yc_oc#>! zKLXG8JS&N{iKi!y7)`7A&)qkpqZ}fbBcJwxmmWt}ss5lD0>4gJZ?QpJO(L+X>)txJ znt1KH27GUkY6Mzz=PblbCEQFCC$4*cFWfnN-Q(D$?$ESfD|l(LecNQ5jJ+2KN&N!NR$%zy?6 z2@hfDk;BYe^=$f;pqS4K5`9bZ8dJOfYAZy-0Y=CnEHF6XY;wyH60%%7O<4_p>Uvvd zs=)_W_0J3r8)tnJ4O0TQtTNA{{ZUb4uC*aClZ8Tr|9G1~UNtJ}_+nTAvqdY&Lfu{0 ziy~XV6TUg2;YRc*PO5W*_d6CCVx{i0EK~Crp(VEJ@eP-SIuz=)v4C%xR zLoiMrodBGO>v8%e5%q@ya40B$EEnECHR9Af1OHnxUlg{o7+GP8$wyxn&c+c9Pd?CFSzni(>1AokA6Jt!{oMZZmtIQ+bxFrA4HeBnG2 zU96>{a=dWSQn#Ic2U|?=r7!Hf@*zdH4<9&E(^x&H4SmotWS)TeZB7oG$M)K@A`PqR z^3f}JCu&Co%Syf{*`$JhAI!Ed)7%{V)9&8eH}BqWy?*~^{F|6bz;|B(fiZEoEKjmP z8t`g)Y}*pa@p3J@`yWADC%H4?KEc%h=3(M_B+0X8MUWTxpV$XOR-tb@cOSI3X`h#9YkV)CLH@`%$V7u{&#C-ak%d|g~0N$g`&3|r0w4_V>z&zPLy(6&#+o}CD zKg~?DS5DF3OSC^svdn}heNlD=;esL9@>Uvrls(2^*ayF2n+jm8(b=T3_LYJ)qA$_5 z#>gcnBbn_m>?CjNst*6N!0Lzza04|HFb$>lnGov8H|2+lMIwC#Itbg!qw2T}ZH zT$9;(_+Z+1gv*NGD)f3hh(UFjuOA+Ew-Lqk<=?D4R5JK~zr1{0{pI56!(QY*+To8@ zqxh9LPxKR$RQ0&RH!ltT>oLCZo`$>vdg$or$QoU|^L&g2{xoAdt-J%1;SdS2K_lo2 z@_|@iTMrKbf$?6kxWpz&3m{%t?HR=sXcJT&n-b6axJLs?RBOqoYIxTmG}l$_g6H(@ zHxe0uH(Q#2Gsu%)m}q%x6_mDnyMb~Mjn!U93za%`NB_OdC;W}DM)7jCsmF)aAs z@S1TK45`FG`VywJ!>vfcou|b#6DLKcoT^M6#UCp3Ru&({$Br5?gN`YcCFUY9;^Ymn zxx4m%GD%3u@^5EY=eO*@Qz<{)@Y{*09jCkHL4s{=fR(pezf!K*RmZ!NO}dAVVr3Mr z!a%(>rmT+OJK1;`B@@Q=Sy58OJ=TUC9~$`UTx2uOoKV9laa$+2{)b6jrk~V}vi|$* z<4KErm}?>2{p@2=S-QKy#qK(a{jBotpb~0-D|ew$r!DEkF^o%uV{95Pyh(_s6D-6w zghZ^(BAJQDvEaRjK;2phPN&euf(1M!gT=!^r=1S~YH)oi%W7Ess#p^U-do7K zjcPJ#!DFVBvPz%lpN8LiTTYfO@=f`W=ojT6c<}B^pXN|hDXl^j|EMlQ$#?~zSaocF z4*q4ysSUlkusR=c0%Gvukho)!1kO+8US!T2z{zAT+M!krQQm#5wGAZFWQ66OwV_aZ z4^un0q$_Uer6D->*9cse33)$XCDvLMemPA*q~e7@2L<_{l$f{I4yVF2 z2B0NmO@<@7;yGi4Tct@QV}&^-3@Ma&+UaT|i6ROS&-@$nAdA@=^X zIt%K!Zd<*@^6P__chIWhi**XznEi%^8D4Rs)Q$HKSb>dWXNcRko z2Ena`h)WGr=0fF~DFv3dNmg5As)0^|twLJ_xx=sP;nW)d$#MyA#?v%n{w?riHCSqYmO{ERWso{( z$jDv@s8)2Zz($10i8W~Qx)f0^n9XC>N`Lw!x|*FhMq{t+|5cPle-K40P9VsVVMiN5H){lEOwAwGn9Qo7-RSp}Z0CGT$zXj-uu3?mlvbM+ruUU6Bi~qpiqmte( zO`TF;FMNGs+79Wtxg2g>5yWRmh7&pS9VNlEO4Fg@XM%LMKxYno*0U+}f7}Zs5ena& zwv&^Wms}(Q4+M2(6S}~;Nv%8=7nsO;RD`Ljli|qi2O$h=oO4buz!7akX>D(PPp^dq z{6r3gNgIssXCAmJ#4w<6{b2&d#l^5$Kgg!W0ICf1f=yi`tygOTjjXsekt-A1iCo$; zhPE1o0TQ88*Uyr4sL=@Ge{^ibp*fb_@h6)bWCl|k{8iW2!@m1Ol|xFVDy+t1Pf=J6 z#~JS4>%pV#OWd{dDmZg3#cc?tvCtUlrQvw3w33M0SVzbL%Yj|k?!-S6HZqFZUSH5s zD-%|cpt?8Tr_(JmV%1gNej02cHyMd3AW&$_ScWfxAW$^{vqUITf1!ubtsxW!Q$u1E z-to4K6Bf(*+?Y|DCy0|;^w#jKG=yR;qOY|G3A5kaN;KTdjh&PRUZ9;)t=x-}iz21G zh>%2jK71^ar|QbP7_299*XCUU%ZQc(_-TE9br*77bZA+^+FqqDfxD#&H!uQ1P67wD z@rk$S<=pK-kJeL_e|-tPR@7_W7f_#1Lc*`UfRbApyzN)JV)oDwFHnS^G_y+)ntah2Q|l6;1_e&F`UFBO=w`12pwF%-MP>T1zg2E*w;@LqRU^n?Ys$Pf zd6EOEJW5gyB8Y8=hg*?8z`;ARO7|r0Lpeu^OZpKoEk@wte>aNY$ok|e7tgS_5S)o7f;4&nudr@7Sa@7g#+taM5DpcPMA-_cR zoD?e@Y3-MEe~FD)nJpIMRRV6}awV9IM^Pi6aHcSnAyoR$o*XRE+2k}efMJvSC^Zy#m6u@xhRfXRB;iDtyGQ#%Ngs3SdU2ces)ncR+HLt6MVgG` zLP8sE`?~%2&h5V`G*7czJj@9lDv5ihRyUtS%OgwkfAb0!;6MY#EoCiXk#tuGvdT84 zuM5C2tn z7ww_$8l^G?t;mM5cogNvuc9yFOT6VjM%(s}(HFd6wP6Wiih(I}clKWUxgtv4HcqlM zAAj=tek36xQ#(h{2cH=U5BvVj_J@6{p%^9|PtZNvZf!OM>NqQo zLkJWr+D=49c7w}t<1PMl3m*blf-Vsl>tt+U$dSa(fBg6V=;$HAjAMNY+gY(ZjGncu zuD=*(=UcD-w7^~;kF)b6`@HZD2mf3@PWxtre;#*ye8chW-SPX)iBh`lv~bCyZ-m0e zRP5A3-=YcVTTIt4hV%@kgkMm9r-21;+hc%iT$kC`yM3R5Pop7zVRCbl))sOsB=-v% z>SJ!bY_xvO?zeEG=-Lly{oC=eU$Ajiho+tX*9EO6gNw8(N^}Ai2Ff_%E&i-y81JlG zf3!Z(scE(19X)A~YR=OGz9(b6!+Bc!ORMZ}{B2Cu{>JX>mplK<`fxxuDRWjry7@c> zzzBJ8P(FRS%82OQ@?yWT+KMMl|2HPKyT)2|hKEdXRHmnAb(MbBl1r`fiW^|5 zvj#sD=mto=`g%sxbzcXb{Bcp7^LrJZf3P-QYP+C>wfivA@6R%*6en`)PFA{e8l&c7 zue87TxVh;TxbO**efnc0f7CZ{zvc(U z@}%aH_r9m_^6oEo%~2Qo>x{26LI;lOBFC{^wuk|`vhefTXViRzGaM99A5?>He?pio zU=jYNx~US-K&K@{ZQ)eyE;^_Gmi=rI<2b;Gd?Nr(2ymIxq~1{#WGPg}TJRb3uEe|V z|2O=NWHjn}vC$~nmp8#7L?pV~kPoX!{>CXJtHIsAL1vgQ3paD_Y8Z=ZSXA-gcq1>Wzh#OjZI}lQ zCTofw^@)ja1CeWRs+9qaI3fO#Lhc*F3RiPl6TM~LFw*Q_;f!vGLz&XFTPEO-A zKZC3b&IF9k`vh!^_M>P7Q3s^6zRbJX7ur!Dg*vX&OuSr~WpvmFk$T@~%kSwZ??avRllPc~w3qWSQ8ETS(CVb{((BSft1WQ~hV0^oKF(e=X@=v>oO@-u+4t znF2=P#{lJ5>gI`qF)Gs>vNstG`P!O)ms1r&QLe2qoWHRiGIN^rC(G)xTsMvsC9prx zSCMYoY1X2Ajcx|Ek>@#geeSBZZXW$x!1>B6E|!%1vc`wux3Nj$WWdF>{CqYPsN`Ji zg}a@%Y5n?!WGOJbfBePRD4J^R6<9Eeo|>ZcYm-zaHGth30jaGxg-YyIxTDqUy|;`fK&bLhR@q703MRb!^xN zr7hj*ahhKgDce)>pB77O4w!;{4QdLEtf9BSPJp@R}Mi%M-iS>si zQG|k)5LKv(qp$X)?%HEep!$1hkS<`=Vl+9VW-?~)$kL>uGQF_SfdDwP>H5l$GUR1-!?Fk+FR ze8Jw<_BJ0+s4KbCYiVq?w_v-{DxGS=t?X>A-mOvUfAtP`y6v6~sYcssYny{OL3*nZM;|17j-M^Jyse`gl|G(T^=h`@8%RwxK- zeeGSlWXCZ8wwO<(tZo!EJyU9>i30fFBzI990Dg=XwLeC5y+#j)d?k@Nd4x zo0Er%MBzBVGJQjQ5UttetbQ=ZU!l+Z4>O2Cq=pc0JQ|n%Gn8I*fTo(^%YTkusBz&r zt4++*^|#}VF^3Bo6AIjF;GIIEQ?{lVM7uISLg?*#C@N0@6zksM^yXXAXrpzc&&jutlU;nK-iNk0y zU60jl;aQdGgm7e}Qa}n6kfr07xy!Mgm#EHm)?>w6)>sKFnsD542M*=tNWN>L(7zsJ zrnl5d=ZiLIu}VM`?q6g~faQ~6wJzY7a-$X}{#`=6gx@%vM#OW&3+#* zsP0Kw+Fo)G`^GbY-Ps{d2Wc}{e+s2LTT0b8BOvREMSdVChIqAW#E0=~+VQFT^$>(Ko%(m&p>McDmj;ir-? z=OEMl?|t(cpP$iqS+_Z5sQJGcmu-1#7yZB`lJOCWtF5jjRNXUEDp#I0OUp~k`LcoF ze37?KCp#WwWXnr4A32YPe;!nE-?vfd-7o@i zo#TF~BmIqJWUIJ1iMzh(isgL494Rp97sKO}Bu;`HH$@%oj}$R7bMh8IL~_j+M=4T_ zo=$yjjx+&@K8Xldp#0T#7)B-DrJmgNn{g0%=KFR3^~w5QM?v_QaQLj{*QpF*Nh|BK zv}CmsIhqDtLE2qOlGKU2h_s4&yU0k{ur{FDhHNWBq}y*l z^rE2|7UiU;F`-_Rn;PrS^R1jH8}bAo;?Mh&r4qc|d;~oBd=ls8GSVZea~>TVZb z6~Uk5Nd&+Se}Rq6rx869)O%(0*J51eW&(v`#4fmMKDsEf@ldI^HPG3IZs}QakveAM zdptOKtP&%^5bZL@Kh&_3^MKLdGR+6YWn&<4C&)1Li@ZNB%e!A2e)L7uIN8|5$C*>; zT->pFC-3l0|Ewrb*aiZ@QHd&r*xhGzD|;F4JHFAXe+0M_4xfBOQKSAOrY%HcnN|h+ zE}U#lt4W-j^z`hQs4pwa4!JmvpM|`T9+%zQrPX~ zUp7m1KK59_1*f3s?)~%e^?AXk_YOJ4jbxNIVfkK-QL`?rJ9Dy(vXQEuWQJj_8{q`f zUsy+{qc8I+*Ua6Kn+iEOpo5C~-3#d7H4p4XMaQoXq`Ee)ZwXn}MT%-+Jv4>AT0p!1 ze^P7Xwi9-nX=ue)#cSU1@G2)snn`@}=*@*GaZA)CXg&v9_FJL`Kj*o+5Y?_}%ktVP zUGp_GMV0G4yDdKr!|~Eqmn>J=Da-ZPljXXi$-{hi|08t10anPM*M)nfyXwCw^C&9c zqEXL!4qCNFvTSz6LTos#rO>MU;TOX$XXf>+=pKQD62L{JP+qnne+T>CzW+e;a^g zLJzc3oz&o~JAO~}oJ%t#UUy>39txDE6IwV5F1NTvc{xa0+Sn<7Ydv~TtS(fC?6@<4 z2OigFMVWqv@Hc9zu|jmPMr8r@I$Baqjxx*+iTxJk=q#bEFfB}0U(GMl8fF&u4I;F} ziG1K@scWy?@!*RpD$^nPCjz6Bf1$3bvVV}Ll^rXJt0`VkKngU9#EFDSDVXh%mZA;_ zZPI`{JWEeRBi%dT;%IH{jnzVi3?OSyn&==n6Pxs!3mCX7IX+2l*4Fhk>lA_HX8HEu z!1d2a9bH@~Ws$8%+sTNse3k)@$9?4uc47}c7VFd&Wv@%?g8EvNOmyX5e@Ut*ESM`o z+Bhj|)woB8&PDJT;*PXj*Vb6E9{szh)}=nM$T0<^Q0+9GOH-$%p<_Ku(xJx8yfc?i zlCyL~hf}wlczVL;y=TlhIr+QLiH$BXE|7;W##J_9PCg|0UutP&tIs&BNGpRRy5$y9 z6SRjhOD6cC$fS?T0nnY(sD3`99 z&ni#K`_XBw+gO#)I7bpGfm~0I_(1SJpNjc?` zp>g0?G-u5gfe{sXRM6-mWs<6`vd=Pf-AA9Lm!n~)!x!e;-JFC(m*NkfJr`-?6f_)t zj9Na1#|C*5o&tGeLn_U7Sd}#Uo~&?EIzu7_M#MPdnG|b6PH!3l5o)I@{Zs$cYb;y=K?OK|_#F>ya=J*&&5pV7W{ZAOdJd+)WU?uN}g zwi{eu@01(yzt|j(Src^a#$8kUehg)v_ND|~x?A7#l6vzrf8L!03>VxV6p>`jpKz%) zViH#^FZGQmW8ATt*4NuqtqYr{nJs(6IK!8{vh8MQzWIZ$7ntWIZuBs3;dN2~E46Dx zL`SRBpE>(M`j9Rn%_|42NvgTj0lVs93mdTM57Gy47458(b;{Q2I7|KH){OJCI|tTo zck6fi4({m!e_8F8lk>_#&So|E+NI$IciV1jR;oTcl1P)5k!j8RamU%z3iMxfMET{- zQzm6fo7%z;cF5S4v^Htjy_xCdt9rTD&2iE0@LW&nSW~m+eP&#~-6q6)nLSiea_ttU zD6%f*=%1r;Z}K|jkLPK)QyqNPLuQDq&;PvXLh4gYe~>9kBGIBbpVqB+H1jbp#@YGSt3O@y369*Xy;U^3!MIzS-)OdbMIvi4 z+vXY%X}^HW({?xBmB;OFQIa?|sM$HrQxZ>8R;FZ!yW8?|#|!g6JI|jR_@i^QGcCJD zXYfzme+jJlv^TCqA*zc}+OL9i+M}m_KCRivVa_2HM4u8s4r`MSIJEk(ia_vx!IdM5 zfFdt{cmJcaFPzV;F&w^teP0@BS&7|1CfgZiNZ7{mfA&B4U-->I_hJ6$mCmCYFdK29 z&LDSb1~wF%WRohj36n>goB!M_di5SR<5<@xe@{QO(TS_#mR__dj2GH^UGC1bqyEn; zQx0-GTwT;~2>2`d>}r@~8Hi`CFG(XnvquP>&?dXp^i97)crd445O|rLPf#AHLu%qC z?JQ9ub^?p26H~5~Kd*FO75m(%&3=;g#~E^>>!Zod7o%$i4?=bo*7Z-ygO$Dntj1C@kAr_6uY zljm%mA%G(+@`{~h#7;z?=i2nB_ae4 zgInGiCTZrqC))WaG&fab=&w{nSu1?UjRCjt2k6G6C*J31<1LU5=8_>&#zCf%K5(F| zMz)KrDC2$slR7I-0jfeP@6(~F>SQokX^t~u6ZtQ!) zOdu$aHulfc5wCr`g+J#+4V^C>^1K*Z3=rFA~0y z`|aoX>&;v9Joa|2e-LH>z7E%42L8^T1>DQXKyyK07)(a+Mc2-blQh$jlZ2e^S`f#Cj-A{Dv4IqrY=Z z<=elk<9jd7NecW$kyHO;^S9{mf%llh2T@#fBK3~(S&)$1Se|GBx>1q^zI6j9S*XWt5}Hut_J4F=8d5rM^nSqR(U zgsZZFI_JnNLKqZV%b3@59b>g;#k480ebH zCWra@;o%hHDms!hR%6{nzgana0ILNn?l%PD$|o><4u`@L(P-MfHB!U35H3LalTdC zy=$<`aUJXC4$Y_kCL_d_gZ_)otYEnIw8F(+e+S*R%RXWa&Z@J8F^#+9rYDWf$+$Bo zMzEuC@c7?5Nht+A;~P}f+&ZQB8&?b|)$?AlCH>n*;L!NPqxHu9-gHA?gdsu}9CO6Z z!Y(MK9MD>N45RSz`V@a=8;IV9Gec`Q%YxZ_f(D#H(`RxZY2*i@5Mul_*)!HltPb;^ zf8m$g?Te5c2qJ&;4w`B_BuijroKskkm)`1O{uHgeR~I<+r+5hQ-n3SD$k&epulX?l z7aCIbifm58b)p*6aBWDX9ozF>&vswRgyFb|DDumHH3N3)O~a9Yrruka9ca4eYinev zVBh;|9g74%m(QYs0eJ_1pTezv`3C%cf8S;G?I_r8?qWk>L$F6F7%_&yhPVSe6{GQS zmi8s=z})dAksXaQ^Gw$6ak;@?dxp@$Mi7UvuNdJ#Q8*Ie>>5- zp@uqlo)jQ>P7%KQTXfb03tX00g&K!GLbEWeXiVOF)e|x(auxX_dmRdcV8YpfaQ$iI_&q$v>Ii}gdMxK zBgsRum*(kkJhVsLv#8tWEpXcU_Nc!~@&bqJI3IMrFT18$<{jK~`KRC05{}=KL)&ss z(ee(LiG{X(CG|do&Su+I$s8lu^oWDoO;`Smx%T$SS&FRDq^oaUn;hJbf4;rkdHd?k zANO`%zmH#U?d?qKu;IfH8s^bUs`*ng1_euSF5_uLq z{65Xh+oV1V{)P{pMGwDS*`HLk8Lq!HC&@Ug0Vz-O)0d*7K3UzEVkQQSZI!27IsGj9 zm6~?V_5JNi_<;rJcAD4Ut~5SfJ$&GP(Pa#NyVCk}Rn17XugMO8DY0~) zMGs#QQI`DsVX)~W^|VDpUNxrON1=stiU-0Hc*YO)7+-#KK_E4lL^9iHjupkj`%L#) z6kTn%cY8eF{{8PLqE-}=*scRPRC|L|ge``zx__q%Ui|7G`O^l$&>{E_L?^7p@k z!M|GHdbRWJ{a@bge{Ao*-Q9WpexH7Bt@Y`Xq`!at=Kb#XyW3mz^qsw}-B;}n1Wr+V z+TQNlxjKBntY)F%FUe;vWx{6%AK`VwBv4C8%A9`u_y3qTd3c-^$6*FFFp8^b`$gl= z?@$7bl)Zy##dG6IVjsre5pqB1FwhtFVjXRxM`7-)@s?V*e`wFnI65GEJ!x9qw=d-* zjdt5h+wiJ;=nN;JTGaDNHlCCVV#Ii=)#YWDErMq;IprzM&CVt}V9|Vem$OhF7^2tf47G}A^HUz-rDTm=j@{U(nSI`&t zy;2JP%GA+Cf0_VQk){2#_OinSUP%Tj8hpeJY|-zJ!ttq-(_WOBnzDFY(9EF#KjGd_ z%5viW6}T1rK!jUtgt8ce_Trx)sYVfEksFWzv$BprY)~9 zYprSCYXpSnNHNdIFkdfAd=(JTPY%mh!%a6mIqY~ZqJ#(rno~{N->-AII-%S~YRCrE z_YU?LsAh^XttXA(2=;1rA>o?i;1^Wko`Ty1XPJ#69>uzN?e1J#i+=paf4Xf8ycDnz z=Z0t)fBFW@)EYIsV(UsNo-T#50$rEdh-#9nk5gNMl+_H@DHB-ws%q&w@`AgJ!zGuPCcWtQ#V=ptjUNG2e-h;g+0nMLIsSYw zf3-OzYC0Q>CI~VLbP|sYXBXkKHd=tTr6n?=dBqF1xpizlJuR!+-fz_2E+Izf4^wWh z=qJ&a=&7C8ebX=UL02REmszd+{HdKwNY8XNLVuXm#xHG8zPI;o=PS8enQoP^l}DSK zHvk!+*(9sXJTQX>cB}DAPL75@ReL~|i2;ys7QUz&hzLZJAUDURAd@)8_aSk=POz#p#?~)F0ZwMl{63?dNrJS_KpK z9eV9e?CWVh+F||zp((QOdJQuPe z!npLtiH0JGsUTG0mgu@Z%KJ%Orl+T-WVc&9XQ_}u&5gKSZbYBczdgU&e_h_v6vziz z{S+2HBCFIKvTv#xM0kEw^rW_qbxJPy+R4Q0B@zQTE_omXqJ6l-dBTTN{gvR5RSP^r z{AVJVl!g~efPs zV39T9395pcHRWa@AAc}re~CC{gKOp8XXL5h-8kDG#ZsaEa8is*p;L;}!NaeRCy-#o zM(eVhJ2fy*31!SBlrkCKEj+cT&40@Lg|r$dx>ha0mAL`FB((5TdF>Vzo3G&krAZbi z{b4MWfATEO63h(aqU?D7o@hd(a*JcV-)?lNrDra6w5SY0cY9Z*e+WDxj(KtfKkv#B zcx@c!E(_Kw{=f~~UXt_H58JA3-L4u&G)?BtD&NP&x(z<_z zvfKPL0x?0mKD=k4S<%@zACzW5EXyzyt0c!iP8#p1vU7Ddp*l3W6!=kU4n{we$>^*d z79XTlAKQ<)22*&Ke_UEKWpL_(%9UvVQ^{~VtfIe-(F8~6uS^o`HD`ls$pl2`AmlP; zXQ?S6x;23%R!EF^ZLRbDyjU^X+R=fT^3pDu(0*0?ek%|}rfJcUeON`0dYhY@LZ->@ z&h5RG8Uw0p(nm=mB#Y}5ys27-VDXdkQzs@E@HgPsu40U)fAIu%QpquQpTP{x>?bD% z`p$kmn&uy9c9VXeio;2G!tSw4xW+aEF-H!ewLimh%PQAeUHmk2$G8Q)3SkByRwBi+jO?kq){*r%q z`w}&4Q3=TEfBnwut=I1fvKB<>TSsdcrFWD50~0rN8onNIFlf9n9NP50!FdpGeU_K~ zJ)J&>57e{7Jq1ON62b0E*y2?1AAR>-^w8bXmN++bL1CP;bN(oVncQ_z8jpW7X~645 z2#U21Z8fa!Y7Ba3)}b|TQsm_|b5-dY?eV*KasC@OG*DRpy+$xL=EO zu>;tyf4b_ZS~U4ZS{8(e?;J$U-Rk#S$7z#nBo@qF4(v-{BZ?8d!|VYb zn2V13uGwRZ-&|Fa_15#M2!7lwP?^WyV6(f^KRmn>ogb29r~`;eYJfD_9#eUfaQJYB@;wH9}>a|#uC?5VUho~xb$BWUfeVz zSLAV|iD-pqz>(;ZJGAn(qt-coCd9JcRv2gnqRWClDHIS>Y;7eKEXoKG8NAq(;zAmcL%!%EVT_jDxH+EM;B1S62(x1^hp@_KCl^I+we^`;`<7?n5La zuhW24#V;9zzm7%N25eei7c_vlthItre<~E&1)g3%NFB63n&%*s*v!CrzDleDXQ1gk z(=O|n5O~qec)$w`W>lr033m5=`iWIv_@oJE4{|Xa`&i-giB2F2GR`q(a7aUhQynD{ zZE`Ec0!5j+=Hfnr6!N7_Q7R$elJ|>__-Z@yq)G&efR{Tni9HK;Sj;#~-{QGSf9Dob zB6{BkBB$xkw4E7sVt@^b{?|v*FwH?bE}!v-oARmH_B^`uhsIx?>R)~lofTvFbl0kV zwAj3vWslCG;yT8lK(TeXYbwSSCVD5UE6CGo_fs(Vi(oYaLLRBhJrc7%;rvLFPzV?2w zm0q41*Vx`O5=}74?n7|F73@i*2f4T;Q_f}#hsJp@IYMfiwF5p)aK`ltT{GMQlwqr; z=iKBT#!VSm%6ci@ID#ZwZ_e7-jw0CCMN7AC+7hRU=L35{rEe%2{+2)Ze{NxuOcjX3 zQ!b=Mvm1gpFRKlgdUDHL)T!)>mtxz!AJ9@ z2>?witP4byp0OCJcYJaJf3RXUSFord%mw zg`tP}w~B@ME<&E(Hu*lO&fm+Q;y)O3o=u|oWiqMWoZw$Ttqzh&6mQkh<79Z4e=976 z9nEloVifOuGJRaMhYwtT*3BmajxVj26e!~h_#Dmt^9BU~K za}{dh)uDzZctDr}H{Hfs_oB)xQzRR*979k7mT4E#dTN0y%eWFXBTy0ZP$XXgU9qEU zS)6Aq42x^Ie{tz-JK%a?1xr6)I7K6@Bg1j{vWmHMi zC@`Ht`tQMuT4k%PFV}^xSVscR5uXzPmmN^Hijot61Wr;wWVq_f8_gY;XtG$Armzje zKSX7n^|kGOp#?{5HjBZqRM!Qu+!Y{Y$*7aBRUkSOf2+|xZVHKBG=Y3wWu0HSPPBRK z;oPc7e1Z=sE}Z$F3ex|nApM^T(yvxQ>YxvET7*~PnLJ~8ZqUb#>p11q=}fJDt)4Ep zbaUQ*cEXXaRcd;3`sT%tYgb2mbCD}|;CtNAO!3D0OnD!c27b*sx$;$mLpl2SrYock zkJ{)Le@|V^E;v7IPRs~=h%nS~e%;@I*9}qz|h(Pl4 zM6%3d(s<+BxWBi^VPju4y4p-@HxkD#`LRem!%P5bS1Nk`df@*a#lL~6FlPnuEDhIK zf5d^q)1g%cd_A^NDkYv)yQN9-`(M_3*D0d^CRM~&$zk6zm2QL^VEL_5(B5Z+RB4N-wJdVI7$PB-tc6n%2uM09}zQo#L>e+frG^9 zhj*oXBzlwNgJPI|7Gee!BtJIwr7^kfe=T=#4&9k{Qt1S6D7BgJT_0l`0yV zBzFTq0_cwr7zj?Et!S8@o*`F25z0hu3xlMlP4IL)o7p3#wE9B2VEGy^Op?(nSN5f= zUUYeu_RnB;_REx|Y4JX!h|^GJFZ*XH5}|~?bTM_nEw~TOv7ep?dK*Z>H;R0@f1g5n z()HF>mszzWx7#}M@`BEqJ1Z__N~xPxUR<%NweFO1PaXw0MPj$ z$@`REW4jRzgcIGC8$~E}I1)w^f1y4N4P$B|F7+Dh(q#aU*A6}5&in<}wImw1X&h}Q zqoj{>rZf=u7Jo#CK_ zUWX4*qBAh%+TnwLyDxmB)8!@`GCvGp$dhdH865%%)HKQ?jYhvA7Zeb}e};VI{zsd^ zO*129#kgAE8jwZxtBbkHYRB}qc;2|~9Jl#Z?1g+2`bU&(w;Mij3b`HOA8jz^bes+z z_M(S_(*4t6+uR^aH1Xv-JY>sWRQ>9r;a-u1Tmu0?N189G+i@yDt3~wpI>S)AFRR1+ zTl^KT(<$B3+%UoRK=0!BhR-$`)OF{#hKzGV`?GsioL z#t^rn20QW0TtS$<@HK;f(jlqxti4xk$l>jJYQwbt!Qqy9%1?XAe{p|6pVBvfxtSct z{ed|NzvMS=9y1=kK8jK&G}4oa(dSB zIO+mE!YBSSIr1Nj?hW4b)=z!>Ro?Z+B-2e?}w@gae_Q2VdG14FfT* zL_@QEMB$0@{_2ST`0xJ_g%0lH*01dboa^^b`1js|o9ky3f$_o+4%|=|(cuI6&I7$m zIWiDlq)Z&bzBrc0h_qB}G~4~OG-h_JqUwPuR(LKOUgT+!WHxO@mHL-OnK7T5t{k1Y z-Mn9vh|xofe^KIlY>s6~DkX3ZmGLJV8)@S+zJsA*I+x0i|JVQ4$Z8}MwBjHN*lH)% zzYZTA*mGO@{O{b%ymU`_-1z#7*Pya;5$m2S696UIt~%u&qf10)#=6If%Z!MI>Gl%=tqZ zaQUWLo2wCE8VWmFHuV(P>$s59;8+h}gqckf#uG=o^c-z&iUvCk1D=1IPsEVY_wn6YPG;E&1y{;M zBqq@Xq9KRFIz@E8j=4&-PST$cqr25c_n`kbR#UMj+Fyy)R7At6Pz~|o)6aMJg!#BB ze}3kTz(0vS{l)9mwAE_7K8mN;XPwSbnt}9P>r)YltqrdM{MJ;_f6M5)VSShTWWVAl zycVricW6YoxCfyw2tdow(0_B58n3@)XIv7H$_?yYU6MOu0i&pG@Iu93ZX8Z zkS|Y+)3-U2?Zf1Bd1LMbbdsLZBr@E9Ey5!V#xcE0ZdFsw zKy%a($RUsWzFlJVC(C3Y_T+G*C&gPi&)WQ@;@`hbGY^9z{qLT;Wdt9T?PyZM(JJ*Z zQ3e^e2i0s%3%kUHw?qWb(CT^17Do9|6_b-RkGIpjzvZv_7jG)v zoOJRcL&_ocY6k!ZNOYzMBvgsgq+ zURAqwnFEle&~xcN&EI9i9MQzs5wyP~K_yF9Q?)IoM3$kZ>?c+~fB)hRXoM=nvIP#` zdd~LRe1LnSH=B?tk9Q%!t=po}*0ISlDMC|GdsQU1{9CwTR?nf(4xtShlaZ@S_`zDs zxyKz*LVCz4IuzRoHnCTe)TQ(4lPb{Af5{nG*e)HDVe`b64fHpJSy1pnGzYX+R# z`Wn{qlnUxz1}pH19k+Dq(tq;?wISBBd@{XGW-v(1BPKVxxL5z0quA5X$b(*_OFOXd zcy@S&Fsu*<=7okWJKeXK+c}>E02syWa!Z3RirMA12fYXrfAYD+5-UP-#mVe)9)5$| zKP=LFiXgEq>r!22uGJoDd%Z$y2hV z!zeDrrwv-0V<6|UDgR+Te3DO+;#Hykb&4#wUkC>DTiTazT`h}D9h^v3-?}UOzwHe-0(3b9zz?ue{GGu7cz*EgPe)=vf6$dDO%d_1 zH&dBesRJ@Ww8j#$D8>(cmV_7oe4WUWi3!PU@LF;EfAP?@uQaeGo3v{r#=z!i)O#Ia z7qAgDDB?0I5}015R5nP{aJyvwlAjusG6zW#566!PI;)_o87e3~kz)7TC&#aB^NsZ? zaa;mgPy%v#ljm3#(W-M?KFLQTC#miFx}}T0m0BhF*w)uWDR0SvDBr75Oj(~)8nmtM z+DX>mf2A4JNtw3SZ1|R4pjRFtsz+c)zA3zTxSy1ow-+OiCD7=!`{Uu91ij@7n#%{v zk!B@xjrQuJkSVXp;mq?rlHPPR|8Ilx^4qo`JN}rq#dax$CzM zc4ujD`Mjd7wgXyv!d){}$@T485VYu0nRsY!e{Or8qEd2uN=L&>wH@74E3kna=#wNa z5^*(&5qXcOP{W)EJOqcD3Ns--b|Wr~gl(si-#(c8IM$4CyB0b z@GE$`{Ij@-i>t;%ro3I%A%E~i9mQj9g)UiBKA(###ui0p{?Nvvwf19b&ClGODA$a6bvT_K3jSy2o3T_n0RGtAj zRAWn)N(9yLi9RfuEk8>mx}AC=q3Yz*Ml^|7sFvvtc~pi;m`i3Z~O2e>rF6 zAnqlipC<)orq5T(hV&+axAc<)(WPltAUIPcs6YlX>-rG=q?bb8neQ0@eL#Z0+dn>x zhEOwPN7W1}d7AE45+UvB;Q=6L1i3P)#(^A$l)8t>d-{Et=Wj0K-W!>gjq+cr7?1}W zVy8_>+3vSRA35Rkfw)c!1cZZWko8ig=zmmBN%SI}auS(jG9r3#Rl$R{6;bZAw}sf@ zf7#0}Z@9-Cd@l204yc>N%Se_-`6O~l+CoG=5i(>Qq6UduG-C_7uny#O($dL85t>V^ zCF(UW}vPH_IEia|Djq(iU8Y;-=$eUXMgt^ z?*V*`EzZ47lVQK04FIlknSvurgn;M8y-l!;8H5gJuzrOqHR$eKeA4uoa z7i!M^E;3`V_hOmC{h<4P&}q&X?Oe*M2>(nj9~c z?C`QMI&1*9xK)prTtk_5`aH|?H-C@g-kW3MU@o2S4Yy(j=X$)J#l`disy}G=Rx%lR zt|RxncEs`44^&rh=Lcj0#Q)bm9cwtcq7lO{18B=`=BA2TsPdp%D$w+{lO`J~dm_8G zdFkvh)2L%|awim?da3nC;zG~Zg;0De5ku7TdZ4ceeJ{}4JMG}>JMD`1?|+Bizh8Qv zJBt-_yLi0y1HP8GjmK~KjU9Spr{aydZaY`K)p|-re5Y)tlC@j2r&aZ8fltR!I=ijA za*NI6x*~{U3Z{g5y$43=z#UIN-lx;K-JyAPRu+;%=;ZkOQ{s|{}~E!-c?d6Rv= zYO;6y$v${bNM%)Dk<|FQqxEv8D!`EJ-iybS9z$8jS7mk5J@Fgddc3Yy;XLj&OgHbu zzn#2z>Xm3V~q8#u2iF$zf7n8Hv!3Rq<4sG!iu|xy@Ye((q$$CV#5~8V|`qSx81k zrk>_i#4}RGD#m$MFefl@KAGrG&pr$smh?|_R6TM}{)Wa$B97`f zCG-PW#ZenQ{z??dtviIEln?wD%R z^s~LAJ_ZYtfwWbW?0+)2OHJNKN=T@MG_s;ytg=b)0%bGtj{;zQPqCv7qc6bKgd#I8 zItYy8ij4+_>Z?DjAk%m8IE|zg|Dq$d+uQe|_QR;XH8rz22#!#Q3D|7y1O`+Xe6M)bhseUSOUt$)`P68|WPk>EtKXWJ${ zUyq0sJMmJ3Ql7q(SC6SSUuEFH(kjO-a{hfezlRKivMtoNiGY$x4b^11gFHS|NW+?% zi5p+?m=U$DFWyzqgLlo^_a3pd`P|-yqQ} ze1%8J^g8d0=zrBD71WVP{&M`{y54v^#z`IH^J`;K3+wDE;WhxPS7^F8YyXkRdwUCEAttVsymX z3GB1IL>|*L&(>t15xoQbz9ZIvQ96#N*UmHi&=G5^jT5RU-;!!S40369^^^`)KDlXb z*3Ys-Q`JT+I^t_Jjq|47Wej?G=g+=;%auO$Jeir4j_8h9dj? zLaVf;J{x>udb(qeDW@y^krqbP^=gyS}jsq$;;Ul;@5OVH91tJ%u+SEz@$(`G)D{dlezy^ z;>=#qYR5wjAI}HX4*x1_xgBq{zJAc3u?9ijQs_0b0NB6@tbF|hCuzpnNkK6bQ)rBe z%VZ#ZrZ!T=CPKtXLd?Twp8QvT)%wk#js_c(hW^kznBCyh6jj!;#J&9R=r9Y);X zE}^7kgi)r7l_A>=N+iI=B)9OUWN`=R{2t1+TTRB*xSVtK8dF> z3UNYoj|Su)&?&IL5(BbTlEDv!SAUW*Y75~G(Hk=zkmUn*!P%H#unc;+ppYP{A(M|% zx(@%&V-)2~8Qi(;&$YXZONVb+dvetjeSp|7o!v6`F0ocB`(cL`)(1S==)C$EaWC$% zI%4su*$LPpv_YhD`s(FjD421BXNC3*33Z{l32q<2O>`Ne+lEA1w`ut@4S$DURcQ#J zV7Kkh6%?tQazVqU6dc^#F;XI1att-;jORtuRR+$v(P&STw>I%`NZK7K^GL}B+11%a zr)om0n2y^GZeCDgef*(29)wuEI-#cMGFd(lliWsb7+_y=e4G@`c9-3bZfK(PnmIwE zw+jW-;eMAn>gwfLfm~*iCx2095sl^U7rDfFB76B2NmrNw{p`lbK8 z*`nVbZlXA>{U3+ZEk=mvlzwY3N=PneWsmNC5+SQcTlalRl925}&~nE=W=L-!Q*v!! z<#ssg^C5>+{v!QaE`J*J3-)WFAl`}zyZ1|WY{}T?Pl=BGXJG8@0%Mntg{_Qy{ma~N z*IyyHRl4&gGZ@K-`8x#cNdrEm@*XE-jJ-^*8FUJbUqrh;CwoMpCn8hb#eEPsCorB7m=>~CZKZ7h*l z_@1@LmN*=^!Z7QEoq6eu3o-%0Z^7+oVd+*`j2$~vsrSZwgq74-`6^RV2!bQ(3`%Rt zp0p;6J?U^j$fbCQg}D)LFuCfCky&R$jAKrmK4RTMsnFA06jaY%&WxVgRt2I52s<-G zgYS`(pplvKLWlQ-7UJ4Ia!?f%fJvmfkv~04fWR z;$_w->a9H3(fyn)JlMQ)%Wl{c;F=((*GV_C?2v3vB{LAZqPWN@#-sanoeal?$cM1~ zY6vSWTAIz04RMJ;Vw60*L07t&oCxX#Rq|v7T^*p_b(~!#Rhy4YOz*5)Q0e&KNJG;p zbT@gQ7JpdV0cDq@iGgjkJZBKWi)jSB3?NFgX+B7&Px8@au5EMygTujStbKrrKbJau zl8=n7wVxvZQ6`1|#z4 zAY5~7e96Ejl--Mjfc;*(ne)k2oKcZZzWy(7jDPe*9ysbI%T2{~Ixf}kbn10#VaD<+ zVW}w+l!GuWe`X|i3Jsc)k@%5LCnG?W27iObT7)W0j{KT&k1&6hU->Zx9BxvDHD(Ns z1^b{X1AG@y?c+xrg;rg>`8Xe@Js^x^)IKr0a9@g+e!wXYa0$IuYeGe7mZ>o=*U&7g z*V^x=@nx|Gb-O9^4T{s#XB1E849%&^oZ|YKs=O@asaf-}UmPIC(JV0|;7$E$UVou- z+&dO!Lln7+d&fy0#z0(+2%%D7J_TypM{0B;%TsxyAqRLCzfG^Wc9WGy!MWs663H%r zJr59e_x$^`U+nU8l(e388gXp3<0Qx?%-1Q)Dkofl2i8cdroVN4BQZXC$gl zaxz6Y7puL0`ZEd9cUG8b{P{YbMt|u5NDdm*F{ja%anNdB-=Pi}c}6tV#qd;WFricf zv@=K%VfYbEbRpnzhD32A8cFM_wGl|op^&ZxO9))(DpuPD)HX^Kv6$lR|;!L9(K$-nFdSU z$@+u>c34|WoFvvhv0zin-&EGe&DL!JQZHq$h9wbF3L@prGR*KcsHJoX5az}tn*Shv zP$Id{;nCYV^idUyCn%1-=9~r)Vq)b(KMAq=6lr8`3enj5+kgH)kAK=tmjbx{;lRZL zEzbEV9mX7N%~OQc&NA`0|NL(;wkcOY80JfP8hcS%E74scQ{3pv3WpA^g7~Ik;-|VR z4P$_dxI#x|KMKKZ$E19 z_6NJ|-FvYL4l)Q6N)ocu)_?Poc>(NDtDU?4pR>Ev?Ak^mq|GUdDb|4`>AqT>kf&DW zFq5$kCV!dCTqYD;h0XDAQ>6W}IO)rSlha$@w4Q{ui9mGgs()3klFPWb)(L%lsf=`j z>2;D$>`_VNm30Mlv-l_S+KDI{adhZ+2dARj#SBN$Y%-h|yy}M9{cQhv*bm39?}rEK z$F=T6?JXJCD%TgmdfJb6F$wJ63(jGsmP=(7P#2PnW|dw%Uz(ccP*;F`(!x|roH}9( zS(Nh`?os{ihJPi~*a<8x38)wMp~BNfks7TL4{1?2uv0~BhTUPMFDJ9?5>q0DThW-2 zh|cTOm(J$tO*82K;J^|t+4ITVWi`p(c8>O+?|*l2bnyK2{JWPgULBtwKAppA8uZ=E zgC{SJjt-tb-9J5i@%;SshvS3u!>1=AD#pWfD%LjEs(+9C`uYi(ydW99wiZh76*LzDiGzqYbG#&roVq&MvLjKX-kEU}ZBXYt>HU3W1yi zVa8H~C4cjX{)Z;lzA~jZgEsPP!Vv2DK948Y>99XZxSJX{U=5l)V_;o|4Sjm{6=W2Bps%u$lf9@BeJ=pZgO#edgGuhe-lUOSQcO*t|!T$1KU&bzBMAV5Wn**zAVi1VSHI^4&%$Hy&WMNMK7j< zOn+Yp7+gmxv4Z;kSf!JeshZR$N*Z2-uA%m4ZQmNkJ>p_jbatY6s4z1nGCJAy)hq^V zAb|=PrgJZXhj2DwInXEc9nO75<~;(CYgwg=+-@}D1l(zM6{rZZ^*P5xLq* zLkc!!0(Tc7UOgs@^sJcXBV;r#as@Z^X`2A~5T)`A)ve@mlnosfbSe=#bBGo8+w(|E z&*oy3C6q5nc+sdX#pl{=Y3g>(K?x8YMR*p!-=V+Ywpn6M&dU`q`s-6 z{XEYifN@}<4YD;DQ&yq^5k{I#qgzodZU z98)ddsQMy{_gz*eQL=|AP*O9Dg&GXWev9oKy*tZ$g3fD@NDXlp((;+_o8{WE z*1RHT#!_tr5m0sQ)u5bi)pRu^szNlXOrW$>;}zMUsz+W|v}EaFSJq?+w}1bXB(i8f z%SZ9>W*?{L77epp7sX74&fvTjAJ2ww_MiRb_Kg8g6Ayn19>Eg@_a(%l z9-+VZg2!=*_R7ObfF>>J7{PYTtMiD<=z!~+t299d#d&MO@dNVpxeR5P7e$Of@Hu3! zl&~u4Q^Q*K)Gpmw%QSMSCd9hN%#y4z|xZpt`U01CxEth15w`7fhud@{OaU zj6cS9#A|qAEugSuLvD%J>}~i$Mm^(+4_daRH-2Gv%|EyoSUcCXR~?fi-RZy7B(+*C z(-Sw_C;J3t?gixutnvW5{=cuBZC-`+T53Dq&bwt{k8H=e?E-3OAAeA@7JcL)k8XXE zK7$3>XKf4Ylcm|^(ljkb`mcAoS?lD7=P!;=4o{??X(4Ar4eKH|@4^4xKRSMPz$8EA zfb2i}3!Gx56L{xqa?Ly$^@qvyF=H_r@}e$IuJhRt&M`RRnr8$fk4KWvyw>2b#t{O# zDKGGue1>4)?CNZ_)PI!?G-ti?`s{2qd{p;-`y9;-=1=i3?Z?yPB?8eJTN{tsdMeUv zdbUdQzDFE~PU`9be9Ze4EOD$irPxEhqI@i48Uxod-E2EsMCOL#{o+~(L}WK90K{SkTUqk*6|D1V=|s(ez0S`!Ypw0FDN z>gY;m3J*JMfk7y5RNreW(~r|;XnF&JiK(%g<^4ntBOM6-rKKFX`Vsy!>BoDNe7yQi zO{~`<+#^NLxzL%lCcN|fcZWK8cTart^I?B)wMR+Gzao$*{<2`AAK|FCTS<`K>t{V6 zvD&lWkpKKh%YR_r8IkAN$&zj*(&5bIMe7NW1x;tg8b!0!YGHl9%_j*KE9*bWhqxhb zViNjRrxaR`p?r&{d+o0@FH7jJZz(8pul*4(Pw}d=y+lL^NZRt%Ip6hc*H;9PDcD71 zofmO}>}%8E%@Y|fDky1V^n3=Xi>a?wMc7n5Ib*8R1e2LDX(SE~){qh@Hie@KSIoFZr3gE2|? zXvprFNublfw}xR@r8DDn4Ks)LDOLX@>9tO-^U2f#5Fbx+q=g7}@ViOusatBMoYP_c zKp`NKP=8Q9foH9C*l%G&G23fz=pPT^C4MnzbXV%|ZrzopWunHnhkdcflSG?R!ktP0 zz_sS` z|Au(Pn2|GSQtW;6^K?4g155b$kqYW%Zh(+^pGCb_=U7N#7{;Lih@wU5nzmhxo z&oU^vyTVUIW3|*^v$@CycR0DnyDu_2wnWA{{6LSJZd*^yk9dW9W`9gSG^@G%r^(=K zC4Xa6b+K7tfm>Ysz6Ckkgz>x0SuxqXOtZ}-dn?B8fUymT<4jk`*4Qr3U?zlasi>bg zlj3?QR;~5);N;26!(#v*nW7!2$2L9Aq2f02IPE24F-=AYsiW8h*4#W;FW3HM!U~*< zoEp?IU0Ya@HVy+Wc`SRuQCV)t2$Ouv;(sY&Uv*U}(aVRx!qKmkC|IutYCYL?3D(pO1Lb$brB)Td5Sn4Y;pCBe67j3@aOJ(HP6!6@J6DSzh?+Ko7S zf*9xQ+J6_P(~$9^inWW#JABalS7?WQLs=!V8;CsJl?~Bd8KmUDbRRTDR5}8pyTUh$ z`zrUP=1QRX(|JGMdaTPZ7c!9Ph-&X3FE{*B5wry>P%b)eOH7Zk3z=zxTT#425bit0 zy%c*^Q5$9=oY_*rY;kWoBY)1p-|0)_Gw+Y3#%UcaXE&%mhYlL|`uU5~11VHQD*myk z3TqXO{hy?8AHl&f5u;f##T>c`x^zjHMk(+k@HtgWq;fLjNeW@YGO=1BMp?kn3`gE@ zoG8aS>ii|_ktA?fhMk~PqRx&kfbzKwicsVR$PcN_Y0A=e%po+5wSOO9x1&dKG&uYD z;m1h-``!Zo-rD}Sx>hn-dKp! zahThTJJ*ViduiX2h|WZ{XYSEuNm0=3*(x30TYf9=JocB!d;j}n2toH-X+sh?4_i{6gz)X~}9 z6HGxGpKa!~s>L8_^C~AnkB*L_eqVh5eP=Z46v(JZANHV^UfKa2fAsAKYIu0`-6Tm= zMM9|+2klyVOlPnqMbGo+$vgPk>TE?83AG&M*X5vJ^Squ(ja)A{C3YijYzio=;7nUDMhv+{FF;Ef97?8h#p5_2 z${Hi@Z@u|WNs;ple==Ij=FiDO^+Hd89dEX9%*n5N zRJJk0z?l411j+kO1hdPmW=egqC&^h38vfx^u@-D>jZ_tye?(|{_`_6YapuO`xAu;- z`c*fVRja*KVQB_i?ykHlbXI7nTw$GG6^u3XU$@V6ar=mQEEr$K0K6|NMqzi00t!&n zA-ElnhY2c2@x*khx&SGwu?mZD`zx`UifD*MF3%Dk-n~1|9{+kZJu6ScYAWY}tefR$ zhyA8ifz?@JfAgIWg*y=2)l6hRZO+tF&pCJp{7RaEFbCr=3 z$Uht8@$7U?CpX9Oq(~a(!wvCzk_^r~N=*S|n>D(s7Ne^~wE5-Iql%RZ9?S49^GI5I z&RYh5=N)EjVA9{~?M8KlM64!UrNwNMLR&NUEwe$Te+Xdh2jr)OuESDl{S~DckhG^G z?=8xPJ2}_kGi23^4()mC;62L!VI1;O*ZZ+_y-_-@$tW^1Yo*+l6Ss9Gep`5}lh(bL z!m@VhrI7W@xl4%&l6dQElS&C7AULU+vG;>D83h*&2{IgyTewxFR~ybmSscUp*=80V zJ*yWCf2;K8Bm5aF@)JG#)D_<*5dC|eW&)CQRqOTwvB9Pz%BvRq*tHw2I<^6qwLQ&A zx_AdDDr$P!Ryo2p8eRMMqH(kNT=!Nkal@rfxPzND5wY0nKluU0su-Y=WPMYbNhvl* zNP@wE*!bC!)a>1HGL5-sSh?w*))M@& zg)|9w5cV=W&&lkB_biK$?lRIkt(B}pYl2DyS_?xuSk*LHRwoYG=d=yMQQCd;M+!5s ze>8mShNX_@P8486(iK#8ORe$~M;6_yQBb0wEbLiq0{dH)A}EQ2<@SAnFgU0a4C=a+ z#@SN+NDdKu^Uy7U_SFE)1hOB)K91z*NL^=$xA#2O>TJ4tYe9EK)lB>T`_ZTt4B9L z5=i&S(an>5G>Wr+3oof%CaF?EwmtE0d73c|i?%n8)+PM5F5frxCsZ#{XicV!4<3DP z#BM&!!aOH2k<~g^$E7g$sGd4x!X#>Ux3XFJUJW^$^y|yyisbFJA797OPy5kdf7;Qb z*7?8Ojn3|VWBn4H-R*W;@`tmZw>LhnuK9=~ZUvYl?@lknkN8zg@QB1pt1p$-03`~S z9G|0j+L06j%8fI<)OgvqFux;yC+c0X+@ng7q;ka%JU6oR_RnX|$CCt!p&ehJl>w5L z+dLyPt8XeyJUMKyw2bCmd-UArf4$IfLtKNLP_{rKOW%QM;BK)+BmXD{Gy;ba2d|-$ z)2S?RmN!Ibk9Zu@=gXDSfYsX`T%HhLkP~QDB$GO2jOEDSBnFlnxKwpznV(PatGCdS z-v?C~{AZc>wW;4cJ#|^I%Z^HKX@kDBhwYWOVbv+EMJW11Z0+~^jWzyce{DlLS;EVq zs&QI#XFxTgLHV2y2h9o*`J;rHg=uT~+rk}G&~X=3Wui3SSu=5b!alf`<8-T(dEi|S zdBg#NEHPqoqLgi%*5vGo=Lw=w?RKm!{f)O0wlTq>qCYXDVU7XIh)#1+t~3YM zVjV*UgZDMfuBgO0YiGoBf0KTKQoRA2Pt|Fc^L$mkJGY_|zu`m&1GljLG!BEv?QXq)wF>>r>MY=2Mxs1pAJ< zjkWW0j7zf1&sv6`h@DX{l}~ ze2!~&p{%t;rjlaeg{;tet4=Dt7Ceo9&*)8kG`ybBL(3L9rx%{3)|L!Q6Hwz%2~Vlr zX?YEqh-AY}knfSwL7U>4BEHPu!h=)ESsc)^W6E{zFIMGrxgj}{8ryAPzPt+&=?*7x zkGTp`V4?~7{S-fke`zG|)2Y~^&H^X~$k8I*HFM-|=#pve3m~VhOah+>ny#cY4==qi zVw%uJ3)XF^fK4w))U^(|412e2vbkl8u4-D+&uPN0w&d5(h`2e*z8qQq`=rTavYE51-0h zn=rSDY3_gO1PU_y;1yzd@BTkbxKwKBTS2RfSheZVjO}5M)6RI8+3*lk4|;yk}RI2 z`EsyYaM&PIX0MONwJOAE)y2S)b3Q9#6#hftg}tK{6_xUV10Pg;O{o2~LTqic+if6h zskSKBqh1QRD{}z^+$Dv=)y~7q?zuqGc^>Q~2~~T!f0rht_VsPQ_cpmpMqxeq%!Z%Y zI8aAx+uPd{ID*yQ(7nCA>exDm7W=C@rAYU3#C%PNu1k^Ttt0dVF8t+D-Y03=GLs=Z za!r*YYsh*r%{8rPh&4XVYvSXaAmTgoug?O?7|lAREv1_4R2IJ9%>qWHRcYDuvLkq5 z+G{#Le}VLjTGfG6CRb+`lp~f3&B|9QBI4EPDoat52Tu!eDoKKOZk^Uuv6IsEId_B1 z=_4Bdp4gMm{vgCWB-OX0V@l|q?{)AcIYPZ{H!a%&7 zLH!ZpWqDK$P!Ow)*Q0oPeb(uGJIwP*gPYhCf0}+%+!b5Rs;mSC*(-Mi%d+r0D*lVD z5T~dtCqAgaLZoci`wy{ZlGEtG2QP_({>B6{x2Tev*xM6p2fRV?)_9VWE!wS@vcaVZ z9Knf!j2LDar%JooKbXa zT5|xN?I!KE>Wyu#S*rhGyPSA^wMY@@fntyf!sesq)XbN4OAjT-Ie8?JC`%X|e@8=e ze*M99xws;La;MhbsOnSNKyBL&N}2t1kGZz418ph|-Q9PU-oDBMG-uO==bXF9f=*}d zCS&2XGN{898Ux<2ut#vY$XDv2d%u1@KRkC{27XGtRjB+P6-j^=^=SNthq$CO;qPND z|AE(Vv9+tN1g(k0f9u1F`rzgZ z{kfBqdt7WqrnY$G-hq;~RXqb4wu3Zf>TQrSvqZl}=5-#~A7^Rr4cyU_skoY@{p751 z=dbuJqTeF=O|{LnX`C^gHSWk7G)^$S)6D#S&+DZr+iVw5ykoF@CP%kwuZr23Z>rb8 zyyH=`E!QDJ*2FtBobgAre_h2OiKnv(?YP8y7O7{d`D4rBN4aZg@angSf734~6T(`; zqGT7bz&GYmWIxj7)bOM)s2IRm<4!Dpi0B7JpU>lyXNT?@Qtq~>H%tSIFA=vYuLv9p zQ93wl+%XU{%Cs&YsL!~%j=x`YP3W`69Zsm@Z<b+w-6`ag$bBNIC%x+o26TA$s8dt*3(!{731Unp_dHi!gfz1T)x0;H5xyPd zE&?d+3lWvlY{4a?a#;k@VED-_imGfDk+`ThDQML)a!SuJ$fR@GTVWHn4h?9Q4uZeD zI`5TCR8w|t1SZNHf4A1Z7kP$;PG}EU=Trg4?R-TTI@G~PR^yvN`J@}38y zp_lA-OZ7#XF6Rtl#|*-aeBxD2uMljiL#?X%QgQ&;P258hR@QZ*{6jtiHiB}udDVAc zyaQ^0DhDIye_+7ZrzEwqRD}mmu5+a4qGH)(C$u;ZZA*t$u#2^$j%d}b->BeO%$(QP zA0uDOAfKRUb3n?mS=)w}8Nb*N(}apII(QqV`-kL4U-awi#1jtZ=H9|vTH>)$*tk30 zWQDM1L^6QX4YaVn!z;=O=7boK2N_RE$B24)Kj~A_e+Wu*Mj@RF3`!iGH={)YGK9*M zWYwLDY&V$3l1MK(9zP}2VbT}Z$#5KIwgHK&VTt_Sr4d-hXV`i2im^U)R?>GuMeovn zg1tM;XEjSGz2>OGYbBzS&g~kXdldHU4%f2oL>2R9B zmn=EIf4O$ACUM_(qphz~vwBaBQ1QFGJNZ^$U)PucHt!ekkl4Z`7$-bxp2~&52PzSPn8H$@B*q6^Q&Y%hFCn~zW>x_E4>kJ87vJxSZCD%K3!;#km!0y2 zKlRv$p|ETah4_0tdY`i7)!VNc{JF?ZB-UE#2~b^+nh>U|t*MUen2|TK0 z`rtOH10sU}$0Bu%&2hfE3VTH|fhDsoIe=$S~X%~E1qeQcP@H&52h~8{MiDqb2GHo6y#4;lQ zp#=*O`?EtNde zl6un}!m6*$MJj+bSf13{hjB2_!PM?ferz{7?MwKk>uA2!8lif5#46#(^r6 zqGmkOpJ>H;scY1=`V-BnFpR7+LLwMkh%ai{#}+XLF0Vy=Xpx1(d(An7w{JsudjY~b zHsOc&9xO!n;k^gVZdL=^#v88wZW(*56%v<8mJCvb3R+)3LH+g1beK;09_ApEA|Mg% z;{LzuHLor%>#i4lSo4kRe+3uuFtyu&EJ}27IpgcJC~$+bS0A2|UT-$x%U|E>yxE{; z8B_e9(js-}%97;pw@d=JK5D6|OwwBX5aa6@$z#Y%An)xS6MP}XszPMR6yhBvR7{F# z!I_%aTkt*|%|>EO=4#*|w45a+THyjq)PW1(NGwCSb_rAxk-Fn2^|Ly#qTf^{i;#ALHCgMSLSjUODX2)Ur{A`^++F#m7P(*< z;9g9eNwAd;s$LeJ2U`TH%_GDv=h~@=o`vQha*|zDja|Q`)#Bjm)x*ag2?K}l^l<{v zxCwmU&{^TwORS+Xe>{a#s!xVmkkX6@Q2>-2AHX{v@}7OVL=4lV|t4t}LW8#1AbIq*Gm zQ}Yk5(`CUVEJ3{w>1&Azl=7*NGLrccyH53bJjwer_O7mUf3wwc?#HG5F5PT3lohhd z^@85Bwh>G~5vW7%hrWe%m(QpT*6Vrm)g#WT=*JB!O(a-PpfneybzKX!vZiLVHkfJA z*ds4ss3H`}HAwn_Nvi&Y7hTbu6S4Fq!Z(ry!Z*r0*Dfnp7o9;V{Yp_3d*X$j^*2r;;m^mej+S)-WIn1B-pB+BkM@Bnw{QdsPK~+AOqZm%6_?BB=sdjG8 z;XyuGCYJXz?{+X$fO!`}Qj}jbQm~AoJ~m~$-2~oMapE=ARZ6?piX3;N#sei)bTyUW zQee@ae;yn^d-223!SmAv7add-?vZ5ZE6Hi-}N9v;soW1t*9h(G-CnQYX<4)~w}a$D~sgP5*e=X>(SMSwkZySHIb z_^OUYU9cPdWWEL`J|KOVxbQjJg)wj$+aD!#f3@brYrq#+KKqb^qR5-%=3PGNFFYyI zY38jCNrzvizxA%Wg?bGnyoF0ZU>iX8!M)BI`cY$9*@m_EoYOQ}U~o=LS_fw&a;67(q6dJ}_Aw|Oo$;l*KUGf_Sop(q~vK&b9~KBUCO zCUDHeA2D>FqmT}=0^1K)CgmNhk3_mo!r*fb1am=D+!<=*wM z)8xDBw0F(uAv$U!NF}|vpe&-h7@98mV`&KGeSl7Tak3f}bs?)l^l~szv1Si$f9;}l zEz2-kC!+N}V`>7Sf`ay@1l4?7jv3rg<=Cnh(T)4N=w=USv-o!<-|fN84>?kA_ldYp zudb23w`?qvs3P`@)LpyX>>)bAoJG1Ssc8zW3ed$S>BX}`-O%!z;w$O5^I&arSi1y! z1)b$SEUTM6vd~B5W~82;2HVx>f284!97Q2fMm#lE%XQ&gTkXmaQp%3X>tunDCJCZo zrj>v=Duc$KGThDdTo$sE+O9os-E50k2#PFf3EZld&c_W zD?lzqKN-e1g)XLQYu>;QQw@-Awnd!u0MN9ODO83TJL?$WDNYg)QzwEqe~=Cg9}dNA z%oV&;V|fOL!WOYuSq?=ZH7s5ZL6e073GXx_<`lWtJdANY*wevxQZzQ}vY0A$w^2Z% z^o&dCzaox6UUcxyvGIeKaQF@rk0TW@l4uk*IZP-F)#cjKio)ySguD^;KTqPZyO;Wn0)i-OG2M3M`)uPNXFZ1OhpZM zkx+WTE=u@I-nRO*RYiK<55-)|;(VInS7lk2)-H-d)JNJ}M)GR$e;8H?5sR^1s&Gkb zkW1%?_PG_^DHhmDAI!j^#G()40{^sETY+xWIn~pvB8>U)eV0sW0uW@ZV9Di-7JBvj z)j`Q2Ss!&JzsH+3hK+BjShtjbv1h@2Xg#>`4RIM4X^$@~Bn&RD^LMPgEY_s8n{7$E zB9#eap8RThFkR@1e|j|KtS_oSa=D+}oEc$=x0&6w!t5R|Kw*>sX`dFTaTWny-Y*~T=r~#Ie4KN#5|{=Fbd*ehHaAB^=_79D7M`8c zPZJ{L)YZz8su@>)rfDQOX?8hGd$JP{qYJnmrKEXrIoaeFe>%wg;pqI4PA(GhjC8hI z?bh}M&lu;`;v%=I{1SQ$ji3OiQl%Y%jbTHwMwtSH1vGif$?_0R-VrsVeu{#7(szaZ zoJeW^$P`-Wp|o&!MO@Ap>~@(5PUFM)eHv;yV5dlFG0fg`^QcG$H!lOqQ>lRjlpl20 z)=F@tzRlCVe^IB{sGvm-FWt@K9Ce+frlZQTxKS%!DhIh&+*tI_o8v8j^0;lbx4ERO zyl-{qL}&RgmDY?AN~9i^eM+1eAD?$Kc^YJ&Xy=Nx<&Vai*kkhw*LPd9=}{fm0z>FH zn+Zl6!FN>AQN|hhy?q17INGXS3B3wYHsHjPA-RmU|R;S307*ay^}ni_YdI|JE{UYl~8r!51K( z6`R}bt%p&2H)?M=+sA;fj@_=@>8_~i3#uc3N+!5uxNYpRcB^f@Wd#kc=XL#z1vzuce{EQjd@mo$u;mS3d1f$k=q~h&S-E~f zH6PlnTb@IN$V$hFnIcsKQlXPtOz6;$z4lEG9G>jPV2i;dABp&FoDM1Sv$p;iZzxk$ zm`s29!0KB|2`C&uZI72fUh`@0k4$_IO$CKW$dShMP>Ii%>5!7$aJ*md#%&A^hf)Ez ze{=+UWGYvdy8z`bp@4@p?{|=hZhAeu*${u6#gl0=!9NiYnZfxn^cs;bm(~@k>Qj>L ztadn!4w-qA%c%r6^5a2Jqtv zdQ4=zPpT2p(Tz1Kpw#r8`RGpkNm7w+-1FqQtF0Bn#e-i#O zi;GQyx1`VCDekBQKvbq9 zi-u=Ks;^+DL<12yN4h3|5p!y>D;>LKu|Q{VtIzwzbuK`LIoVJVShT~p&egQ!NO7aI zMWingb3+)M6n9hQX85aqK~Blse`F0`Xps=dsL?^rTB&Y?cIZ-d{-g%m*#D_nuA+D8 z+ptsyPthoOq644Tnum=@7%)<4Fo_~cS2N#&s%JRi`bMRw1Z+c9!0+{wQGb|BA9I*% zLzO8!xkmj+nFs*I?&cNxLlvJvJS)u>-$zc;ov#OpMho^?7$@%ukP$I>t2 z=T+Xnw`}4hnKss>h=%g#`n=)~CD4_p%^dJOVLrdz>}g5xmfuS;ZtmAk$wf8(=lS&c zY&d)|IT($nH;q7%Nr#Qxf2xZX6%x`22DCG33+u0tj>?ZcaZu|2$ z;z@C0PdwQD{H?g+oY)hOzQ9ldf*oVCZn-^O>Ft(8G|p$w2vp0Gk~KoUHZfDCIok`#*sJ zChx6;C4jc0j)H!*RJV!YrgEE>EQ|IV;QD&Xf+1!BS|9!4p`-S_&h_xDG4j4P_ai$) z+=xH5Wd3~kaV9(~_Q%LZmQQs3Jr(C+&({KV2i1Q70==s&e?8a|PvEQrQNRx1Jv1&^ z4Y5@?N12D7#nP5%<@I_PoD{!vtE}`S{gc@x7?BTW|1(T`Y9f9XtLH653IKl^B5&^q zcV}761gnCnNphBfhJW}}tOXleGYC%#QbS%FjmvlD#@nm*F0}epH zL}N7ts`@Ljnu=(MMJ~@09^SoMF-y9(!Ioe*gqv~>(%`<OVG*)sc5-t^Ws(8zgGLF#WK#Q>o|UcYxtoO3B_Y>MDJHbc}zJJ;M~(mtmZFV+4X z@lu9y1gz&li+{M1qVj%xV@Xi*XM9Y`A*o+@r?ubj(=SD1OHRZpwe@14UNlnJ4=}D9 zA}#tm;`gkd`G@Ffe1n>}_HMB$w@&jDx||!9RJYcwnI5TER^0G<@|ynKRrv+vaQTNl z@fsgPk3Q>kM#Rl=F~8gtiRysWPfpk$Vx0yC70)P!@33%TR1P< zKJ2HiVWRYrHXno@+V+6bL!<0_k3yFbasU5jOOuab7;u%MtI8IZlziL?2PUF~Kz zLQdP@{pDRg_LS2Bw|}rMAm?ZM?(yhJ*B0YdtOcuhotLd6?2s)P9z+%n^{VPz2kHt=CU=N_lnFZYHvZsz_i?7 zGF+#HkrmBhAwjwUj_C)sNHcXIqGxF_-B+JBn}4C3uFgy@(jr@fH=6=z5+e=DUqlKJ zWtv@es)}n_7oj^&ZnmejRexL|jn*B2J@3zR@(CDljX+F=Db3hHH^;XSaC zrGFk&R!z$7`^rgaKu8W%0*Ff6f|6B`e-t5>mPMi*r5iFa_v?L3nCS!<;KO{Ge zHU4O=df&1}sJb`2(T-x>b$Jbh?yYiCU4M1BppBJ==jAvN4e~Alz|9tq)A(wGwC1t_ zM9ziWe^=xMDQh#HVTHvli;9X|ID}NyU2%h_H^W;Cb{k)-n#NbgPIDSxiO8Z{)nY_v zd!d5fw6fF)YfkuQ>sSYLhktFI##e>>^CqZ7IWt%H_3Jfz?bfRGs*h#;#ou60;C}<8 zRh=Z$Nt*aRZuFxzXH%6@RWgaF(Una~V~E#%eSqZosnvfKF{S?6Bv|?N$VOMwfT@j| z*9|*glwT~L%hC}dh-K}WoL>|^qzH!_5^H)M)(}y}2zcT~9gi>7tW;ng+)t}_S7-=} zk#X&3{o|UTqams<2c%#{_KT=DnbXUdOyu`$p5W1@R!? zwpAYPmlW0AUMUUO>67{~GJRfMs-FsC*Rd3Ynm$_DpKNrXWuuT-1nM%q0-AJ=`-|z> zY*BT;Y{8xoWyrQ25?U9=NVLRv`P5yI(g44cxT{j(o;jPzRdw98t95L3SASq7I6CV0 zzyE$TDkz(o{?esNHzi9mks%r!gp{!)PC12t0NzCKN)1j16k9D7z4$bpKoXo4n}5h^$3VxWP%FFZ3<$D@b?Ea-kyjrY4`Qk;OB{D_MMmMZ zA797OPy5kd+R>xd`M=za&hCC={Suws?RH!8hqIrzH$JYe`MIFD6=Z{QGh5DQ;3cy$(RdX8-L`WRS1e^)I1|$ z+;%#K@FHSTc*Bnp2FOJ#YO=?T?M(;)6)+ljY$)JS2$Keh|D7!gQ3c^6T8G6eSII#J+R{hfe0^ z@`r$3)lnUTO0xtj(tnn)A!G`Ws01AgO=;n-g4eHz)a|VAZVv|O8`wN%?_VjEdZRVc z9>R)XoZ z>2PEM^^}z+yV04;YoltH(GQiWkBdd+cm^qL0snxSmpA2t) zSFx0VJ!8B^b6S!W&nnRm3wcJIN$?nbxE~9DHdkNmZ7?(n@8qUX)Hb^ z{h*#g-TKH$xsH*4CCTh03skrSQ8hAu0)+yp5|#+&bbo?A=Ps)DF<4bJRnSg>6_!co zYrJO_7LDLptk{Gyp$|F0iiMY_!nF}PnDk1}hUQ4{6fdeygx3Rl7_c7(TK^bUHcA7o z3|)3?pAK7Q6*wVYOF>dZXaO^))lHAj_uhypQZPv(+ywo8il4(YlK1Hppoov%4B_8M z=&?w5Lw~mt@0*f;^7Dpo58v>aDn2cSyN1lXK<@dW+{F@=N-E;H7o6wUoGlX9 zT9vX;jQD<$$(x2rj8N}IB3&H@TCO|LUD<#3ms>=K2I62tL9O*1F<3M6*BH$gjdhj! z*+L<&pL=|Ak2&i^LfWguFBBUsw#}&C4+Ni9g_gyrceR4^8#o0+~7tXQ|0c2 z+Mur>iRI!S_r6GY?B16Sj@|pULu2_o85Vs_-aZHnWMZz?f5mH>6XixqqgO zd18%)wl(pww#Rh3=P40%+=)>@)*|3d!c}DC+Pj{DRq63Ft}eRsJ-FkVu9hW17$ul; zBPK(Ewh!nKRFqGt3?Qx!9CqgPlfl}RbtEl=8%FnCS)g-k4|2wovZ6EhNJ=+P-O_SZ z`?)o3xI&GarGMEvHO`=@c0_qp4Sy;TzuI^`il^6SozAzzJfAeUiA}3|jJPYdn##c$ z4qBI6jZHdxpTF#6eeI-0Doh$w8HQI5!(OVePpRym|ASxpr^ynxSplAR8Ll+Wp?iuPX}Ls+o zxPYfnHU%C4YavHwPf%Ir>Y9vNqkICvAy|1yW02?7VhR+pERD$*49I{O2*xglhRfNg zsqV{M`FCC?CgExXy#NuM4|=?Tu~VchwmBfDs zHF!z<_hdoLr1kC`+$8?{c46!!jbjP?B+bpj7)t8Pk~m81JCgXVXleBy>ky?!4pQfi zc!9hms9P+(S~%o^=(Mjyj=S<5Jek8}D$3~}sV+!-wJCKu)5fjC=1Myoy1RaNL+P*0 zIuw#t;O3I$H$m1)8h;Tc8pdkS&ARbFrPwvM)&Ki{1SjEe8|53j3dT_>h)`!V zpSF5ZmP|^wL;!O3yPC0=(g{dhTgRP^#VP1%(ESg6D{U0!E`L%Xah%l5GEZ8+oBB%K}LE zIQO?uHGL!~z<;%`af}_6;ImC_7i?>bAz_gOq|1mF9zp65W!o~hi7ftgVrCPs~Zo#m#u9^IuBhwyza){$h1HsXik1o|jmx6)fU> zXeHr}bpG*D>2{qls+%p4bh@Gt3K?Eyl`T(Q_>$SXYkKoS+SX;oWGyzyQ+4~nmardp zG#a9Wb$|JkRt(_cPGvgzPoXb;V!GTO4x$wSh7#}kZ}CAP8T#UbE_#uJmA`%};l>%`B z97LON*&TrD#64)l;CC|I=1SliIH1=!zqLQAzb%E zk#V(3O=uSjS6kHMU-aa-il!#Y_$c`SvnJ<@N*0K3yerN@cUkw`Ez!uOi?7Ds1~Mhs zF{8WeJHju1*>o7~?a*n9+*Ojj5Dd-l`j_g$t?#qX+6Vi#lVCNc(z0k|xsqWvJlNhB zTOD~xYW(1@e^-{u+}jsj2`OF;690nNrhh~u*Z|3z>l51?33L8=hyL>p{pTGz=MDvO zO?g#akk4sMC1q7sxU!<|rz&G@726{pmJJ+Eq(u=b;w>}KF=4kVV>f$6_2C1V#7Y^; z{?*Zx)Be|By7=mwpPlgm60zHEcUL}&=!K3oK1wE6MumAXp(q>P3R`Gid97EqTPy2kn;!)izuRuW_CyS&`GO=xgFpr^oFD>wTm8ypm zg8n+;qV3rHYLk8trvQLhS4;3Ru`UvP&qw%!*k=?z4z}Fw@?=_%9_-3TeB!JpkJLxj z8S?(vYV$iZ{Db!~jJw*(abTjgTz^YrX?ID}i?+sevyw5!l~pWJfm56IXKeB>LI0K# z7LGNckjyYhvwU3mrD|8W{BNCzqbxfE2n;HR!LQV>k|97mg~ci#)0|o6Nw%gA^LLUz z1Q!m6x1YQX*UVJ)dRiUuUSsIK5WU zpSIZ&NMNp$ZsihU#C}CwMY#_qJWvXk`9NOlIfWO$F%>@Kt=6cB9Bfi)$&%T-45lrc zyeWBa68EhU=_o~&;569rbbkbl=-UL!!lkkFwgf_;DQrqkuOz2Jkw64%?tVOxy?ksUttS*_rOY$F=@AXc?H<*P>T+!6I$@T5bTP=AHcO=4R)53giHGk|Sk>X9U8`u=` zGX4Tx@Uv5KA0F(6CK$K=7wCeQ^oo1%C@>3_K(SOezJ2lX;K}~U>A}-Q*ChZ7Q75+I z$PQE9(WTJo934T2gJIKnPJJ{kN0Rfni;3MSH-A}-Snc|*$PbKWw_r!$8_}aKYP!Nu zALWlw)@mKO-)y(HccQJWsJ(@_$YoKC+71-2tBHox}8 zMo#~uFiFw^LkTprR3jxWigZwKDE4*OFTI!cKd&%vvTnBiy~wlMiuJW*ECF9GcXwsA z=v^nHxVzF3-G7zq>2zFlHaGdVmQk5oF~t$}@{xR2Y;L!=9!BlmsJ-PVY6j7D>~`f2 zR8QHc?8u*z2@n(9_ExKn|Fhn*5|OSr8&qY!3b4^Gx2tCmi8MKbkT zimFCI`D=4i%;}O8pR4;}E~`0|w%gnHqxN>x-l`_1?ti!Wq#n#8<=rQ>6d~1CjLu`= zwPYZeR!q0cGHa1+}YsV7bk;zG7h2)Xt36Mwh&pn;#DeaD%ch_ymo;FU)60ujeW zdX*)8>hCO@PG+Rf(P$*eo6%)HOnc%kY7-`tv(p&(h&EO5NmP#a}1W4M6EOpeb%37GaBE(Hj33jV8Jzv zO60aCTqI>^cRz_Hb}#IgTT_H88?VPJY=2EyFsnX)R2qEjGoyP=D@-?OmUYWk)}F zKh85COJ%NOO!SYK@%8oQBGd5W!|)_n8jfr>r_bgB6HugCW1MboBMza|bFbqyJ@4g3W1I$vfK0SFooP(nx%Y|P z8Rl0FBsD>ZqDSeD*!IYX#xTDkLodBvO*CsHKZYhMOjI$fVSZIZR5QfJZn>vh+wIme zJLg`-ym_6gCKF#4jp$x*jCaJn?SGmLsBapJTQ0Eu-v3C9X#G6`_{jsTucJHS{rbB7 zv~~}_$DzS4d`}TIh3>Wg(C+jx>PVui%1ysOkH;x>bF4pwG=4|yw6^YT?LOMRzq_;h z@X>=uJKH-C@7>?Ne{W~!;m-DhN4xFqhY#;`L8w`_I}X@3LR$F8Jj zE%Cj&{I}TZ*rL!h&xd@!WkexH<}!8|Qt!JNNjcUR>4@%U^^0`g;oB=&PNuL{P+Reb z!_m3a+xP6bK^0i^K(O#rMq%r13+hM1Zeyl727v!v3qJbz z7w#8+`*f0Cs$3V_x_T4j6{T&MLtBj ze%3eTw81AZjb%8_#W=;A|L=c_hGbl=R*PFnr~|WMGFdBBLG#9T>%rE;?T7lMJm>is zq?wGGLKBB!XM%}sL%jk|t^k`iYMSqH9LGL$i$kX#So}{p^ z7Bw^*JL0a8_v9V1<%zoXiTF0bGBFRPps;{~_B01_Rnx)Y_xy}K9Q-$X}#SW-ae%Ill_bAYf@}g6= zO4+$5LtrEm`hVTY1)HjZO7;!E3nJgASJy({h(yGW2ka+3f)eXDI$xDiv)KltmfvPbbYc02dY2Vs zdp93i(gndaaOp#UFkBw-hq~%J=8v;FNU;cp=59tttuEP)*tls#2{v5;q+@W3^vZ!+ znMz{}u4hPPR zW2G~RWN%~>qb*6ZnNIH>$g-0`EJ1Hd#_1;mPh4TD@F820OGjYTVh=H`MY3T|W=A0h zcAFyl8Xt93k4=Ucz1tAW5?(RhZqkHEHa#-z;D77=$rZr3YO3u%N)ulNQS*%%M%Ahe z1Y|Swg*CvZiW?2%o{9(v@NWK=>D&F4eViod7N8u;4$8(SQ)Niam|+n6{kJfE_e;9R z6UrX&eo4))A%*LE%_ix14K@+*-?)8mq0h5IFYbzxx_d`#m8?YbRqp#uv1v?_4Mpyb z*ner)sk*%svKhi~vz%vmk=vlPn{2hA&bD@vM@sy7u%nu2IkE?g%>=1o8!wre*VkWY zGr41-?yRrlo_qG}s89%aX;@|hr#zg@G)ewDftUeUoOJeV!0{Y42?COfHzzEV0 z8>4|7m?3~(Ow!^FHKAl2v_TMI>(r=eQ-4O?;SF_4>qwBJI6&(vxtzo$wFz^zb#}pA(#b ziTD;uQGOXur^6(gCIv+^KweDxSBdCBAF;(47$4GJlA#b5QbeSMV=q8zyNSjZ#y|Dq z@d&1QPG(4KbAA1UJo)I!Ywk)v@6BMgru8~&DBpKK?-eaFi?{O0)h2F%V!D}T{p5Y? zdO8|@YHAP5^W+@A+qkZ32-K8=;eW&5%@liubIY9CCuU-;yN4ZJWe=C*-qD9$R#Jj0 zqWly3UfAenjyH$*P_aSF50~a7xlXbI;oi;`Ga5fFDESuTrNSesav#*b<6E=qUp98= z+V`prhGx>cnKW}1H-$8T(WX<@FFH8q+FCMB2RBOiC^p1%`xAgZuu{Bh&wu&IDLOK@ zzD16IfS%otC;jv3B+d$UYLUB%A1f8_+*R?;2=?_D;kTO<7VkA`%IHL_6h$W ze#8hQkRfrbqJ{>s05cPmFP^rNb%Zz;qpI)Hm~42K#X&aw&-T2(oqy)jfn#9;nbu&E zB-?2_Y9Ca189R5Tqu}3fr=06IDlk%EPc`8(G6jJvgX6|4dMo ziIvuL%@mrIElbn7nj2ue$5Wv*y#eQ8cSU|VkTnTA;%8|4jilK+KZk5{e*Uo|ex@Nc zKk{|POn(%oS)=JN>whOf0bYk}SeK`LpwfXDCRwAnDO&O5>TOf}tJtxKJjIUrM@*xY?;qo-|;eEy1v|HzErNir1Ad8?G3>` zOfA{il(1+>C`;8Y)P~dNWlyL@eZ3`tVfwhigJeldD~RM#Z-3+DbyuRo{ng4weVz2) z(6%yG(!mgMeLOn#8>9;UjSR*cBAx(UB@#Mt7@yvB)`m+5>b=+KqA?TG^&gG9D`zCZ zrnn%)zq*^(JLK+VVdmfT5G$c)iAW+M%YIv)V9Q<`q6j*J?utx)*@1V6Os}Rbj$d2* z*=z0N+J=;xlz)@xXZ_7bI#AqPg@;e^YJH)qe^|_F&u3eX6OdU-IuMHCAXR;L<@_8R z=KQ?7BFD=N=kw`g(y(;Su)5o+W%V?c(9D!`mX#_gkyT+4W!AeE^5~4Q zwm!Wc)5U|_IOYqSGRi=!EHaj)K$@48FJgz2sT!3Dz< zadvC}IjDm&#LRB6^rGc4RyTxg@0Sry{GSo_?cZ!oj4s`avBJ&SJOIZlJnHVyd%D)wx^-2V$~;ho(j zCwsReT!(sin$>Ft#Mantd-e*WzXv+bSTd%wOtahfwCJ;?V?Pv2@zR4v@y# ziv8jB^A~1w4?5a^@8AZ<@e~e_@TAL+PVtcq2RN1=xvf$b@N`7SH@mVig35sBAmdSh z!hh6DV}!oUJci;MIva5+#G3xno@bhf>F|MznF4&D>mtivaMd-uLIv#8A> zCtYmqn#1mYYPbMFJlrm<6@(hy!D+ghBuUX!O-ox%M?PO4r<+?3)uA~vqd!E#rb!YH zePHJX5>l`Axwfm6I7Py}+LWdt0u=aHmw$XGsXZKKLaJCGMq9qAtdUq8(d>D$&rt8x z?*AzrTlmgmBiz5{ZBNA?JK|^6s5uSZOZy#jV6@=+Yv?t8oW^bRntB?RUPF$EulKfE zTic&F0)_ZJ@1<;)KIZ_LWi+#eX;>p5<>vf+Fax^o{9GwFai-kDgglVHA}tktfPYR5 z(@XXCag5yNtS99|nO?h4Po-krPkUrufBE9Yso0}$8t3N-yE#8^Qbo7n+oaKilLzxo zHj}3>o}8RNJ$#7*L-=eHaGShWs6?ViRR1B($mDhuPu}$NcbOQb*_)yxUJv8TWO&w? zP2kIXcKG}c=PwV$p5XZ2aXL&I2!G(~zHYq!vD-a6yW8w`&$`_Pdq{uZ+1z~nW0QX6 zn_Fpl@^qb3GmTOI9JA4(0l5Z2$>1pGW3Z1L_ZCy^kz*9(r+eb{85o$#d(of)Z3rF^ z-jfR{_Jr(43$+%{Q8%%XWW5|Y`1iUiv*{p$M#dO|Vz0ZBUS(7(s%iMjNPo_ykTca9 zpsX2c+{#vL24Z@Gw((_)l8qHO%K9aYq7{!(44`3mUW-9=;nQmsO7y5tI|Or45Fpy} z4|su_vSOY3kL+U@j@m=5$<;8wY;;%FTcf_i#_(S{0CPe{{_YClG}26ru@_OjAVWH= z{qGK*pPtaS<^_(TS45;_qJMAR*<^S=icx>jIs*+XCpjB1d(qcsdFd=nFiA95nhdQD zLJ9SBIINtOpx>G#5DwlZ=hM7_!_sWU#rZfd()ae7Z~;lZcqCi9+u1kb$w9oHO@?QB zF|A(eZZfl>Z7BBiw9}cjQ0y!8g9KNg)K{cAnS7?WS0uR?X1vsbWPcN_(VKocX-J+y zx)!d#w3wdfZYCte`MtW0tkEZE#m~_Mw*)K}7mBg3n5EvWoQ`M*3 zv5o@ti~l8Fn$dO)?`J|srIP`L3d?+oogY=)NHR_J_8m> z{0zIb+}iN$EH{}SKu3HK&u{|72L!#)`TS7*K@=h7srCOY37tZQ`7}x{CwtahLodYjR4iGpLTK}G>8F4;1G)>b7MK2yFVw{dC ziYVCc^MqbPT{HT-HAzU*#(XpNZnxVtYZBTXAH=`@Jev$Zel0$TpB<_n@r&v4M`y)C z`=rdH-k}H+-+#u^p3B3fubUg<|6}jnx7tXu^wIx+PZ47?g+wdG)n%J5sv84#F=cF; zOV!jMPmz*RkmFRQDl-MfhTrOUIK9?+pz|jEBxmhQTr*MqyAu)BY>`}Pf0fx?g@#=p2vwIw;CX16Su2;7!@NN6?xe+-fHW|n!#0CqW~l0j zB6bI8#q){-)-bhU;k*_i%O2*6c}S)s22m|V8KogEP$-jqd+Xw_jd>ZC6?pzpAzLjm zzsx^@=O6h4F$dP5yv4=;5+N&~ViTB_gMZFpGl2GzVLK8=-5d+*auLfhVT5hSVF5|I z9|5LSuehM&c6;YPH~02m@6faDPG_oo=EE>enH*hfG8FYk?Rdk6l6$?(gw?M0-J0cM z9TzZP#kjj1#Qpge{I&wWHASGu8JwB0Qx3;nC`}EEr-Mp}P3%Z0BgbKqKw?m5-haG3 z+F^aAQY`Dp;h@CO;&Lm@urr`!hA4a-S%e3!a!SdWf2$Xb3iIk^$#@8mjz_r0cl#}8 zGunT{8f+UmFys)0DpfKB8-)M7maLCMyY0{>z#+_X_c;1r)b=mR6fzg zTY3X=`Bac?6c**U2*QsTp=tcBV?}wF`V}-Pd30rK4bJK=D6_z>+S-5U;fJ>5(HXJp zDOD5~kQ7P5@8}8#l>m9SQEKavY+#U6vQkl1#_1pri!vXhQfPP5$KS$apMPu(`$<&3 z06$ZD)@Z(yFsyvQJW5K>S^ljF`9;j}tJEGfQ4@>G4_TghKaE z-o2Z1<-&&eYojR>@$S+lV_(UAUa9!qoFQg5e6qI*zRr!$`~zivxAS^`=RmwXezOHe z?BSQG$7_urK(2puFf*rzYf6Oz&)B|Dy0s*JwDn$K00(P8|OuhP6m5NrFMd@a~G|T82)uk zsYm9s=tVdDunkh27Ds9zWxr_f*MNQ(eJGo4`iB3r+ixQ24fy_pw||)1CW4(0qcH97 zQ#SCGqdc07QR-P5>^G;AQxX=X7PHc0PNPw?0FFyKJ*iPb7ZhIPkwYHJtux`7CZS$p zvv}Nhj*59C%BvBDG3(+G<=)c`nVP%_Cg2PBXKTJGEjV@xRjcP5Bd^K;PjcrG>yFC^ zzE}yukDKzF&Ca7{+kY`55lMxzBJ}x+5Lvh?XV5&8;aS5+)hD@UX4x$aR3DDYD~0?w z;0Iy=yGW8n{MKXS!Ag7`7UkA?m^bWUXxhmiG$c}hPb|e6v!WtHsw9AE$kgd1zi*E#ST&eYnw<_G>CLNJ_DMt9EgI zLUqwuBFn7nBmn2-&2)9+I#|RgiWqs)KB0$xF?jM=UWS-=DXaN^6fe}_q3%jrrM1R@mEXRTTLuoG=_uVltPP)`} zxo*fG#33{zp!STT^U75-*+ovbW9I(jKl*owEK0>xq z>2u>8Vt@BKk3KEk*nCf)mTwki@x@=lQ5*oU6+{58EUl~r%LG*|f`OQmCoH1J%8&D; zCA=L|J9u=c3E#Q!{n_gt^fzIk6DoPRTMdf+c7q51X zL~xwP*jwASR4)S`2F5I0%K)yIc{U9GqsY=`n}0#FP>6q-6VKk}?i)dpTkQPj&ekyr z@Go=hA=1Fe3c)n|KoIOHuRc2I9L8X7;^N-dcb~uuRc51kebE5{ePuS%@CZmrm|jsu zopkO8B4Bh1f#YYHT*2_i={SM{AJ>vL!kX^^)=iX~FbqU4h8dr5q&+7OlNJ@yn_#UV zDu1$*&h?6m@9+&y#D(pkd`pgNsp45ujwREhWI2>7{v-|(+D&6{qQ@U~@8G13a!2=~ z@HFrm{9*x~%Ox`|`~i_Z!Z@^3HLsY9lDC^AgyFr47se_TkdKh`sKGdggmUb6Ns*j} zWaMU2TB6xl-AY8V4C3;CV?thEM{7Op3|-p7RD@- zUO~Q33`Rr!?-6Qq@EP6;qMwKRlxKMINBhU>mvI)Vx7l81`3}60Dt|0CUqX&G~0CsPj$AOTRc6}ET}LbK^+*aQRg{w z{Wa4jO4e>Ib89&(SC@B@0FOl2J8#VC)o+iQb;^58Ji=-|Q05Nf0?j6JytoG*el1h( zXv47`r?9+}sEi0k(Z8)_De<8Gyv%R34ZE``f-DzP-!M&6`=|{+J=U)JQ-8%sBxjy2 zGh`OBo1aI$Ebr4G+54E6hAu!3ImEN=A8z4I5-rSke|4IqJb3bF!xlu!gC}Z#9^K$dUfr36_|t~^L%F!vSYcfcb_ti^`V~-FmzlabB4};+CU}#Pk$=i~yO$7?0jv2+ zT;^FBNqbiCMMpO}i#a4jw@n?sjqQyxWcx|f#Yw7)Lq8mdENK{h*&K3f>u4|{)uzYu=w&arEg3$d7Y zwzAPx9-p0;qS0##MSmYDwz7PbQSdZeoJxGSJ_TOk4Dan8iG)5z_m(gA4dZlxkS+vk zoW%JLdjcD)r-@^$&{^~g`!iwc0Ki&NTpoUZY}s6VKT1Vm20vk(Rqe7o0`1D#A->3? z+l19QeIV$7+3Qt-bW}w(Rzo@rf#F%<*()cY>G}%0*|^m4S$}-EGn;i$v_%pRW8j&| za%l7*9L5PCH0c?xzR`J%H1RF>-NhOWuKis&o zff*)A7ip~FDu30gD#^0<}oqw~$HD z<2S_X%68yPCB~%`J!!=WktEs#iWQ;*H{z*uHK4V zd@|pv%0Lk)v1f`RC5f7oLsg{`fD9!0nUs{Q0jEfoTXf4^*&^U|A=aFb+r2A%cTxs5dCRt;eUZh-j`sjUbVzw{4ru ztmEGgB<7@gkN^I{fub{*8#Q5~uvKJi=zqPM;F=6I73#hHS!(?P5wdq`kI!s?dooB< z$}ZC+3;Q0s0q&PPLA0h-f~8BK^ImUQlvy60MWa0Hx4TK!ZTGS~YG1}_Kf5g2X#}|E z5T4PCiuhwhIJKxw128}q<6?j(aC#MF&|Q0M8534y%ny5lcQ(1Ps~vQ#6Pi(WA%EVr zJ#Ul|;V~IJsc1&4&=7eyR}to_vO6|ut7;6C85mw|A@%v*gj~2B5dhf z`LIwjVdj84OQ-q|9n=KS^4#KL2ZO6-a^x|PON5I=_W)+ltIx4?gnyCa`-mU* zwv5jzSD%imf;$;yBv-3)BgR1474OGj3z3$yFDV*Udn%#tD(HPPA0AREA~>cQ^j##I zkEL0e#P7lUT_}D@7CMi_P1Ahf+HQ$c7`*Pe#rzR+G7m?P9Y6PT)4b?#al{*{+upDY z`2$gnmk9A?9fUcA5NOnt$A8h7MZEv;t`;db`ry{LThNqi-*Q!%6`NJa&|q1Hx_g2D z^bq8xvSJxG*zFE%=!h;Fer_ua@ir?0gGa1d&P!%&lTI=aY09R-_FD!E#VX0dbPR<| z8lqRsXv9RYQR9hq9Lkbe`&d=+MdkeBe3L?^&3dnlPh;n!&XbAvKP#PTm?X~UBMggIUWbq&a4V~ez;|{lqi`#E~ zUDF?Y<4@f))5GZ3onu356xg963vhqJ=ZbT(KiqX&~&D(GYQ`4zG$b8n(AILS7r;UE*FF((_Izz2V)v_4PEml$c#} z45!t3wCIG5FWoG%A3HA=C-{jxA?3@#((+eKaNU=|okv%rXv5i3U&+0)@oD*ngV0^i zk<C3pA#QmaLdh$o2t%xiGLS^z=2`416?Mcza6;8r?kUv z$<+0wbM&BnP&)<#+ND&-*0hgnp0~ze`t!53(rU!X(mP%W_bJk9r!KOxxco7WmBn9? zf9=hFzcDRRQT|Ml`LLb*{r8t;m`~N84WVb;|2ip@njhHN-f^pzb+` zmqq_a&4vGB8R(xkzx+N4+LK~#W)LV=$}7Tc$ih^brD%XCl~D`)0*?lqBPg!~PpHX-L_6SP=Xu;owN-Ps&a^cQpSAvrBdaDrGMSG(*upFt3-8ulFZVfQ(k$cyr({+ zjjn{@6hWq&+`01tP=4VF`H3nfNWs|w=L&v8edDq2lyK9plV7E&Ui<9n|I@SnaqXcv z@IWn1%7C)d(k(4khdWTs@<%YnaWD2^F;bBg1c0f@{~Yd70|WU-#sau|?!PC?zmnfi zMSo68^8aE9?ABg}yfO^JhjPimWv^>%Qru!6-7_Wr^JTl=E+O^qiSU&i$=@W~-6OM9 zl$IyPy%OeqJFF52yU{iqD#}rm!!j{K+@0J2u7z;#oI1?wSYN(C(SlA;^9w-!E;JQ- zW!uW3^yCUC&#u$J4Xng*d!@X0h|Py!#{o3*o{|I9JS=y9;KbRZQ(A zv(*yNzL)`4d$CNo8+`JwiNjPD7<>q~9+pq? zRcKHX&5BXQDpFDpZ=({EWjLQ)XMgc6a{hf1)tXdQ*2KVpioxU-G)q=T- z5jY0Z{#KS`x%er98@!5-vSz(l>F~<3F}zCEt3=yBZ(t(n8xcDh9)5IG%zAYPL7YJ) znYjs{`vPLHIO{K3NU)}5poBJ3rACr{bA7d>v^lUw6zZ3kIncQeSZowaBF-^ z-gi>eH%@d`ys)pG=FOR^>!WLm@I ze0;t}$^GWZ6>do959Cv^U~xnW{GjBZU?*$ltflPQ5;K|{@~5V^ipbOPQ&l`u{?}m_ zH0HqDu=Hm!7bDat^@hPm;nP3;sdlh+?@#99cP`RJqh8*+>mN71fnrG8U6p*(w9zvB zt?_J;8Fvi>%4kWU4u9_CD)Y>FI0k+{mWZ=n&dv-c<9~eyjF{;!)*`?7U-dz_RO5cl z9~M~pXG3pW+!GjEP14So1DV%<<)DphU#!X^FShm}BDQAw;l|tg05TAa?dZM7ek=}6 zji_pMg1l=hb#u7@E$}6zJ(!q-l{$Ysj}Tf5H8G zHs9E`t&Z)EZ6_VuwsUj7Q+4n6^H$BOwW{{tU3;%J$1~;7v zE?uF(etQ2|BtUy~J8+;4|3)Bm0;dbpIvj*m#VHHYP`O9{7AIp!IaNO_>L-l5+*ji( zCupI2Dv(m3$>&oo?MbqFzX>ra?4}=Z7dWK&QJUcu`x5E$%%F_=io$`DC52S(L?{$4d_Ro-|Ya6{WIb1@RtX_d#a&QQ1-g zp~FmT>&>R7WfYywcqF&8E}6S?%J1y|ydBO2=l(18CziW1L6>Ppm^4h^R4B(EV>IJw zOPMqim#M=ydl_efvjEoUC{WZDe{AqFqm>volG`F)LjJ0nhf?2e5zoU^V zj8AV5yWNiwLo61)*qa!c*LI4(XU^9A99)}uaw4<-Ereug-kGfiJts0mtMsQG)@*L- z^+fedr#Tw4TOyTVftj@TAd&<>u*H*(V>OtcDazL~U=go0BM9V3RIxC@T8IPiEkcLK znCNDOl2^s4jo4mzN+G>7_nJ{fI*xVnP6{ zK6b>_RaKjd4CY#%Q@s9N%_Kh9@@7Z;r+@xc*lNIv=rkTM7}7 z26Pv)In32p3se(Y53}YoZBu8Z=s;PxG{%{{Z-AV|yiaJTkc1aU#M`nxl-HaDUENS^gH581H7iKwib-$y{v_sVX04VXJOQ82{B|rneDmfMlp%<8I zt92fFANGa(JvLo;p({bub&a^9oqxC(HJ1G)Ki~ zU4ZrQs7l_Nfxa{Cd>6xh!CH);4%TNcl7Z_%|McXl5`gEdY1|mtGl|7K(FmT+%83e^@LSY`w!a+*fEyIZfs(G$Wqa z4JhBV+I1e+T1?}5YN_Yo0rK;tyJoaL7yt$T4Rl6JnWI-jvud{HBptk(KgTYCq@PY& z#Gx}RNz##!K`sFQ1cGZ4t8Cjo`^uAinV(CeY*k~1&ymyS89kTI3fb`oDd&hLs>G5` zu){^kJB;~PasO)HY-FT-f_;SvSXfKzPxn$(%|-%LLm7Q!Q0elmVeS;mH)&!-ybilX%UarWdrxBjG@5kXk0xhm^1kyjb=| zDtlJr1lG+nhex7z6h}xD134LX^k7Yes3#ek75g#90KEjkz?ISwu`RB|kDGtP_ufkP z@htw$9yr>d0kHK&Oy+ZA?Ns(Iy-OqeL9eVf(Y?pQ4qw93SWQZo zI-WUQMtt6SUaskaTJ<7@Bv09#j}B34mIq#Xk~bnrs7`fg*}{WwOwHIUOrZ#5s5h=%m{yx| z^zDpm&_k`f)r@hwW~ZqGn%wF);10(h9{NuV&7f$K#IP*@2~q)U0!kFFcW}0evn5nb z3(Gmw#b%$lcbrp6?+hM11aL`WsE$y&e12xb-I$vGY9UottQl9T59Z=c8zBID)zX>` zd18y{m8HsU{Mfbi37_BgClr$G>Zb%iP+HgEd9SRFp<RF_ccY^B1Nw z_Hd{*Uat1VH~PTjcx-;451bnx=;UpwP(XAt)^+{6mK!jqmJ47A<~ah`eA!8>ygLVU zO=N|upwln^AH~_a3vB)YK%9PwZq@DqP+W0x0`J70Jg8ah16fFj@#n_~Z%8o}fYfx6 zW))S{)S7ZyMdKqH+ALb)?mXI(o)r7a6`34Hbh;i6^)VTJ#r8^$7wX69kRB}o7N>L^ zqDXM?cnt>Gl#8E4sNbOed#Z!=e@6FUnlFI0KK@&A2=sFO3fE_y1Cep}FYWqOD0*;MJShH;6Oy+JzQkD_`YlKjqmor(9;}5K?ns3fsR3j02h~dM!j6p+0h{` z_}TA-cw@RS3J=NWEfaDDGdp>JZ^$9SC(>)E(mvt1(JrV@sVWz>^I-M0r_VO7CIaQspYzAjzVc*j38oXpG0!BA(d-G;YF4e zyk)(@1p%1kFU;pZd>Ey;GNP8uq45lWXG%-#m2_ntX1CzF;3tXZHy6tV#+m|I(QhIl0B5=C-vHE$TetsT89 z2^&4>QtYGQ1EO*3{Nwx<|3tf3S-WYx#5H@*kB;6tT3K0(Y+@W?iM}Zqtepby2w-Jsu|9EVL0ea*jQJRIfC`V91=Do1DW4>JRCH1 z(12}Np$3dm0dqVuAeNmgL9_wTEE+{4Ys)Y))H3N}+W@--Ns92&oNi+BT#V}d8_?>9 zW)WwNuS!7~DR866d!slxE)l?w(PI+FAozJY^=#gT9eBtKp@Ct&&{tx&k#=jk#EyqS zBEArLPafDvb{^;(JLZH{dStUG0HqrGYWr&<5xTFi2c$Aog8Velr%?xBvd4l#J;}yd zKF^9m=j6tZgO=JrG|?FT(8uq7CbQ;qs2x~Zvv9@_WLYA^I^JZ z%lq6r{8zfdi|wk)#~dOrrF((KANtt~|3yY~aH3gQ9W>bB{!H@S1(;?z* zLZs-SI~C`1GoVKRjPz}o=nS}5lRYealQQ#Q4IqWWec&p^VbGWcX%AL#X&}4U#c*jp zyLMv~hqKWOeh`ceAl0E8s=<5cZJ^GS-+(@v5ROB5SlN^y31k7eMk1 z4kKH+y$M06W;GGqeW2mK2nDh3>6tj0*R}ApZeMPtZ#_7GlGybAKcrV875mykh-BP7 z7!k4Z`QJEj+!`15(|Pw<^T!`j7hHLHyd%71zJ6DDye^*=i(Jp<)2|mP8$q1r6qS8G zuLt-!T{7Q5+M$WCWv0%4P1jP>N!t$v&Q&wRJ(y7b4ZnvY1>3H!r47V( zvSNd}a7+#+-{@hNoq?YHV*45KQwc;e-lruZWS<1NMAU(0AW7-nRQc48h*ZMUE*WK1 z^7?+9>}invYRo(?(_ll0W$LFZjtxMQWArs)__4S19x?aD3rw#Ume&!9lVCahnO(vg z5pK>OwF?%K@BU4VP`?*0G@PE#DG`ks{GMPH#H1s2adp|l$GPU?+@uFRLo=AwDuL1t zBHT>HD7U;V+pzWCvg%0Eov(nvS*2qqK`1V{5k*X)$TgL7!hnsY1Ap0pstAzpm&i+V zy&i8&xZl!Lsc1`Bb6-Mzn$Qm=48N1ZLLB;)Gl*d#JNFkm=nO(y;0mtpnVnDWjc*3% zoap`?1r1n4Ql*3%#g$jgy@=ZAQ_HYCOH`@Y zo*y$Sp^YbJ&R)=ztkNf+*$a@*{ICMJaBGS9*g5D$!* z7LdLod8?hy_GVSy_s~Z0@^r!r!Y4>*K;i~BG|p3iV(=$o5DYENmgJ*q?AiW}%66wOwt;J9~-F_v@Ws3d$v$qhtW-nOT)We{TFo z{TL=5+!5b?wuwPij_GCxg8q#7Bs|6eS_WE>EW$~?HpM}fdaU6mf!FIOL;of8Yq>9; z53GD!*`B?Ta0{vte1?a9l!_e4C_a$(Rmq+xr#f`ToLUn<%#P5)FK*tB4GdUVbhR|T z$u&(44ayxHG&!VgC1C&#=5fky3m+dJexEgXS7_c1EHFAT$i`IN?&pBI z!ODR;9kZ$8Y(Bb8e5iOtBifoHlw^p5*qE`5tQl)-DYbU+F_w+rMpIspms&xtZwQ0F zAURl=05~+Ep58#(qsOP92#BcxegIdx{MrPdkkfDkGQTDKeHgGH5OA0SAJ!zfv&j(M zm2hjw2;y7+6CytnN4RnW6fqpYKmflP0v^UN$-#<&AxfkNk{EKF&nB|B*bkC~*$XjP zP(#Nhg=Wn)u#*{~kmG-+*Xse-fH&?1--w3x7pc9md`O|Pk;Dp#*LBZ=K(A$H@6Klf zoQWVc;8Kr62M-{%+A?%w%!mg+;Nplie5!)LiDkpYPEJQv`s9^&TC67?Nlk`JQFS{m znhFp9Fv~Vd=Ma4}Y8M{a2vt65CvWT~0n@m?khU4nL05NjgIB?rB!;oPOk8r3KwsZo z2b8BLjd{^*ORWJ2tm;f10LU_|T08XVb^a_1;L-prfIbZ--Dl|VfGg!+gqLI3uX)MZ z^~;twLi)UOtHFcjMvPkKy92NG=6S8Z-Fh8*dRk5sd*J0T>purx=gxjLRYOKZMzxK8 zJz+!I6^F`U)484o!E|e#my=>*6lCV;{-$0@#KHc+Y*!>!fq<gy)I#R+6Hjl) z^44rNfr+!mI;Wk}G*7$|U+hpY+&dB!^INgx#I;6wPlZSwJFRjYf5r!>7+Bu?foz;e z>c|#%Mj5XiAkzYYp3Z>iVW7Q{@d zs9C$mKgP$FmZ=Goc!j>;iSS8$R|UayUVq9rL}~;_sEVnbr_ZrUcfw^%-Z35eY+iE+lr6L99p|z4%`IaDwq-!*^!e#G$ul>zGpw%svX$_*( zcut|gZY4|dZ*Hw5{3AZWiXkQhA6wXu6lSl$S?g%VV`Ptnd4j>(Gr;4E=1>Xprn{}z zTD8DU%Dc31PqKFR)`5P|&A!u=2<-~vg9t4j3PspZTu8)D{Jq$UhZrZ-nL3fjUF^RD94OeDpvzN3hzUYO7_ z==Vm2()&B!zNe@p(cx>oaXTp8OW_a-*;zeoY32*>F zVL<2qg%L^0W?MuWWQPETJ0`Ik#27R=3?{0npE-CkqZ1V~5#eGA{gwEx@NdvzVQ5EJ zEy}cS)o?*NGN-0vAK4R(($!Fi?L)gG0-wvj5j*6$*y?^99~aSI21n5=Ar5b|?FK^! zpt^a*61d>nbMH`>0H1b@^@dVr&YKC?fD$qD&rR4d1l}Ny@=Fd@4>=J(B-fdij1;ml z!Rce#ajjkJSUtO^!tOI?WHpcqyH(iX^{TAe&%uacj~X`GL zQ^Vj`TUW%1juQJTk0C;3Qy;OS0y!s!r~Br=Xdr?cp$)#p(U%MK;_%8#Pjd+fh+5Di z5TZ#mv2JB2BOJA6P}xQ6Z7Yd}aVC+6B2mY*?`U-CD(6yWJA5IoxP%HMnGO3T*Pl(& zZ6Ja3D=>&klopF;3qLPH=!3W+IMuVVok6bL;~`@%jAX~r&emZZx(iG=!FjO_>h=>-VgExvd|Mi2=X09NCNiuA zA%u3`0#mi&CSK$|!S)6Vu<=rtH*Wm?5kHT5J-+pqif!p-^(Ol;l4)$8{8rSEf8DkG za+!~W9&NR=ro?M6V{Z!;9$z^i|AOZI9?g>)px@J>bJCXYS<9$O+fo4`0-VolZA$Sp zO_(6Fy0Ko-?KfS|*5C@qlY>h3Yv)7q$e|}418J5PR~U`;laBfYxYF+Fc!NfF=!QY9 zqY*;K@{WJtv5;mb@}$xyNB41zB9HHxga788!!PO zrDKp&A8+)JR=8JIddrD#F6F!$*e@s*UrEG;v&8RpDVu>><&*Q8>LGElM7+s&T%~<5 z$w}p^N67HNG%}{30G4h9Lbe2gcEO02EyaAEBNT0+qOu`oAgAW#uHxFg>yJ`)SA1*x ztQ5UzdS>G(SM?OLC08w%o7t9?2B-7RbLa5D5)`~q24&5ik`Py=KirE_4TnP$ofNl& z0q8G}UQj0K|L`s&E?(%tKjFSM8CV#wi33+xr}@T>v(bBix4x$ndcO${Y!sn!d-=;y zl6usCSHFntDRkRkSiD^aX2mnYUA8}*h)}jKySBEukQn2(Z2}ngZ=`o6WDeLWui!_3 znh`znk+h5T4H^c7FFSCyqscsOF;$H(lu-rqNDDv|35>8+%Gn}c7xOo#l@#|1%8VX@ zlyhaiQhjLvrt48Jm8}hizmyY!Qq8oxl8e3fm446)*LaB?LQ@3nsT8enN1Sh#SQknP zHc1;fdr5hg2u{>>b=e{oM{L`U)8Wdt5jqDViNf4>$uQ4`fnGEZ%+e7_dGlAS?n!De8o z&U28Ppe9?lQq*>Pp~s`wTD+ zS|ET4Giq2(2lt4&j8zlZ?y;aEdni&>ruimw+mLt>FRb@51Vx5YqKIaJ%rb}eEI%H( zW5k0ErK>)ZR2CE%(o*K-W~#2p80TEfo`Lm}=<7d-q{#lp_Z=j`U{9fcb3`2Eu*~#1 zslOZ9I6u~{*GHlQ#n8u$#11dl_Dx03?STQekG5i=HK&LSOr=-Nr_p7xVy9Z*OQ3Z> zz=|1u9A1T~P=@&^Dk zaO`zm%}<|xBjrX$DV4MvhO|b7FV5A(!tPZ3EM`#qPpTwPLDD21?v!RMYi4}9Ue*%{ z=VQ;}et_i+{ST)Svio07<j!3U4&Ivf!-mZEh7Gh zozyJMU#dCJD2#Whx;WS_WRZ?v6r0wt@JB*S6V@X%5imnyb2pBh#S?Z8Z)gv)+TIAWuYqcKm($F?YZ4A zYlywdLJKCZb;!}|ohhpq$f3_~DIlvXp45<@cSn#}hYd%K$|>m&J=%a+BMqZF|IaQEEWzS-I-?Ex6n9_exf z@S=u9Q}2{#p*2y7>|>-v_9*r|z5;)0unv~C_FuP({l+SHt=ddoc;r9fW2k`3hw2kv zEs84N?p65zajeMpZ?;ZeapK2F2X4-%{_>-$bb^>-#m;5-QSnXmHcQ>??`4Z7I3C{v z7639t+$YlrCVHc%p|X7RkrGK{R*e0&?#}mM2|CE&lI;)0{>0|Y^afRABkRFV^kVg>)Z$q;*ZO*~sk!2o*T^Tna(7SCUQ-_B z&cU}yRc56r+3O`RjLWm(8p9A!An|+zzYQBJ(H`dOQ<|$O|K(UXs}OyBv2bP17_ZGV z@8;%S<>D2t1(mp5s19ZXw5cXNWu^~O{VTu^*Q!uQ8CKGw-}?<;^cffsu_UA-%rKE>C+R1$6Y9;1tF%0s^G&yjNJD)t!`T(ohF|l?C=$+>dQ1-;hYM}pa zZAi|4cudc5ht>$jmzL$1Yeax=qt5wr(T43TI#5=EJF?W|(^y{IHj>kXLRS#LDku-h zopiEHBru(nnpds$_`4Fx{akoWkRV6G5?SA3!xf&WTn!(LrMO0U%xTYKz-K5L204R0j1 z%cbEH%kCC?GGW2)K&4ka#%KhxNV7iZhWH$^2jD9}^8n1np_47a;{ED34(Lco0A z3N@nY*mlERa6CRc#d05E>r>kM>@+KcC#Dblv{aW%5rr8Au=R9EJY{B2D#u96o{IDs zQ7uuk%6>{@PCow0gU1${Pl|C?Oir#5E$KrJQ*!a&VCdaI6- zA=1Nxp1MXnQC)`d`F$sACU6pnAiF(&Kx`pT2s%6)np9ZRZ^M3EI@4s#L`TR0AAf@# zAXg`U(RTzI(si>NlN$vjN5V}z={_AlvvH_Ph8h#eBZDsCV(BgqdK8bh^^8&cn-P5F-;C^@ zfa?VSCN<+Xvdfv1*{wKpKV2-o6u27$&i&3PIJ7NGECxZxo{hP1H?r2WoMa^xB(=N0 zDpEN)TnYa*s#vvAYPsb|{F-vpwN2u&w-tbw1}VkWa;cev)WqWphi!$O=Yh^h6jJj6 zT$CxZKPlW$c%$kHi?^QeS`EbZLvXP#VI?mmR_5_yFdEA-tC$PtEO2_h?xNw)bvYyf zEUx})O;!|LuzQHPEkrTJ4K&%X{X=>GT7A#iXB2(X;ya$kX=^uao%%F;e!F=$CJHpF ztC5-^uV-`7wi~om*G020`#RwD8oaSW?uv3>go|fPdej*3otig3z=(i!`JIe$fu?!J zoE8JIIN$nae`da$S3?5KRxFR|G^UXW@PKm8z`!r!n`Calh_QB^w8$RK%iOXW-{-l- zTe-vC4qQyn?V${EP!#d$aYTl z>HY37_EXc(I}}R>y^6Xi_*Ny~h^A0SMVutWfd8STVCgnc(>H{ihSEV}v}4}@s=8G6 z|KX*8WuQ<}thk}u<&F@GX|dPmaFOmcMEV09l$yCUDVkH>sB)3>-M5~bs+2*>i}+hK zR!d~S;)ntbV-uz`;p|lBz&U3Atp~&l%qtTQIw15(DjdaPBZkrb0 zg}@M?YV#9Q`LJ0g1C;Ok#qks?kHCyiOs?Ns64^yR7vF%oR>BA#$MTyXu!wk$^er5@ zok2E!^~$A-Eijisg8@%T&Aw1NAZ*qFNJu-835mfpQPj{spUE}laEk8KxutC3yb7gr z{oMVw_7&w?hh%Uj@81VN74VSTf#DWwetnqN^qDe!WboI*gD%EX<%RyQDs?O#zZZ{tZ7MJE|ULEezz{pb9bg zt=!*71B;MhFiiY~35Y)(*&7ooj2;Wfm$jl3QrQ`CTG?p)JyV;BNuMvX74h)Sv7U2%7}_gG8}UCER-=#N(iv@ zC^%@}=&*ru!h!xNXTTLQNfl zr(lS#VcGfse7BwfN%((^^h7PeJWUc&lAk|q1-ioe;Rwd(+rOs4N2OEL*zLdZX9C7*-Jz4tNYZO&nevz4oITC<20oz&MoyQrp zA5t6CCWqVUjmkvRCJ;m2W2vxp8hXt_U6DYxJFH>>!T?hn-uSMMB;uT5BBOq(pvVyn zzCX#&Tplg-E&XVss^tU*U%EE|-i4=FP|ExFZUnC^F75D9I#fw;Xi*cimDcjzes3}a z8#}%{NXq=ky^PZWH?Q|4hbb^md*^iC-y|1*x8v?Ojnx<2z0Aa4>apJ;jIU+r+;1SE zaQ7YnHu(kg<7Ml+s&oDN>S+(x`uo=iQpH|dmOF~ch^LA~F5%KTj;6_omDU^Uv7d)| zqQ;s!Vuo8b5uZyxd-R{I52U5QpM94?Sdx1K)TFBOv1CBUq8a0$6_9LG$MNRA+hY5c zPWtz)$^-BUvb*}bv&*I3Ir>9V`)IFbK0po32VNNt?qNc}Q{2e&D8Zq%fDfxuI%Ten zo}-xd84F1%h^?V@9wfuRps^P*j)mFZTK2%iX{~EI0ExGpLb26rMoa$=e1W8m(a10( zj*rNak&b#bo#eiv*Y{&3yS>=Q-}a1s<7YYqzPPEeo+RY&%DGC3FEJF;?oui9SAZ>4 zV_Qa6UC#%qN^8%XvMyg+?5`7K2)``c(aErYU5=F!&P>W)Z z)85xgV2L^R)pn*cv-z)D@}qoWPJr6&@EB(t_CCmP>`cK<*!m4AulUeI%q9ZnO zVm!jhb+Plea($X>OzAmA%1Y$1*Jb@j*>Y|?@rUN5?qY3EEz6v zThQjgRKL4;gY}_CHUrc`Ez0nvKk$FF;U0Vw z_wclvqf>rpA21Fmjoc<J}Kh+<6tP%!dc=WD+@w0pOPd2jA%1uuailfEAoOCv6h%A{jh*lZP&g*=O}-gGI?K#6`qpR||&#R?Xq2l~zGiNsUf@dhPh2}FW*k*Fg0 zbQr?1cXN1l-tSaGGE2}n{ZMcp#zK(aGg6XVoU(>=bmeSB;joj#%NL~d(R)&WaCCeg zGH2ydoKg6&viM^=Bnjx*;tV><-yeq^e_*(#=)krm)Q3F~4d0&)+IUWzJt9K%qHJ~P z{7-Z{*=i%tRq5!0+0;h7c%PRX80f;S>jy+2sE639zUtNG{8l%B_ayE#vm`f+tZ&-9 zKF27g1=OGi9P}Dp$O@vip3OZ0=^(Dy9tx^|78loQeuu@HcWzY^c132(CAamr?}|ay zWUkG3sw>%`!h=(pI$N%xbMc8Rlf6E`>1Nck*a$!&R)BdIVRFIDiZc@k6XX#nQnV+K z!VV>R?Jq~WRuLpa=yWVfL1z$fp`kUAraSy3#kh!+ceCFfS*JEiMEb?iBS$t zl}a>-95V~(j=y%2SQ$FC{SeN(Ky-WmRi;vv z^WbzwmXQTGb6S}VH25Hey2XaWXoMEU|aoB1Hh&P%0L%-im^GS5zJB7q#F zY5b-IvjZn~Ty*g==Y#23Z?yaMNMK`l(?D&@GQ=A8oeXzn)x^&Mu&~Ks)&7}Lk>ugR zMVu0_u^(KUw3<2-ob?WF+{mZMj99~3YXpu-1Svy>1GCZ?5t6ccyX(H1juDQ#{%e#G zF1D>$6i_DUgqb=Oxd$ra)DF*x0*KWf$UpCWr)qTeXEXMq> zI0C6>;1D0qQ+#U65mZ#R%o`lFsYp)Dc%8xkCplqQ3xgSe(?W@MGaxw(XeL8C7nt|b z0()6&iC1*E=*+R%6#Hezk;Ve_tcbOznJP|omA$ZV@(^2P$p7|~;CBCaD60ju`AI9* zb-mLKF;FGS5kw)<4wlZZ_KR}PL3RYZtDd*WrqOuWyjlDCRPR@cTO}@elAZW>a_Cie zcS!rgOPC74tv*48u)n#eCknIZl7qRNpNtp#E^Tiggg`py+@&&ZPjr!wo0l0$7{ibI z@m;6pfe;cifM<$vc#bp5+1PxwnHXI%?q(Q(JrQrZZ^s*S5Vq zfo=CH?*ZtnCnha%bnB+#lIq*3=p(eMJ#b>33#f$T&Rzejp zn5-?L^vn`J6t1+$@yBJt1W*6^W*mC>1tBMKcEk}zT{lRt#@{qJ#Z@FGOM0UM4%Cozi`6+dwjG7A@2j1 zu1d5or+@kF^KxHFrOU|<5fDODl}~$|9y+#}Y1jYeg!a58qHzhMVnxqriT(3Y9`@Y0 zmiR+8Zn20~#7tGVRt>hN$%ug7;dMBTY*Ny%I*wAy)N(sM zyDiDctuW3U;-s9mh1~*d694 zWS4=xuB1>xSz$eH$|ows_5~q{*^HOr_=|rY57i$O@#GL_Q!}*9@Xu>!8s?X16%~SS z?v54mJ)M@wKLZv*^e)S+I+#opGl4G5PzyYAa^{xwp+y34QDwq^#AU+i=w20XOj2TH zPz~IhL9DD)8xJgwkc50MB6tJDT*P#_! z?P2(+q)>V&Z&1EpIT(n{9bG^+s<>`86CEn#&<}OBVq~A4?AY5l!*Za7Czn7Xh(UH( z9Rm@Og7=elL+~?vxZYqZ^C{(D*H24Cf_yE8^{M zMN+CFdKQM+D*<1-0~H8JXKTZ)^?e5QI4H)2*BJ;83>j|*!ze39JWu_&hlM4I;;R_S ztk~nlrQ8vOSDtf#fRwuokM_PXa*nD&v}$ebZb{8wEP%jjW&M@kn3{t~-ZLiZfl=^H z@}>YnL^IDi;OmN)TcW855^SL&tc6tI*GCS7I0vjjc^lsdcIgbjAOKTL{Y@$gQqh19 z(z4;{;}(lKjLafDKn@kiQizajE}>$&kGAxAdTMzqJuk@zi8SZI`W?eEWzg!&vyCz# zJtd%B_~znysA8qMA}O#_n`P@LmO&P!O06qu4r!rF{DzIi zGla#;3Wftn1pZ4x)Uo4(mEt&4j|>H>OPC?Zu%n3>ez1!I^YuQ{^BuI=4Yv;7b%i}U z$x4pzlOep_qIWHo##0ikahZqo66otD%25NPm4w9NMK3y$)_wtKm?*-lfy2)ySa8@ z7cbHHd>zB{5LhF{48E@<|8wcIh+n!4-a+psRuO}lCZi(s^?3U`Ak;SI7fow7(3oqa zX-iM^#4UZ0n>nM6g416!ddK^7bi4F;vB-9*LV48IC{Z-Xm5P}?%u$XUPDW7 z@#zbIOz2s6HX<{*m9X?BsJN!G;^YneCC|q?@AgvUni0S1c~GAhbG-`%<&O@e6U^v z0XN@Oyk~-k_rnb|4n*R)WPC{luu5Lc&`UCA`Eya9pA+*{oe3N`*AwXb{yZ8+@z$~c zt2F&vX*~%)Q_j3K^JYCaZ%~5E3$5hV{Ra3&>N%3?tuvDA26UKAp)85s>vAf>9lmflY|L!&4Nh_Z# z@AZ0K(rn(?rF;LmP$vIJTN?1|+5!^v3{)ilM6trQUW;WR?{C47O0s%H?iBJyaAk(* zIbMG2%{%#rOojd<^A#?+;NgnP=^tCT9?=HVP}&qV^Hix6@<@7h`Sd9ubz*%^(9+f6 zZ}j_)N1_wSZcM2i%==~Sp?79OSxnRPH1NnL&p%}cMR*&ey-erseKLSme|N2_^P37=J>&#j3`RCMnu=K(s5 zp}YBor84V@8MWm_D3bTiTsLoOx@~9b*}*r);HHarld(HodZ0sBqKuFRvyRfllDtF5 z9vVFps-%+Q-z8VTXc+*SXfVqOFUTIB{>sJYL_R)uD#0n$sZKV`Q;*dcr*V%(UC=?8 z3LwHnPf4u?E!@9^k3>pxORR7Lg9EoWgZxTovR_iVmw?8liD^P(j52Fx}~LkIAL<~1A}W~tazjF!Ky<{^sQ_z`PD6Z6F_X1 z%}D_rZ8&{v+S9*vRN`E~*t%&K?C3FrwUWBkO|M%L)xxcuJd@9c`rQ1@TfNKSxeC0 zW5n7X0^fo3Kq6915m|2b0e0v9k{TbPDf#xPLt$`N4=VfHOr>!y02_3LI(t56_0rWk z4_MR1eW3*yIGSKW66;{~sd_?o6Hg*N%T+wu?Fv_S{RtbWDLZo1 zv&5&*zExk|fJClEbDwSG<&RomV%AqT#hJURxW8T-4}F63-qwya)L6d;ng?35beqhFI|a%88fL)p_9>-q2&yycPm zg~#XN&YH#ZczV57d0Mrz-d$5nhbUcEQ0!9n%5(3`pKaY^Vf;EwJu!i)enjqw4c`-2 zLlF&N@4CatHq=?9|C}qGc#S2nymaVJ`lZDaetp1a_I-27H-bKMBeS)i*gkFxAG$+nrxkfSoyZ?xIw|^P zMEh0Yf4?q|1svaWXY6lq#pCx6P5pM?YY0u5WWF~1)!EB_c#nn95Y5g=TO*WC29yVI z-syB}5E0uQKNe>#&$!UMj#nNCmpj_t`XnS((;TKA*aRno4Mw_o0nj8&uyr6rhagLR zi~@-UA5#xO1RHZf~^A-R;YTIfURY* zzRaXuMtqUbZ~PP^Pe6;Ii0Gs^;F18e$P~z5n-iqJ>w-|8I9gjoGs5^Zx{49@@H6q#UyLPqYUhFYDs@ z{l0->zakL63?WQ#XR$@OI)?(Wa3U)S(BXmALJXY)J%V`!bvh<~pixOUJQs%Meu>|F zMQm<5wfyv2?2q#i z(7|1c@1ra6R)d6i0X>{#Qv*B|_e)6Y8o?iNC|q>9YvLA!z$&7nYjH=bPnzZOdJk~D zW9b&Eo`UVW77}2{v$F`PsU;5H?%JjE?!j_jxT6m}p?q|;$t(l9d#h^@N{vbN- zM)|?BN6qe?M}R-smvah8>TkD>5A_^_o*KkS(h`>$e*zo<)0Z}X0wOhs-Z?}~EE1fd zJ9=`32T~XYaQ=m@%N?#rOR(F95ttu#iwX#cw|RqPQKAPXc^-!?aemd!myLe{8-I4g z1V#vVZ_GKqd0f1=3mt~N9+rp#*|(>!#S2+dKkDVUC}G>gNmP_TT&ABi3ziZ+P*F8l z4IUb-#oVVP*a7GUfEOijYAWi96@5QJli9z*&{*+CeRI zfh<`1IkgZ6U=YYG6{;*?+BS*x!P&eE3zDZ3)YHO(I7YMiIiWxv9lZwqkN~uldJ4fl z40%OzNTnbvn7n@08><7&x;Qn`-7MkV9`;WaM7L`eV4t^f^@z%%IEzx$9)IZ>XKCVr z_hXc2cpgZykg1#6Vpp-v@t$nabFe|$?zo;A`HaCYW+s)egTyw>ATd7vEW)9=m{(64 zF}d)~VF`_ZH;>b>EJKjb@URRGqmW)VDj06Qx?-bJ7~P0zOvx<}bj7+DtFrM75Au)( z@6GNOrt|YKk7%Rp?iVc)1Amk9o6RF}7M9T^!p^GaiZmP*=UFKq!=Yt?lLJ=3a8zE| zjEV)SE>*&t!&i4%BUPzlE*INSgikp&=?c%E0U{v6nvMG6hdoG8LabrlHh=QtD70YB zAXN{oC&TiT07;NVn}eQA`o+4~+CLWi&!32I#LCjYx5O|S!mbN1&VR%=Vs+`?k-i`t zMCFy}okzX*#k%N@bF@{^K1KN|8vDMDa+TXpR-V5H0W&p^^<>>yAe?>Cg^kd%F`A5l`Tz7z-ED)sI9TO z;Q4K-f|b@@Cy1dk!+(_U%k#K*ZfQku6iyy$#9pq9wq-%WV2gkL{U0vXgwbX)iTq`m zv!RNrFc2C*x4uFq88@oXer0@Y#dJV>0o5%o3`f&~21c;wk;Js2T?77=!|#tluz}vC z0|mHr+K4z}pUNbvh?L8nRJxEz;~S~V0L@AJlfV0mWUvbJ;eR28J|HXAVF|2cdH?6_ zwc_WCC-ZdP%ZKEdSC2(uQI3mwB~SVMyw2xNZ7vioQ}U>JWywKCr)_8$ls|WngO1pU%satF8ycN)l_A;Q5{0-~ zigm`iYXLZR)PDoL+;&@}VlXe=+|z;nb_zbz2xTmtG#9Yhe17k{4?JDZDpTbt4i#P&jAolro} z;%Qm02;w!mx=SypHRj0TF{dG&CAt#bGo!uuaCh?QXOw4Wh0g!jlJ`qrw ziwLRKv8?opfo8x^7-km{Ryi7j>{W2WZ6u|L6@M^$Ax;nQ;b8OQc3ixN0SP~fG%C?6 zLr0t-9&yq9H5`ldCpgvV6`gf^Nff52<`9$xuI%8}7XWoYNo51$2wG-9+bq#>i0_KY zbD|HUB<_Lx8^--2Ok{@8vY@;a!1Cz<_7HQnTPyopJDa}nt0P@|ee+BUK=K%3^9;Wyh ztW@LJkH=%O8sie67~nol6#o7k`IzbTwFBCel&a1{{?6zv6}^)^3Or(6%Dt zX98v%-hYOdfY%fiIMREtwj|3>egP9hcaS*8z-@+Lb9f_wDw6P$UeUgTCZ_1zJE@kTFQ93yoWhiz=?#pKK-~_;2@3DnRPC2=8wPRlZ;nA=8Qa=KvW2NQ55AxG@?%_gh5I@ zR2R$<0bOz_A(%NdE~E+DP_mjqRg9*Kdw?-fX@(!b1Hl8&S94 z9r~4T4qllu;G6w}w?FJ|?;L!)_|4Hz`#aw*e)DE?Z|7SD-frw>WGfK8BrFPbY(hF; zr}MZq;rg#7mtKbg9Dm1~uLZ=YEG(dKJz$#AKIw&8N>c0ny`7_j-L1n(MX=Y4Ui)G5 z_3rlO(ayHmKiJ*cee=ryW`=tpOq|302w?CK;NCu-6K&bT!p`B*?jDwYxcS5Gn^&@3 ziW`)RH=~bW$4Eb1Uo(MrQqq``phU4sq720M)kP#2Q3zUCLVq}h!b{vNiZNo8B6SLw zS8Sy)fSu6@Y!ytWkHwR<`7lI}N0k)?>e@X^(f34B4-^AdD7nCG$u7dP5S%&UeVSdS z6_vpCm2f%8!6`#q^2=Z@__kJKL;d?GM-1f;vw{75y^G#282$6G;Fge5C%0}~6k`e3 z3ht03`XD6~*MI+Go)NMugY{yM322unXbE1?@Q1X-@|yn2^4^h4mP>w-XYXO}8Pdv_ zK1J3^5@vTBBql$5eDGQpvaffpZ}G^+!f5oX0)V!7LE%7b{b@r_@i_7J&jt+qOOdz$ zHK<}iG&ImlI9o#K$YkunDI_q{saZVzUSEPtV(65QuHvY<~_{O{$(zkcYp z@h8PZhxBdZPgwt25h$8@1i>tUZVN^M@76Dfr52n5@!1)o?knEwuy{|?yl(f5TTU^gblUpfvvp(Gf^K+B?_2f8q2!`%vfO}#l+~4 z?5@!v)_>gGDmnx$HGhN%-$CfRQS(-m?@7IPqlyxB@?lwi=2u4wJ=!^7M*QU5wQPs^CQULsU@Sx^XIZb%M(Jr0>^_TPa5Idpj_p z;uE&E;3N;R?3xjmRM83(9Fsc;%}%=)42Dp9 zksKEjTp0tnG5DFlzEH&33G8+biZu7RvA2m5VUoWS<4UY32sTRe-i8ki&z8GOY5zJB zXQqoiy(>MJqqYiwpde$*8y8BR9bDG}!|$kfFv35h95T0P?RFG#S^{pDUcS>^lTPTE zO@Ak#(ggH8H?usxy9#tA0A-wzqcMJ-CiH=#fr;inmR3<2>1za^d)C>1LMO z#jbas{^e8#s_Bs4#l-F~1f+dhzL^)BZ?=ud-$j(7_~pvY{8y)Q(T7o(_RWHDv$Tv4 z!X&X9uuTNuUpcp)Yr)bpy7deO&YZjR(V~IFv5GfN#(Dg1eLamX8!&dwPCA!I1u*Sx zh~4xedk?pN^9NB;?$PaTaGb{i-fVAni!2$J5quEvx36}NI_Vr-uO7%kxVSbS6zRx# z5#iu;4q>F+YTJnlnU_$`)K$0H^88C@kUdy}qzO0RXO3zv9=# z6A*BJz2Tv>I3Jggz+!u=IYQfNgXLKPml*g&m6sItHok@jdGlc&%Zj5E9^N$^6Idv- z_$b#6x~Mrl63)p{j#Pr!Pfx;(5v%xm*LRKvh7#YndknRy$7>1F?jE!C=QYP|>?yg< ziqB9BU1fG2oxE#*lHmmFPEyJ4a1{2+^%(zu(=v%a*NgKkFO3gCdUTU$hf=Kcrr)uK|vop#xr-_jCNA8x>znatNEH*@*`yJ z1aG^Tjq^#&{oLM?Ee=5GLbK-~KVQ}cq?G}+`3qJE5DxGi%^H1!<0G3w(ZjIywhn)P z_?$hJj}vQ(d|o3P$d%NBI5}(C?9-}|1yBovt>Qui`(b$wgi_SLz&)AviVJ7j4|WcZ zD9iyc9~Kri?VN!$DY1IR#V(bVKB3t^~1V&5ruh_i%&R4H)HJY>TdON`W{nACMGPNU_e?(*uh<>1L+DGb)04hF%0v){`^vR_~T%cJk z^CsDqzKwycGI~`+6-{UVHW=SnKx&LHPC4wV=QBeCbJl@MP)9T1ev! zak*wTA}xMdRQ<5m#IpN$~B2T9z!f-pdT2(RqN1qQO# zgf6tjZd#O4*w<94@=4Ru0UxU}jV#MZ)0Jzdg^`OZ4mlyrqvPab(qGYYRW2stCtL7BtHm?mQAukY^WANlg)eHv*hg!H?%*xjT@$7y@J=f>h1t zuQlfFc3Zc~t3l0G_M2)`R;CmsI=e32Kc1pXKS_CToX59Po$#jl0cc)h3Q;eszaVGu zrbgL9C>0)A1DKd~$N)%qY!?w)ZkopJq)g`OC9>>1D$9gOAy=1w)|dGInfwzmqf~Z3 zh#fl4!+f5C;8{P<#(A;MoWScv1R(sysb~zt55}>L7RGj5fRhyNtsx*En4F-XqYT}r zA@Di@_6I)|x`GIH9zf+~1Nl0Ex3xqz1UL&IU@yz$RJymWM5BPngVRdSZ*cv=3o!o> zi{Io`W!HEKXX-qEqJV_B-;baX{b&%UaTz67B#hJlpS`#1Y9raw2LDPlhbknFQV6ii zE~=XQoBBZNQmbMn+)gFaRAYFbNB~Cy;&x>r@FQysf zkBYM_8bud~3oTMM;XC2*<|wACxI3r6n-cF%{!F3b2y;1-N}}9!RhHtPUQAYQ7B(2n z)rAhDQ-ragOqW)ht72i%f;}C(c!1Ppkzp;$Ga@g4&}9^zkFF4rgl3`~8`y^2v#n6% z0U`YmY9zr4!pbGBNM_#N%Jz;rh$qC-LS>)D#ShaHNukcMWx2_n=;9^Yw3e5jr$eO4 zPbM(uks)oGad1?@L8cT;CFf$fN2UuKwd$b6>uHJRb@@ef2{V9sq{mkU_BU}?Q4)M_ zVgJg1K5_I7dHNHLq$~_~_1ThL5MY7EMm1oB*a?fM+1?rqpp!IKo2DF^g0U|{YTT;% z8O2_n;vqVdCWG+GQ+pg6mh{Pfc#sVpvw>Yz2iDccS5rxM#|?$C2Gn7SIJDXzQ|Ial z7}=UAQt>GA-A^m$)nZyqLpjLelPN$)s16x_NGkzpZY)}D-851A&m_~X6b0pey@qb^ zvWouA<^ht0bTpc2K|MY`KA+}A+Dqi9a=>}YcsMRMkUrRI{1Y|cIL0nWt)MSlP=IlS z{L-h#tfSE6-^3p0A?ApslM9GN(=Rd0?kRQ1QH6CgzmhJdYl*MMs}#L2$c1#^w8Q0p zw#Mu`c7#3be1RDL${~hyZcAM8A3s@@f_ffM44=Wp`0JgKDbfMO2{!I9L`}4mPsigh z1N6Q)+lz3dqpUaaROb>jWj40S?G1F{X;L&KmZXIKx;OB+`MgHqX7aC9r3pa=0gd@% z=fVt4`J2&2!%aKWLCIIjrZ*DYkT(Q>R?N(D-2CJ^ZZKkEsV)y3Ws4XHn>(8JYr{dw zzv~ykek0&CTjWJwXyirs*6;yYLenci98$= zKDSu->%H>1GcEnQ{^q)R+gtGE&%!%v`7e)-dds`@-CY~nkHQ?*J!vTDPRG`NYySiJ zgBFfTA4^%oxIJ*I8)~uPeRjJ$9XHE9qAX6cxWL*!xf1sTos+(xbeGqxq4T{S-+y?q zxuj3hrEhjOKP>*-wyqGs(3|5o9Z2$H*)oIRnFE!3DKMa#| zYF~Z-f&E6C>)$NxM}v4eUfNuL`)28RdbzZ@`thxCF}+jsS{2uh9)cO3pO4mg1kaD2 zcKto-`wzQ*2X{6pjOk;GADMyCzt8tYIi4sD@>g;}`LPxi5q9K9tFx}Shm1$Wn*gpI z_Ia%ZIND0Nmv* z=x@38zlh-@PKJc%Zw+dH_5Cm)qGI=*|Ne?OicEl?6a7<8>9}nW(ENJyVu2Xsq=fb5 z#Rct9{)o;#E&~_yE43;i@#x;o3W;bYOAKHUBMRmr3=XO6+Pyg!2bQn!JVF*ulnHo3 zIVP1mk&}-B>F1Py#kutoUGGHsn5!IFmtohP8GWcN0Ryp49IM8EUXsJ1N#jH6XLDxk zkXQo1z)?G5D6=~TBA|~gN1tf&(xp6L;DTzB9i?5(&aFe8{qoJ2*+WD^TOk4$3`ZaH zJTved<0+L=o{gD_lcJWF33wH*7FjXq%v+WW7@Iv3>wyF$e*fF;r~*X&|A@@;ktw-t&tWbS~>^v2R#Y) zIeePUK3l)4;Ax5l7l8TYa(k4XoWNu?qqNb8*wj#07j89zbn$1O?+93TChM4dDG5&d ztzS)GwWI5G<77C3CDfS!e@tpVzlg|@b>Z)Cm6KY*-ntckZX|Hm13BolDT=1{&`#d> z4aBpIPxO5SK*56EpQ5bMuouqq;04oLU~%Ht;KAu?r>`HGc5{c_AtJBh z?UEes`oW+2T?ZLs{y+c#M}b!bZSs4YjJx;Enkyauu91r??A&lx@IUoLmSnGRxX)elwd?24IRy8#g=lHH%GCcqhM>BmO#X@hZO;%Mq>+m9c1x1M9?8Mg$4+b zl627gDlhnoeyxsu*@y;Sq_~=r#^;~bjo3NI<5L2~6F25SAUBS!e1dLbn%jn1cI>L1 zQ2(UPbD{q>rFAL*Avre&I`Qx);1#~=>Q|A>GWS`5 zcwwnbO1s_eB~LlMuzDtMJ^y>=Rc-V6ZJ2yMt_h zO#aG!68EEtI*P^iLv<4v{Xc4!GDzjsV9jU_%Nol7s9I{AX_ohnOB zo%tG-4(1TszuL6k+a3Z6)wNBz&$uh>2t#WoXV@OSYUw0fVF=+3*g(7(pTL+A0yZOT zthPJtwI#L59wfF+EqNBL!0zxRl%ZaKb3$VnlhlcTpVYrGAXFUk^EEY=5NTId}29v8CG1HvvUwb|x{@0On!Ev`I&n43#) zYj0=omP~c;f0aSooOOY4lt{^Vwqam8!_6Q~>JO?LNW*vYdkjx+;d{TdeMW%F`f7xe zIEYUjR+DPSFQv?%rQg*=8P+pvuF4$5r*FrcPe)O2p8tCGl^Su;sOgaNmVMu4sku4( zLeonYtAcTJ&ee6%KejeiHwv?V{#mf~tJwVL>{Z{Rw6+EsDC$c1!@s*cS|&)skEdL+ zm1v*C5dZ)|1z+S~31N3Nzw^*gUCppniXoy}y`;DBeZ>{cy1`<@|JXJ~K{RKNJPi;a z@qmp+m7z`ejWo3Y_Fl+y%gP!#y7TEt8~tk{BOiP!P{)$Nb~;Kk^(KOUK~+FOZZbO6 z8J?(le>lA2<@<1DMY)BmSK*o^b{5tqB9&5q;HiL>*nUB5*X*bmoL=84_n<`wYj-jw{rHwAu=sK zah2+hB*UB6==N2Z{EjPs6aub@@?wU)W~R-iTF0xR4Ococ$GO(`l10sKu}N{DdXz}d z2XriFc5B)HH`TaWc|idy@u_N<$`k^0wNyXinA@G*gXb^b?C-ufy5-!WmD|qmttaRc zCTX_GdY&P5?sUyFv6bbEsHn4b&e?&nE*vcj2+uZRf<7psxMJUbz6LKzS(K<=?-OJR z)tV9Z3Wb`K z5DD|&G*QPD->S@ikhX!633C)9G~rt9zK?Sz>Y=M~oTx#3O5q!YwvNJ-Naj&(9aR+1 zfW#}%eMtH;*3Bp$#|#Ooj?xq+C&XnWoEO35m{Crz-5LzQu!EFFO86N}`#>E;W=}MV zbFm!r28FEyhPrF@oa|+lpn8}dpFp6vRw#`N z395q?0qYBoO?kcMYm0Rp7p4qJVHZREF=Xk|WRL%$&nvnNtiHFmd} z)ZAUL7e7QvmX1c)p3+gc72M_zvXm?rjs5LUX?(gIf1q1L6Sca**_!4|awt#B z2v1snGL+-AWS7iAIM&=>E}jxuV40?y!>~6(`hP7%<|M_2oM8B4(AJNT5BChaWuwsl z`e?bu(h}jR`O3BOs37y$g~Ea32u9Q6`j21}>9HE5QJyRn1{>d#HcZ!~TlHz#Om^Xk zGb`*n^V;Yo-B(Wx8u8D2JDZCQKtjoO$ibk0r-v~f&==h0 zh0$n+YDHGZ3W>SV6%X{^W&$JnbZ{mkzcx`H4|IAC=j(HNj)|-9E${-tLpZmb2WFjc zMd_Va7exdB*nKA+<&gVGz2w?!owcum&KiAz6V%^Zh?0R<>Jc(?*H<;5E7Sn{K7Yo4 z%dceG-=Ck+ddZH?!sO@2ou3b)tWQQ5uQb1!E)94>(53!UPJT=??wQl5_W?8t`dCNN z$DLVEDJhE@AU)RNFdeKNO$LGAxEX}EePVMKdxxQQYCxi zx7zvL2XM7>ixG5~oj-XLouM#m&2cDyeO#(a!}Se)5fW+0vdO2H27XL>spXXmsaGQ( zMK1AQ+JEE;0+?8;;@LU1a69odLCRyZDbxV_@Dv-KHmx2qe9;8dpSfz-H1SrMd9kG~ zqm#2VJW@=BPv%CGOJ2xY9-*bsvXe=fAS)K%ce7CyI zk?AFH`;dfn2cmNVCDEl%VbMU$4}ENNcAq>ap>YxN+)9domFc=WQn$BYgS;uV+!Umo z-%?}GoafR{2{NJO9~4nIRyA9p?$CcV8I)C_nUnQt2k+K4m49~l^3?%q^%ibENlQww zH#p8QYcHTNd!h3c9uKMK5B@)Yy$;Y@&`LnhQv-UwBG7YG0eXc0k~+|H5A~i=33^qf zpy#RurV*_gl-qIC1HUi)*s2JoB}Ywg8{_g?Rd7pdb)i?QF!ahQLtQuKs}1EEx+{G0 z_3F>Qo^$${-nu8C|8X)}<`nGJDH6T%L1-Elb)v3K|1hK)Z}IDYz!Woi&r$l9>rOCF*{sO z&!Me&>`Wqfyq!N^X1l*k!_iSH2FznKTTbjBFDi=Y>I4*hRxXUGb>7EwdyG@_*eX5x z72fos*0#nk3PIC_Vi3j^HRXQMPoyN<;c5zo z@<7VDMm&f8N*n4>IUWKyD>c8#n0fW3W1rCiclgc?xPY@S4I)kn2TOGIQoLA=!q2#B zH>v!dPDZM*SeLAS{iU&$T=AM{mQ?56t%^0!8k&4H2Z&;KP;)-rmUvqQXr{{J9vn~b z4F`e*Ni(t9Cf?x)wp>jFY4{ey0$R)$m|e^O6Jkq*v?etszH}JOddV8v+D^wOu|}oy zu1}mjDWF*{=2e5!Ng26b@@~7MuzyZ8uoMCp_s^pOevWm2yrT==%ju|y0l8&wQOnD! z@v!qnOFhPa(DNo;>2v@sk_|56JZ8-QUh+VHJNq-GgYrskc_hvw3)U(UobOXDVuUA- zRtF#EA(};oq)m}oUIvRC#m6`nO`qn92F%^^Y@?s$$~uDBj}h9eLBuTmsl4NJTwBDj zy;8_ag0Me-1{ELT@1${dYw68($4vEpb^S`_ySrd+m3Gf8ete%<;gu_Q7QPBf!yK%` z#Nom^`uT&zKUE*IfXe$(5@vDQ{4C#`0iqQu5?I2_9w9Or<437D~w!>b_7gR68J3{%TCrID|J zJPFwrWiWp9LD~!w$RZs@1QE) zb&|ycgq-6lNc5y=?L4}2`9XkK3Oy^$ytMzCWP)xyh=P-=Add%;`^NOtBkurwt4Fzp zx@J^=b@ytA$nZkV{J@{&Fwe@@U8&(T9^iXW?8lj(DA1zSb#WGj zqv8ye1xf0unf?$8gM|yg`+Sa*emIey`_6p3lqhtvmoV3RoGV~Fv3J*5kiaJ{QcA+l z#yF6WwZ?>zF4Znz7|c1iLja@dEWC(ZWOdAc4ltpaG!fst-uWv5RsIcgNz{NZ(hYcQ z5#8%AQ*g21(4n9Up+u89Z@`uZB|c83M01#v4M`5tJz-9x(26LbnV~5*r_t+u)&21m zCA>H%6oNUNj?qilm&^n1E-qnwd9?P0USv(@dn#R9m-E+jEuUn-2-c)9`bd7g&$ot` zIjI5+e+-h+xvw7Hu5%CMK$l6xDhK*6sC*>z#_oYq7hJi+PWlp$y#ULfMA9PJEoXP- zp(p|FdOAt*fn*z{9eELEG5sN{tJEbdZeQdOz_K83yKmP~J9xR*Y0_NcG4QJ^n`zq$ z9AmD%rsxI$TlxcXZ6q0pBVY-KUORL+I0`YM8Ci{qdDvfbe?*I!iSWt7N#cW$5u#_kvp8c9#uCqnKt% zE+hbp4?91u5JMteuDvBjir^_i&#%>sl`RSFd(Vi-Y@2A&Qpc9X{Y4_t)oD16vFs)p zf4FNY2^NhvPNoGxSQlA1faLYJZ-tMu>ArUh(B*{ijw!6DuoRug^i&f6g}Z2ZY|O5e z=k`wuZV=vC2PIt~2VsQD@V6nhaEfV^=(`D)$5U-j2gTmf=~L zA%dqI83v+oYejCU!)JFbY{zVvMMCvVZA1*X@wU|dHvV(4)l%EtgO)njdh-k+18I_{ zS$-BzO2zcGo(vIS{Ij3Hw5Tm5gs8Q@ya1>-2OJ6ky{(USr<2nxMP!1pKg|016@;{$ zj1m*VbP9^dR9vNi?Pd*Go3HmV(Q#zvqY>K0#6XuXs{$2VFlQ{~G4Y)_>RE1&<|osu z(%Q%JT3+ToKr*bQCg26{vy8QLC{||3$%?joQOQX9(wdRXX@(_p2|ZQsh6Yi+Gc_}A zGx|pANknO<$flz!HBH=J;pb=!g6izbm!PWx7Jt;&yw7<-x8*#=uZV2CM95`t;SwwUBnmD=id7Xu3DeljIO^%u19gI!L?YX^oo|<+&mpJ`1d*dXvl!!hAe|%*1Ep9c z59KD}V^~)Y%kpn5A{jyn4oX-UNHIs|g5?6TfpR*ERv&e^=4I)qrTVz}3QkzT7G-0~ zXECbc47L*ZS5Zc;Mf&btn+9sp zf%~(@{4`6)-hk6$=p~E%8=dQv6uR1Juff#Wen|garT;#r|E@QgNog_)`(j-T$$6t2 zmL|th2w3!n*Yv(S_QCb*(six3SUvB`X@`hJUIM#8Ubo zy=*N0tO7+{XsNX(;D+mvhMPbNRx8SFS#mj%#Dy;C&a7~282J1$#);Ng>|dB{DIh4T zU{qk)s*mb}pRBe08fkI5e}~A-LhY7XZ#ET0WS`({u3h52g>TeJ7KP{9aqGP5t2@8y zwd{-ypD%d!+XULi81e4-I)B+!8>)6!^%iF3VL_LB)cHbXKwmhm6V&2BVYP3bxI&;S z0Ribq*ZQW~%D6$6azi~OXI@CzbXsc!>UbS9EalaC;lwa$UBm-&zLAoM^~O4$J+K{h zmg78fQvM7lAL+912}*Z#MWd3QQX>ok-hhDTbp!B1oH0!@SrCHoI)6)f4X;$9Mv9Ul znXm|xSc?xbGVB3IiQHo3qCuopJ+F@VvzUfY^fBic>?L1;v1by6g_|DlIVgC71?G>Qr#9SCAY0?WyRk4ltXM{$Tx0JtO^{ z3FyrT#5fu%?DF*Ra~bBPkvH8`!xkd?tfrSK2nM!(xe27<00Kr z952phP20<=(|%M7>+eXy4RyR&sk(BOS;l**Spf)}Xj$2K)cK-G?Ns_D4ONaBh)Ek? zAaNeM7d+u4Lv`cJXeP{4?SYJO(vN1 zGQXAJ){>A+!ceX;#1!TUnodySBX|U~q2s6!ksiQb4 z-0w+MczRmStqlkdxgyDBd=kh@IG{}E7oYO=V=zUSbQWQ`d$gDQumU81XzQsVPViD0ne5D>|KF!hPDFQobjK#zf8$MD-+#gbo$9AhJGc$M0_UQ0PF3w;u)By7;v|iC19(UWq0kQEfo%b{(BHW4`6-b@f zB?D5NpSeat!88=$TBi}MNRW#;i7vyD#AE1A<=>d368ErSI>~PYO3}zia@<;?2TauS zI62=?Zwc@~221Q=GzK4@qe~sg|7jyE;$)F3jMC_bQsejg+BTg0UbhK-Lrnc??8P0KK zAgpl<1TNc_8l4C+IeW@c!Eih|MSqx{IFZFO5qfMKQw>^=Yw(*v88FXav46b0yS2Ow zCx0nd=JP>w{^$SozbgM7JJBS}fF<3t=PZn(0rU8 z>~H(Ssu6>JL#!ZYy!G45utA><7^K@j;Px3;nb8A3`Lp`cNWStx|I>XNC)Irdx|CD< zGw`K=nV_44Md+uqD?iugZ-2|nW|l)2b_zS+z0S%x* zPNx!z1`$6x-lRcv8Yh%_+=fZN1!cdO=57&loB+0Sn$H5;Kw@TDc7Oa4<9a*s^G`nD zv*EsEqm<#k=CA)iJ$*Km z@#yO2DZDKx7x`ugQ>nLb5N5wjk@f2!UBTFX5oK2}vQ~hu2H-jt?w%?tla}Or1gBJi zRha`QSUWPJ9Iha0EPotEl@0Q-9)Srcy8QleE~8l~n5Aj)lmAyNdmksYj?8@sKy zY8{MPF{Q;rI3Mvvxht%$xwqkhK5@EK+B0JdOr2MIe=gj({!bYfUz-l?yMszq4Ri$)?Fn;ZXhB2L?xs zLT#Uuv9uOAa+IEs@624|^wz>x%a){4KK7ODO-2{^;BVcJrj%)o%bAU83LsiHet(Ny zXq`!T;2Fr?^Kgp@$)Dd7H4x0EJwBb!A7(qV(2tR2p5mGTsM!> zbaWmUE^Beaxjr^)L%?)fYITj1QL5SQz2rr78SqQ6P-OWs4RLS5ED{Y4AMhpiGtWZZ zmN%}yHvG%(`=~!fG@rB9wc?-}FOx_y8h-$S_z2g;N3Hm0RuWERFoJ)C z$y#Ua;eTlfzrB{A_xbOs5AdD8rp)b5)rWUERjKg$>e1Tz#>1~S9)5khQx#$h$0#LL z8BzF0oR8%_aoYou4#Yev=)OaN6y|<@ZJu4bcaLkjF z`e#*fUH(K*VbV%^3$GIB1!;x>=q;#S&`!Xl^fZ2tZR7H}YA={RrHYGkYxO=yxEK7V-AXYHAl57enU?U@h!53;-6dcVxU zLh^>T;0z!Awb-6I@PJjUvX2HHuay=JV0-x-X^_Yit*+He8-B8mZH ztP1kBeEv6C4v_$j2i)#wdfkw5d?$z7j0$soZCpn+4zg&%iR#Ugqm2vN=c<84NJx15 zX%ZDkg0_L*#LI^*PsxsxFdiuQBqf1`Vt+(zz^4Q*2pU1#^oFoDmX|3m#l#m!SjvH# zN<60&g^LYAFSat`8pBbZB1RbY2#7)0@xcF`N?1Z>Ab^lLa1rI~QYxeUAV)N2{AbSQ z+uz#WwkV3FfuSfo`DWcc`d}{++h8vQ9zGrwMC>yX$jwkwI@ODpM~V%MMS2-#1ApoT zcLD#xYw4_z#6UNk1R;b>XNZVg=Y2ZIKfN^Lwv|PKHbHlB{WGPldp=d2#9pM;^m0a# zL@pLPpkgPk8(G|ulbe1b>BS5np+}53pJSdf4%pX&!AB80H=rpH=!PC1GkVgF%o5Mh zewdv{1qa{?SOUEsam;*7K zM9WT;pBE`Wx&!q(2KAEa7SlnTmN~Em@lfbonpIeHjtb>jP(KJ1lkcXnK;p(xOwhPV zFWKFq?%;?6MV94>+B(?7Mx%hN(8I~#;69&z;&*g8l#lyP(0Taj{sHr8cz@sn?^;_w zQVX{wa7=RDd2IprZ+DB9kQs{YSBHnYFOGgb*gf2P36yV2C;safZ@w5ee_!9sxBd@% zgYS%shO=r`7C-pCy#@XxfBtL$%E~N!coGfc1RL2M_Y?i2jAu*jQjDHkhC?Pz0gic( z25u1@huos*P2{S(jvbbu@_)pgT%Ni8?b6i!NhU}8&%X74K#`lKXOz}D(AMW|kiV6v z0;l=r<`Nsxm)^BMbjh&cjVt}qQZKU@3~eL#St`GAf*L2{0j^kNxo5;gQpG@~SC`~q zRnI?XPj|Q&YWL{+hDfSis|g&&`8f(P-<&=*s4*NWal#o*Uvr3SnSV_O0xr=S9yDHp;YsE zoJ`->+UfplNzPl6vYPH?nW<~(-9LVT#XcJ{JzH;K(V5QPf?9gpe)~>c3nEOTEp4lB zk+}(6i+44SoCoIQ#(z3h&ygk}05WkgHCSXEgDyC!_0d~?dLuB(YL>dJGeJ$ehC)u+ z5+$(e?NZg2(Y?MkKvS+Vs+;=>cS_*p(X(iv5};pNaO>IaemA3C$^yWb1AmY5Y~1IF z-={!TY1ey6I08%|h4cv={&NJsAjk(H#&k_Sol-pg#7n6l&3_6eGwGZ7@>ziB4ijUb z%{40FU^m{pdGls}UoQL2KTJuw#o7NYclEo^Kk}Vp^-w5s)G0^_Sh;pN3T`GQFgWaG z4FMrmgdRze6y>|7J3X*@IXM`|o*sc_%yDF@HKs)5GEn5Eq*l@iVCs3WG|+w$UF!5H z2J4S5t6j1A34enr?LW6KoFPS*NHoCN*7iq~AkLP8@XlZ}>%ta{O2 z=QXpaqUy>|78e^3sH6I6^Bw!7`*@AN3I;0IU6lre5*&v~mqT^!0L{q%SBJ zn0DJsNesq^XtNWOkW1am(8#Hp6;0q1^=rCt{602O`9FW#dL~tA){6ep%;6^VieP^~ z*xC6~sHmKueyf%5Oo6v7oZnRn7zok`sfuH~J}$jXLpeE>jRIgrA)#1krE{S3D=KHa zte>i|<+_rdX-kR;+^Dba5$hhQ+PtcXv;700vbUdjR@CaJ(e!Fsr32QPzp=Cjx08X|Zw^|K%^pc22V*OyG?y97o;m7P5{h zZDB(wYdFuWF5#8XDGD-nEBr1D5~-FcEEDMA=$rZLRZ& z`u(o}d&S=x5>_VJ3MVw9Atl_~5Bth2?kEEJ$tHg-o;p#sP~DMhsC*Vq0c6oK`c62R z0LnAWt4bT?7jX79QhEv55K}NPl_}9ckjoDMn$Hl4c(3qbu`qPA7I3eE{LCt83-SbB z=UG0(*SLG}S)jkkoG!at&3jbAbnu}-w{D6xSh0p z#CU(*Lnp`mFrYMN$-a}Z@cZG2UA=GbmIYb8y;U35D%vMB3f1QGoR;IT-@m=bvbOX* zcP0E?s$unHoiJ#>-tk11{FqdiAcXrfyk)5*jyrY$(W_ETZbDi>2%yFodEVMQP+U#K zIkp}=WDM{oFb;D{q%R@sFwhy_N!0Q(ahZRf5*|10Ve)c1E;NfKSiapd1TwC-CYRB@ z|IrHc(hPUWUB|gYhg0w+gMq`#rN3l1EnPPqcOwQ4JSF56Gw}rZlyQHxPj0(XPuy@j zga)X0pi2wJdRajn3!sjrS6km)?ftuf;V>v71}^Gb?F=;OH@?UX9{@1Z9s>Yk5fE z=e2!B_XI>-FC`pHIPwaw;0a>6qP%}*5qkro6(f!)U~yjWC~3}4g$HTQVU_02fKSn)moLH^n?K&M`YFbMRUW=Cdp!;8$yetu);iHIU#xY$SbGWNG+_^{ zFV-G?m+->^a(|g-2?z!vD{KUTaS#c*ui{I5S-@bwnKEpiqtW?FXLK|K*^9!f{`|YG z-c+IYn>AIi7X#$j##CV=(4BpW-TT>F^IiKxc^{Ol7A?@8@g#V=j<0NY-omZ|ph87Gb4pNWPN7P?N3}I0;D23X*XJEKGTAb0yCus*U@Q-$ z0tgu?6qmEezLR&UwSEL8YlmtONf=uX5H_;4y-iBgv2R0j&Nnpjq;y55+%eoDnf{qV z=PX97xLC9^)D8$~r*ac$mxCT07qaZ=USim+C31`;g4$HxaH{|KAN)L5uL%F!22S)6 z4%IK$2Y*O9V6m*2_>cdgc%<<=3ktKGYW&#bRlrje8m&1P(fDI<|g(OHi>7(`%6? ze4py3V^%jMjx`39XgpS9Q;KgL#aR?*D!ok9Kz|MncJ^6)coHSyh_<)9jKJ0D+Q0^p z4WjDx(+2)(R_Ooy-~JC{di<+%G0y1;ZBY7$?N>dcVfI2`CUo3@ zA`7`AxH7O^PAk@S2$Lbd3&$89lAt+>&Jcs+p`TfvC?`BXBdQ6pIL83*1H+W5c+JTM zg@0e{e+CNEb$hLNOr+F|z5LXK*OK|Ka&M%1Pto-`mqvm+XO?V^(q}Gs>))eRcH+E0 z&2wMfiIM?*ksd{&!sQ9kHjfg((U>60%TNScgK`b9WmRl_WJyTI`!2xUo=(|9=bH-A_ll+}L3v0SC(ZiIEns9yc^_H1}S*p+eP zw9G_2AfWsK5HzRJXk;b{rKYGsPP1vb$v32>3F@C%EJ~N+%pA@Cw$XYhLmhw%;_HoP|jQ z7&@U*zr7{+7Io*@g@j{0PhT%R)Q^>Q!4Aau2>5`{>{Y}tI8DN$2!U>aT$1y=rQh&kZ<}bVFpOcO7<&vfM%TSp4yEx=x71gX3LHGf^6gp>RX z>r#k%Pa~p@OF-%%UbhKRB2gTiRX&c*5n?kOK9HGLB@v;Y9| zd#A^0MI8shAiD~(X>!bFQvmPeV5OujqU9CgyL+7?qp+MYX~H@U+hYOH$aLEpm1Lkl zvqWWac2&1X#?)Dqd0BmkqkoOxV}BDyM%;locMA7fEJAkZp1B~)L<}kUDkzfSY!#zI z4xrzG8l;yA9a-=|@-Zu^H&-SV$ENGdSinT7I6*&Yp|^ErYd?hlbOY3)^j=F%#E{Lj z$Z7Dfz(vbzsl5X@(vi=ovS<{M%0;z=dlK_ZIMigSbr4IgYo}B#HXqGZJ;~nC_(rtbi7> zyv+Iw(LNJ^wwGIEUw>EHtRVv)H=+b!BIHoegkz*+jYduc+AdsVYHtUsNe0u9&*Bbg ziScuG2JS|$th{3lL*yQw@6g(a6LoA$9YZqVo-B8aK7Tp;AYi?Jz28P$9=V-tL~&kh zsKwRx!w3KKfB8QbSJ&3sj~}n#J-8DHAU6glhOZ7AIsTP7LVw(-ouLt6S1R~L!DM3g zByNcuLPXYq%}urBovA<{rWfW*wy1CWK8Fv1tJ=?{(sGj_!vTT+S%e9n)_89q015f| zRBgKL=jYQlRhQ@SuhFv;zX){!zdw;eqm-$gKsVo^SO6@M%*BghB0DVlC~s-+PX$+zUH zaXkA=)xT^i353Z=Ulcb(cXtJxQX1EO$7g2LSE(_r>+K_G3NQlhIUzMl(SQWZY>a z!4&r^%)&zVb?$^qr)jr^$VT{iL{Mb4Wj2YS@qZJidj5!;-DhqrWLUM=7ye)b53qtm zhri__C!&hHt)7ybhXQ*{T_#{4mLYA`GVv_Lp3bRN!6ZwEwBGRL4q^Dc>JX+|&a@OM zym2^&8}-L>Q+=z#VcJ;l0J`m3MehqlE%AGyWvNY7q+qvBhHevmRA-M*D4BIyLj>ui z>3=|y77eE{sJ~0Lrz=ZT^dD)QsPi}(Y~n}`lOk3P-h$2u;Lkf~Qe0fGr+CmynmFWp zy+ypE?S9}Ue$C?HSjsn8*FPYS2ASvj|*A1sp#hE6)p^b%|?nG*HutQA>8~ z%|Lj(RsPYOO0W0xHWEn14vnt1=!IlW=#Qo_SP0wVMVzHfOvBJWghoP6VPifKtAEV> z3q$v_@Bw$wxaS{Pm9oFb(WUP{InZY@C&cH;x)}l6&XzxC?a_v}ZNR=PJ=3dQeECT?} z|CM;`T!P98rEJbfK_;py#$ll>6JeUR1DO@AUdbQ>k)YAWCM zUdAZT{J#M8oPrbpW=5NM+5y8!c+hrm$)#Y*HUF@FK20;Yc|Uqei}g*?gN(TXU4Vh~S6e5-(Q@4v-=zf*y6 zy$8%Z|7|w>&RZoDK7v=NHzIV-*RDW`o{jNPpR%}!f*+tC0{a`Rgo`YM@-}I+&GOJS^5zD{L550`&;>_C z0ep-8ssO%rm{ZWxMd^y#q_8U86}_BCqe_3I6Mti6cj+q1m#}Q~CoS}n_*6AayFns_ zj4buOdFzC{=YMUDDV{|Ig(i~dUL>eYmc20cbZ#N3L2K?npLZj;ZV^ESAhN(i-SN173D=Jd4qlYf++-n4*oCm`OcQ#Ss?KL;fQ zMD#eYd64^?Fr}yQ2)W08NsF@2wq&YT4Gp35?OIow4K!1SgRn(yPG`8+k&ORz6b_Ly zj~&W!GM=eIa(`1FXr$+Xhu;a{Ni+341+Wewu@)(gAPMSn!W5X|lj-A4c#l|3NG;*STtov= zTrHYCB5v->=;SO-&o^pMol0-AX>yXL=UPYaB|t|SYXkY)1N;>gQP$YUMXpG*E48T> zi)3A35N8+RC}zR|X>5@w zO@B7k_l__u;$nmZi{3&dI+5eLT}}%+DyZ;c?J!kE8ne*0HToSL@g|Nc6~K83-!dW< zFe98aev}6PnzQ7?6C~7}M>tdpahwLPvRIXup9H~DDn}kA2UJ|uXXG;6%-}IYM<9W&jJ`Y zr5P4pQj3I}C-fZ?oc!W8#I}YRash93el69z1=V}$Q}4pEK1AUJmLx-N6VUBxWd@mh zc}%ZV9wL!3|Gc+JBP*1&7iI2CWjM`Q>m09ld?&GOUzvC576Z+~&2ME}W@Urj=6_w{ zSpbj)xfWI~<7ALt<|{y$4Qz`6D~wD=Kor#X%=}Kt_Z8~*&j{vr*~4!i#yz*zyZ~-D zQ>PTVZPV-P>A~l)%d;RXvN*b+Jx?}d6GCJmBucEiZMBtzqpM$$lR?JJaHPYQTZ+*a z*$-e87>-q?;jc?z<^X8}D&j`~bAOQZ4RP16NT@$r`@+OeUjQc`ITXQFIt_-YIh^QK zWG1iys&43ZK*zu7Oyl)FfS~^Ex!QSxyqA2O=Je04$wUcEV@q|fV78^Ka3U~aU?^J9 zdwMwG<5s7m=)F$bkPN-o`v8_C?F~7YqtifOjpXJ9V=sN);=|65D*#U+hJTxQjGPX2 z3Dl8f_>Ib=NWEp$M<7*<hB;~*ECK2? z9D{u_3Dj!9pOFmII{&kXvN4C|3cQyXH1u>5`2cQ4#OxzWIxoWhxql+eS?v=04EY?* z-4#0c4mKB7aQt2ndxoByIe+ZbOz3bbI4z>E+0gk!{p94k(=Ruir9wzb7*Yg(LP zYq635Ga~uep_3s%8c8e17>`;h%ShOIFfjL2$q4yK7dhglOWh?^HDTod7?`r+v4 zKt=EQ2;c#Z0kQ$bAKrJ^-qZdRYlFKonPy0II2P~)dDFE6izj7p~ShC zOd1}B^OJZjQoN?SR)58se8UQrSI9SA5eO6m;=tB2qWtCbRFRQ~?|`a7S$RN4QcjrZ zakHiJRQI(%iXl+)co5a!3nl!FzksinSZ=OJp+(k97QNp#)gqMUL#o3`|BQQ>MZwDx zG7^4Ji$AyVSt`JMI>+Y{3@4S?6%2!3=FvbM%Yr%9$1U$6mQv{_ zy78BP^DI5bd}6ug=WDMn`51`$0 z`n|cA%WcH`?OsT58{njgxlqB*zh_YJX*_I4M8M?ohAt(63+Ky8AihymQhdC-3L9Fu z+0v8&)-pw6eSer2k9HU`o|K#%d^=QT!#-@$Ki50<-(S(crEQvV-QvOe8@>yfJ&4B} z>R|PaYVbKoAsHyw;KNYk!}6R;JNV+GbQ17(G<%hAWSFK6561WyZ5~TbH&VLIit*;0 z_HpQ>OxcxBYraX~mfH9vcB*m6AywD%lZ05X)w>cs;eUe~loPRmR(lst*D@%|M={sw zb}iH6XSQ2`j{Q)Ej@7UBDJ9i$l`7TQ*t(K)bEIqZP1UMYt7ZE(x9ph@tjk*;@LC5t zeijwMliI_yJ;_&(#ebz5&?*_7JdlGWASI|h#-T)%0;7=xKQu|9W+7fVia71fy8xN^ zV?yt%J%0eo2iAsOjDYT$Q%=r}nnMQ_8BC28z;Z?OauQ~Fr2e)0@g_a(-)(Fp(PaYzgrEvhEjG2WZR^*Hxqoe%#qF&VN-B@=gEqH4+db+fj#2;> zftv$967HzhviCGg$Hum2l#me%A$Td%*NgGDI`l%+ef|f%7IKVm9o0k zfPV!p1sTh%xpJ1xXj4wC8yXbBau8*}`3i?o^NShn9noPcjbVk?e++)~V?F>!h6|9p zC@ykeyDlw~8hJBQdMuVa*8jN##h*(qK-_Pt#?2C;$y<{=NY1=#WE`}Cw(hcXaVBH6 z?MGogwRM66t-w)j$Bi_1!3&+qM|jQ0&3|@xI;Otr?Jx@O*jGnC{GIyh?K;LYba$B4 z-B8DiH8X&9QqzF9C*2mR<5KJBX4qdsyzy}vJVlMnf^hj-10Ga!i9@WoU26X#)lZXR zYNI$I#ou5fWCI~C5*Ux*1bB>$gf9jn9lR6&s;xL;=+ZTHLzlc@)SXz19hBL8k(F9hO>!wJ}*e1GjZP~m9k^K$5Ft1&rZc`}?8vx+7Mx3)?6I2HKDXu0nn$mrw`%r!s8h#M2N+YrRelkj7enQB4c0Qfl zdPH9DV-!_a0DfpM49dk7_NiQ1s|_7S1NB2F#IhK@^t7Nx^$&+X>^`T!Vt>A8z3T4H zF57*++qGrwC!S<6Vxq6r&XZRjt}YEwV0;|XPAQ_8PH#+vvnT!gFq|63Kg&Peg~6kX zd2u(MY-Gr8pAuKwzU87z-lF$~YK+78@fg!=dng8kZk!A;_5S@-zlhNtQ^(iK?C7QP zPD5qa@6AosIg1_FRJonH2!BL|fv*J37^}og(MhKbOV7~ySTw1{4xB7d)mtj`P9Wky zOQg9vVrP<#%)C5P+CoYW(XcPAvo!3VkvVOb@8k3~-4%&{dcCg@38-bgf4F!Di4O1h zc?Xz~tE%+lnz~kNGdKU5hh)XTM0K$q0T8wi`BJ2vM$L1-&VUJ z@Is-<$BE2!M9wLKnPD#?uw*zpUnp+$5TNU_wam)*oqX&Z!dcHBz*k;}89j+E-HB@3 z;pK0o;CTyJZ!zs7a)as#AU~({?kEcf5dtF6QDUYi6SiG1Sbwi4Lwld*-vE3((rPBemr6E{Z8??o{@C_%?$SYJQFd6Ji2Y>X`b4C%?vbPUf>hdh^pK<0& zl6s=4C3}xNEM~#88pK2tuuFKeS?HY!qzT_9j0LSi*dri@E-?IYfxu8cCuyS@xM-e@ zG8e7$rc#ECt;r^4sx6c?vm4Q}g?uBZ7!HS7gq%edJ(jYl0tbKavisS1@Y|xnuk>~A z52@p2Sbz7mU=?uf4(>Vy8ZL>|ueT5ndJ7w>w=n-L&WFDQ8Uwo)yr1?4AA1Xu)Z1Hd zjED;xHoCpHK!z!PrL)OQO%!ojK1%r*^cpFZ+56NlAY2LYn%F27_ru(8;`jbC1xiP8 zg;%cX2OmwWy;2`7pLI3f#J!8t+wt7jRuD$*Er0&g6e1d{u*l+mO&b>RxuW;zqm;6r zmX~Kl#t__d*WYnY^Si{4Z zxTo@-8iUT;^gAoA!z zTYuljvz?{_62GdFC;xOIc#P z?XmHlA^|lL!~Po=3^Rf4aWvnaU4$yGJ^} z>i39Ux?7OZJxISBi8owRB}e*4`QK=;H-BlczpSyjlQRwM5^Cs;d&$^ti;dg~_{``c zyJSlt%t4^G1{ZOTsQww@pDqt9DW>iw)0NBqGpzR4`*VU!DQ(rQgQ$W%^0pZ%P$13R zlNE+){(PDjX)g)+^>dOsdJ8rRQcACsKX9Qo!2=5VkaAJb3Y;x73f6uHReJp3WPde$ z*m)eB_SaT}2VW1u;Oj?UN5R)$J^uQ^>FQTsJsg~JqpYk86pyj#7wI6Ko{T)?E3MWa zIG`G?1-_}F-;!h+j=Fbk%c~|Wy6Ko@5Rh`BqmB#q+A%B%TUqN9rl0)7X_fYz2$ z20%&-j`J(&Vm`{0d_2QU)dYdXxo3{ypE9ha(efJGawSnpSRVzda&-iguoh;mX7dt%KS zyIZg(cZ03J9|oPy>Z5~}`D^vTGr|+G$b+7N@V*rzL zn&oFP44J0v`d3a_8zD;(asVfuna`8mDxZf)Wy>P=x|e|B0wWt!(Prcp=WqU zx(I#K9g;@3Mk6(yoMxB4;sP`jdJ2(BG)-|XmM?xkR3tL9_rv^5mj>ek9|6OcCgTE7 z0V$Vv;{s6uCzr|N0w4i}m+IpJE&&Ud8RP;k0h5i>O=cP z|F50Mfm#P=>97Xlov*!MyAFah(f%?^lOY`**OztW0xbcxm!stZA}pt; zFzZvM8brxioD*2WwfZTHc@;bYqTUq|ztX4Yg)J_Nmu@`tHLj0Oorah3R(QN(dvZ0WfkqCOUoh{O5DTpyCWx9qX zg;GK+y9#rr)L#OYm*K6`-~+@K;>4ctN^Wq>w6`v$QPS$6%4ELn+TIB?NeeY%#b@)j z`Tb6Y*d4O_ZWKSMr7^g-j%bZ2(AtJ^Eq?}e!~S;W{`sU- zee?Eim6 z@e11WjVKVdj~bPBMmJITB?Z7rMr?kS6yba6I22q~iv*Ox+<)|);7o7aw5-FRX)p=C z%+|tCxZ^_YyYW1A1rEZY4%5>4$4pkAvA}`3Lj&DA7h|X~uMVG!i=>z6eOF#5Br?mAEiNMe%dw>W(PV<2XMqhrop@apIK%`gj4052CS;osi4?=ZlBjoc#3suK; zm2W%ngB5G0PwjMJ7Xzq)v_+Zjm6rA?|6MPF%II__X`vf{_0FqH4D*s!QXY(*=;A2K z3-?!P#(#~WkwkOb;vO5C8D}5OuBtatn4!gW`j`0}NcH_VfraN4LjKWC!nF3+>UBDr zjw8;hfGHkkplfy9krZQWOUavL_Mem?0Z3*rDeuRZhrI*`GR#Mf z(>NLpT55@cRhK~i3p*E&EnU%T*$7BFX_yEfbDVJYdC?23zda_rIFUYL#R5dr++IZg zt=H301y-<7T3$(XEJ-GbBPggC3j}^@b}T({R^3u>L0zkV{GyiHdqp(P-@a4V>VwD& z3V#I*;}Pi~;O>o!m#30F)>3A}IDu2;^vEpA;Xp%%WEEoXPNQ-B`wWKDXC4ra;>JZ= z(&g?pHYK!RFF-?E%AGZ2I6Hw~n1HOL2ebL7e3Q4el2X!6rrCD<(UAo;$k5{jR8>CagIXZ;L0wCOwih~~3&iVO~$`vLnWv|?IYKk!pz0pm|2s;bGrRuWN0Fn{YU zOA7WCJSO!dD6bCnvDtREB6{W<#LOd#*&IQO}A?7s|p{{TWIQq=zJ6X zefN(l_nKFR*Y5g#v|GwjCPBgoMu zK*Rh?a}5;3jdB`cao;zrsBR&=Il{l!>>qq{;=l70SK%-(!aNRXsT#Zjv}KX;rJF!@ zmsc4`=ifmGx~KDiddnj%a01IQ;cR4Pu}wP zIvF1Bb-dgQE>XT!qEx5d@qbc4?99@`)vwo_$2bROKJ->Ecff2_Tgng-N)IXR(<>2C zoK<`gQ2+#jtGVo2XKg*`JP10gN1e_F{omicinN~f__o{a>OL5yfVqK9mZe7L_Q_HC>sziXJ@X6r@lytRr6Q6h=@s)1dw(vbPkVPQnHB0t z2d_k&A7n8SBFGBEO9M5)6yPr#k%rt{%>f`ATd8-l3tmL;i-T|&J&%)fu5|}FyqKTI zlg-sm=Sw?4_=;&#NOqAQi4RjY86U)``4s=Y6O6#Iv#nssA#NxZU&vs!VQ7*+qag;( zc0;8u1a+8~8e=an`F|R0Os%bL<`FGu6h1uIfbj{F3ggqNdiG?6n)u%R=orKhJQd;gngp#em!(z!x;F; zx9^(x{E%7gK9KlCI=2WtgP$<}`f8`6Vmix_Iz9pM2q*2ho8cJa62q2X)WW)+P7@Al z2EyPLaG=au%Jo@7(2@mKV{ zRAavIDPKM9r+oGeboRv69sGB_Wtw6B#1A#&|9|KIPDxd9u>!qG4wO3-u*N)E@06rI z-$sG_>8$AQVGMGc5};2Xw2zwJ0BxRG)>P4XXI(v=apNNVl?_k+m*LW0F&kMl2`3yy z+MFFDeK8K4^3|wlw=u*-bA}F(MW)C+A%#*R$&K`rU|)whs}vRS+)pgIc7A{ld^`#J z6@R>KA8H8Emvl-}#<)meD3r^~3@pC8wSpwPBpRj#GHV8GMy41a6AT^>{xQw*Od61; zDJ(f01%!_iI>gb`xNI13I*-DkI*HBzJ1N4&Ee*dGjESaQ@{3a-Nt_IIM=5+M2m26n zo3tpz1SuwYj+he4rb60@kVpesuqY^k*?;ub1B#R(r}kZl1ZAuPJQSoSlk@sLU=RnY zf%x@#*#d~ni$Z1=wE3%4DTX>S=5Tn>l3U10FcSWhpCuP(Ar z2Ryp(F3oHgScUexAmt64OH`g#|}58dP5f@$r!kAmJ?uo&o0De}$t77kY5=nt)jANn0fyi5)q?x0SvjVXdDuEIe%KnA$=UL{0^DSs#x8l%GNc$u5|cSePq!Dx9B5ys+wGAhekv$Onx43@yxaflPy z-I!w)0k4T~%Cm_U8CVMdi8LDu;HE-XDc>X%b)>oA!j`3@TySeyegfZ8uooy32C`Ma zQLdFVBFNO&YL~Hh=23Z=oRXUc4(GcD`9`kTE$${jzZ2C9>wnZ5X3RZEyX?y|>Ap;& zEBP)!;2U!!T`xH@T%A=UY;1{^3I_vqTv}j6A5&(JA-6CQ+v*u@6GV7A#Uy$pruV^H z>T5tWho4NraLkyW6mP({WB~X(>3)z}Sta{jRKS+G5$iZbnI|Sq;MoyoX$Nh%gy!G_ z(QVa?I=_{MoqxJpGvbu*ORo^HiMCPVPolH%BBqp2`9c@)#RbQ{MLZglB-KWU%>W0+ zBSLI-JQH5nm4IKCAbCgO4K>y(H9S$th22}6SD0>_RODd&P5GHQNm1g_nhjwqK^^mK zlxkzS%VWDoN@Z>erlT@xUdS$zdnCmVt#&$oe`<-CN`EuJ?fE(bwbp4rbQ+`2bG15@ zS$pWc&?#dTBQ95ItE!x#;NyqwwNk-(N*Ahpz1ChYRWZsGH(BYUqcYJfKK!a&!cmXt z9S_O{96bmH9zO2a=O4W}m~|M`Ohb7C>HmG0F+~sCoz|=&U&Tn?X80brSG^w3dm*if zxs!a$34go&8|QuF+T-@>ZQl6!Vf&GW?B@Tyb7rd!)BBwpis#coAJ0DB!z>G#;sWt> z2)P0XY@+T$g-2w~anc`6g^Yqxu}RqxJ*Re8AFGrd!r|x=Rt25C$e3|V)N=xb$*)}o z|IdI9tsq1d=F=)`lQ z>&X>e(QZbf$&@dvQg&9{@ds>>hz17v(m3Xwc6=z}N+a63UV3-=$Y6TU8g|ar01=O{ z41cWizcA0AOT>u@P9kdVHtW}4xbmWsnRu}{%cA>g(yn1W3`IJr*@Mm{VpHja38WIC zAH4-}k5e51a7-1$OnTI4>4i*#Wg|M?{HqUe?6Vc%4g4QB=5+#anUPJg?J zpe$3~)pKVF>H8D+#&KM-DKzgQ_-%7C61B}aqf}|Z86EG%^9Ij5N2*Lo>e%b`F*|gu zwPL~%`LIR0yt4+`w`^podaj#d)*>)`-9TIIr1bM3CWft(E48|Y%RHjP^x?`l%#2|y z0Y)kZ7$F%6*epvdg{IG@H^TX5E`RypCWRp`&-M1H2$)@scIs@#4E0RRfxB@DYLqpj z@~)e?AMsi@Ke8{$kv_1RO_IdRH&uQa11eJ(%ID3rd*{M7=bijeeWWW0P-_r#Fg$ZV zq{Uz-;fN7)dkf#FlPn6)-8+S8>#=TYKN^5$HBiqWy}ah~bnJ6d&Ta8gM}JzRej)T= zmc*-TM!O`@z-!o2rIoJb`f{Oy#jY0T=e-5zN+d$k*U>68?{$RkDxj6M!E@yksymFT zUSx~VlIfLMVmGKEF5<933-Ae?PM`mPu4NmD$k+wq)FcCzm!(5!>~1wT95#g6JOzY4 zZ2*gP@}%1o9GZS9O+w%nI)6YRxm?;05R7F|8#I{i&EVk@LGmEVnk}E1faJ(&7DX#X zMgcso9_z5BIV_SEfzhF=^rygpqc1O84m{?2^C|F_mxToi8U5-Eu**1-3$WZUK0S01 z;gIy%7JT}+BsGzZ98!cIDs+^ZP)@(nazZ)lS%3vKcyB*q>E|;nvVTi}=nxU!&IFo2 zu28^;b9)AUK5u{l#O6i|Cuw#xGSOx1VNFCE@){+r19D_M%4>E`QO~UsK zy8jv*r93Z{f#u~9`>MrlY*sKRaA`LX=zWz)kIiUyKzSuBFMpT(Vf6%it`};Or4)>w z3@roTPcRFPr=ubU2%*z|JDm}@YFo97fL|Kth7E8A*PUv3YvEl0ZG!q&BPUdG;PH#NheAvWy5IgFGxN107vA zP&0T`kwnWSz0N1`Iq~@#^4`(~g{>6WvT<@Me6RIh-$&G=%a9U89F}D!7IvsSLSJ5S zETP{2Eo#AXf-EmTDv^Q+=L5mz3O%xWAF6)%tN{i@YJbiL6oq*kv1{*B#1|4>R$`Ta zylcKE9*?5|&Kf#(i5rsQ6BET;Zh?t#!gR^)*$i7{>tip388WAI5Zb%|bt6$V1nsz1 zl(elryp)@O8(j3w+gOs-I1V_o1c#It!yG4cGoIppE3$1o&*&uq=_Kzgo z(o@1GHj?pFp^^;^HSTckWFRAJ2C|94p>_ z#DA?dK8Xg{VjN3Hu|l}siR%#@^LZq4Uusd({Q?WrI)n3Z(h7S=35yN5cun>1fN5akf5BIT&QHZe|~fKsKD34#;ZmGo_H zN;{=D#CiM4sU5cdr>3zupX@uDxoIbBNz@^r#z?MJ4L^!}Ai*w3*xD@;61bAYa(_AH zOC5xNkc*ZjZDozu_JflS6iM5bq#V#+keyx+;DW@vcmLbg{=xHIetK88=BH1JY;-t% z=>YMRyt@4z`uc>~SfpOF*2g=meIK9oiD^hTL^4zokIX2n-g*?u+s_{eA;oh?;>F9O zU6HJk8kEnZE`s2gK`C0pC1leIY<~zMi4nx4CIdDEl={0NupUpmLGzsK!1JWQbV{eq(@(sUM=zWIxJD8Y8Gc zXS?Xj^L#ni>@DDZ^cq1y5pPzlPJev6c=`{kA7=;Be^~pt z^yTqy5lO$Gg437n{{k3)$>3FPq*aZ!rGi&k3=FEcy>&vA*b#mRuM7!9nkbHSSZ0;y#xe4%JzIwJ6KMy`8csRC_zr zMbC@30TS_s>zhM0*E`p2fjpdCV*3YMHy}j(&O~5Ut@>U_>O2N6_YXr>r{BWe*gi|s zJgVA7?yV1fdVzaUwRrj=VlF4S*oI!e-0E;d+kWSVZ?_l1M zVT_z7x!OK>1@ez^njyI=8DLkOtG$<=0m~p?2xBqP`u0J8w90z?$rN#9k}t;IUNlv9 zeH39ay$N-rG$IyW@AW5_Pe+J_lj^P= z4{@0JS^EF6_paMSps;lxR}2oh|y9sH(*(geag4 zph!_>_UK=K`vLa;yU(Na=y%Br^ede4%{kW%K;027Tu z7}1ZNF$f$XZZ;Epp2own7AX9iL)PlzoTs@l%iZJ+rdYJ$;oLejNeWnQk5>=bObRnw z#aI7)b13n*BpSKJqIAey$ZGWPhH%p~H_)CW2)RGUlAq?e6HcbpEY<`7SU{)0rIntj z-96PZpyaa}f9w`gIL#p_9NFt^8RW<_7yGRwaz&COZxz{lI%~e#h=nt{a3O*{sMYwL zirbq>$Z)5pA}Wi(BM!0ai2HNz*+2L6&YM3KEhw3veYPA#=J(wIx1ZPlp4|zDx{66z zXEA#?1Zk!9E(=rXAn_1UPe-H zx7=teG3$j`Katu{LDXc?X zP)g0Nf7z9EImWQGHfGN9_DisktxI;uEG;TS?DDA@9dDpJZm2q@w=TYG&G{v}VN(;B zAUhpi*|&?cT~#IP$!ev@PQXybFf<;=3Y$(~N=^4qPv+A?jPLC!b2>Gd3cB7&HFrzZ znGgMbE4w1#xF4A2uGf1YtQyAS^UZ~w~XUI%GNch10|zuBNeJ({WrGHvOfiii2> ze;xJPkN*;VJdQpdy!!ady^jy~K0f&$n_e+G8`KL~kb}a^UdE|9dbRtd_dXsD3q9od zkr_~jQ1DL2Er%SjY48I=zIr&S|~f6equI#0c5xU>Bs*&6R3?h{&6$c@MN*cEI- zurc9h@RQ{v?pri}Ia0Q_+Zr3LQPWxrWn_*IjL;Vd|4Wym&oSE@yAPOBaf+8kGE6c) zM=rW({Nkr3HaN-v8q0N6dX5%MRfScC+@G}Vfn_ZahvZLe<#U1 z%KW`gk6)L1AZr{xI;J#|ZEdP;TRa7;LcVf39>+!UPBfzXmqTu~DBD+T@vcfz?PutyPam30hwC|>l)VCHCp7r|P5(!6^%mVl%=I^j^@tTzVJ z@()`G&pC7}8rE11Nv1X+I*tc$f89IL{Tw(9a2+S%Zv7<^KDutcr^NLSo9#3F4c+K? zX0a~ZjG8arOnwumwHY*tFmuS>n6VD^EI66#pF+Rb9$RF1dzKr0-I!aO_?yGF^o?7H zb4g5frTP=_UPrn(Uum|<7tU?nBQ~1N;qS=`#3?AaOYpI>NvL>9NAm7We}Y_4!XIcm z@{+LAq#jSE`6qa5?a|qBK!y2aFdKmYwJD@Eq zh}(8^eXyt6?OrJ{qQz7f3|`ATsEj#IGelT1+okr z0W%~KaQ%aSh5)X1IkA6KmY36b)7) zmMs+v_BOF=f6Qkuj%=1!;}|~RcTXmHbpuE4qaw)xN=pHlW`Hi#g5XGCH8C{ZQyd#i zMW3rD_vlxWDG4pw2!K?Z;s`>>mY|X*%;F0AT`jm0L=a}PA|2(#93w#x*N-tN_lEakyBgriWKg% zt(d33H^n@C;EH)>i!nZYi^_S1a_*s=XDH{M0D#+ah_e$GOYKWEc>9t#6yX7>)Ity7 z2zjGkf1X#+yL(I&GlirLVcj7H!_*Uf?&>7#D(B@oZ1ifLN&2j7mpgs zVtjdwH0tQnPpREiu5?D>>zR{i4h!5IylIF6-9=a{i4~e>slRR2OvgBk~jc(-<+j>+myLSE2z? zfntDnFvae2`e``Gi-y{Y`VVFq2smwU;9+cB<=)J+ELg_kNEo@uaB|ybHNm>ZluSD$ z@=D$`or#IVq!9qr%*?);LDJn}x6`08i0H}HmH{-cbvfjakD0R3!pK{{>o!WlzINXn ze_}_7$1m1EV1c#w%PBUks+&q-h|ix}1N#12!e5aNbqSrLzpochz6hDMJAlgy%A)p_ z%H$!)?jyp>LM*#-V94?w=UBn#d2z1E@v6C!Yo-*fc2#Ywn$(T0c{cXHeEn#XF4o4A zJuk?K-CCmT)y*|7$GFR0sVJh$nxVg*f8H-*uUlyKT69=HanZ!U?=1Z3Ew5) zEXqYLFCkR#@>gGRb)(L_{AU(3{ZPl5z@0T2oG>H|6(W8Afj##LaQn;GkAh(lr~WYg z<22EL<7!FIpCtY9mrtMn@aQiuPbe1oUtXS2(qlbPUrHDhb$0Un=}9xq$?KD+f06)V zJPFW3wShaC#AI5?{_i{zUd)51eCm@t#lMIeYH62kIEtmN$j5guC9y}LvEXkN0a6_% zRU*pGnc*NC0=*g9MNiJeqae&AK^R;aNOzLB01ao7=GSWfaGzgEc)z395ecQ}NC>1+ zPEN_gZL9=XRnLC?j0SL{4&!SDe>-z^rS(PX*$^Ob#$=MRy*Sn3Y3*yWA!`gk)xF4l zIF^XPT+9fNxKTvlYLI7liHC!^Br<`=IfunQ#hX`;^Sl^P>~uN!CKHukWiaxzSTcMo zkgzfwwAg8SVOt&-7{o_KqL~RHT{kf7N1Dv|Woe87v7`|RM%&SGjIhu(f2j_*FW~`A zwKtDzp@07=4@CnD>!0)%Qj$;*;3Vd_!kofiPF&3zVucu}N|bIvvcB}o<{Yo=$J z<=z-4GCysbnJ&p_trW4DX@=Sx(%RsQpHt@Tn?rS@YGKsDURFiYo1zI`H8tBUzxi{W z6pnr4+tL`3$f#^C!zLQ;e@Fg}$WXmDoFBQ{6i|Z7(X_(CivruwsLpV*nYvFIR&i)x z;hGq;Y+sJIFUN_LQ*&83_y=&wp36pUL9O05T>>96iPLf$jR&xhj5OCj)YTo9AU9zrOz$&*#AS8{8QSqYHrie`$CiaP3i*f9L5%Qh8njcRW7; zBxDc#3xLOn@V`gVZU;=haQaS5U8uOcC{^6U@pXE~i!{qRe|aI*@w>0Ser|mF(t`({>y2PUc+RU-{4|VDkCB0cQWhY%es3~_|=b%JD_8ip&;>%R}=v!JbgP! z^FkN$;mLQZpW-@3e=q1fybi+bg0&Z4W`B&KkO<~QsXG{(5>X4jZ%nXtC%Hot@wnBi zBb?EiKgW6&KhP|mX2NCesl$U;r&*w-+pD{AA3i=ZJh$_IdHnnUS1B)C7n@DWC_+GdClw{{cY{Tz(Yea6P>Q!7`s3M=@ z?toX%0cT?Yf5V(k3o2rL36xBkiV7Klm=|ZPu|!n1L$H-ZES-z z3}%08i%`B$s`QkE<^pgES+B%-C-;?Wnw_n!EC*I!tomu30Lv+6jLAYzau?DfO#q#g zsx#To+ud&WtfS7(^ZvAyKj06ABG0-PKc*C73Mf_je=T+U?BuJ1=g*z-zxqsQpn zB<^3tL%PsGCfv^_;C0W+qQ70~F_sGsQe0;u>QK48wFO--3dEqsr4Bxy(d4~LKzPs* z@o7U8J-IFw`l=AHG8r4zK%z>ff#vq2X_5{iS<(!_gJOd;N7Qm1q}pUmKnUgOqG=~1 zoVd6Yf7m_fFKH;Ea9q{j|JVNxbfSa2Uq<7Sn2~KirDS%qFh8qH#~JW zoz}r~i6V27MSv;PWTsEmK|vlvP!TbeGj$ood0bU7uA+*_9G$8TzKOK37#q%onfwD0 zgy{qbTga8=SE(KhwK`$pE#uJiM|zC&b|3%&QCVH5+CnIHxosj@hzTwYgmLB&L>`Ug zf6*|D6<@dcYugvI*}Vao42yVxL3y7Vr(8-?-3gdV(A;F@dGFPLxijp#-zog6je?^kIvIrePJvxAVjU)J)hLFKV)JwMMOKp1W z$3DX$h&u}v`Klmu$#RtEM8vn1E{YsMR=r;8bh2HA3F|8WNjPV%xeVrj;fym##%j$X zBNOjuWKvQwzxDBS;Au!V+aGLag7^55WJA0&ZL8hDxRE|#BUW`DTGmZaABN`<$#iQCf58XBoNak8 zB;B;>RS{<;0vp=~c^GXLW4I$|`*IO6F!^P3W;u@YW6@x8{U;YwiY`xoconj`f%eH` zS&5TEpC@l|xyE#zz5M|}?SR-vTTSV#Nctmz79i+HkwhnE%^NN8+1nqE>k-en0j_@r z3Ed0{w-4q9=FMhTJ!4pWe>4xFEE3=s5`x#typ6diu{c)0)qRSqz+%?d9O?j^m0aGo zwm2rs$=A=3z(h>-Ko}r!-!tfFgnqyzLZbJnGm_0$XY8&{GI@TZHXhx3w5bplC@zw` zROgWRnM(m*Ts;F`-KNu%9c@Ix>({|C9mbRKMzBf*o7pQ5#O-1g+I31A9LaBQ{WJ=@(kZVOf+A6 z#tC=<#zKv=JR@r|f4cA0Ea{N?`pDj=)S;MD@FKt6&(3KcV z3S7Q8REmxQXvh>ygv~)U<2w^pkda%Q#e)Iu#W;P2lFt5Mjn9KI;NH_QHTwb(6XZEs zAZI3z?JD7#-w;fD#3V`&NSFea^ZSiCH^>=zaAZEhvCiX5f5ecKyp8|{heZnCGsaRR zY6UAVrl`E<_I+h4=P~7i*@{JZEnqu_LGe$ zX^Eg@A#E}Sf1Q&15$FgP2Vul#cGZq=l}}7$nlkEf0~WS+Rwf?fiF#pS)i@0XmeLRd zXi<0pN@S#At~J)6gCZEM)TY^4UCXSWI0s0QmN|~HwJBs`lYztQzOtzQYz_T*7w~v>a zz(uf>6+caYpFxqZJYSGuY7IM2U`dd~X*5c75f}Z@_0sK|k$2PHQc~;t(YvLVMk~Wq8SvX=|pEd-l~cb&(Ah<5GU#Nl53!u9L;)yS7GC-`~pyR zO=8X&UG3w1pi?2R7PEetcFfG!7${1~wd?b9L~{e8z95^ieYjVGYZ~<-V*PO-Ia<`T znHd{R<6+{+qs&;KS?<(B!?~e=p(iDmw^8COe;>!`bu`eGd|hgfv}U7uq!$#)2u37~ z$<85B@tXQ z989Ys$kc~mVrY%_ru_@;j#-n)1c!_$#>UbuY-U3XzvciIhzK=-n*awSrFNMN%$~`( zf9XpGPV*)f+<8By@EW|%mz&tuY-o~1GF9hOQrI!&V3@waP}3cNoT<_{BV$Qp6GuVM zOe{kxT8;7|dFSR>cnLP+h$O~o73r2fk{>?@5oK`eNe>x~(ujlJ`TUza9j>>*sEOWbHdqw9^j5=cbE3ho8!^||?3bfY8R}r-3fe?I z3uka?X@mMWvDVUhiB>Ky0j;IjWfF&)e3qCfc!uU}!Pf%9;4h0P$p-rEa+IMxe;>I@ zO?%N5;Ae?93T&?qkd7r4#tpa)kCcT^Vk}@UUU9!4dFNVm2_e1d-QtVa!t8Vw>_2`S z9G;NiPs?B!i}(tsZwsr(xK?10Eis#^pqfv}W@dA@+j^uQs@!qSM!7~PyI&n0_}3k8 zMOB`JcB$*moV>wx$C9a95DqW)f2z5XC1lX;H!w%kvDMqwp3OBY%QLV25P%9#rGh-t zkY%-gbDOnnA+-2hfV?^SNIFSfJbHijsl*7Uf8!eDt|(F5?@x=kf4$^xpPQ3-JmMtb zc~Y@uu(k4Op_%QsUMJFsrkPZzLHQuSSk%BpnFB&uyE|CRes_b@z=?AjfBCR&6|sJ| zX;?kyyjI0!nfHkSG4Q_P2PVNk<4cGvgIgDh2b0FJf$9E|5@Wb{ahN&2z zjPl*IO|0Ilc&IM)wRgJkAx5XgM8hz9Ii{jL7o98=^|f{f6aYFGyA>mdfND&}^}u-T z7MjAQ2B#lt81^E#1nDK^e-(`^G?QL1O{zSDc7W;g7muRwOyIOpmFNOo2ydEYn8dj` z8_mElnYxvqnr`@HuSg}y6($%LC$WnLI*peUm9*uuLK3n!btx335MF>}9VV6(IqBu3 zzqX1u(>Ss(=TOIyjoZAiaWiuXyW%PMB#d%DCK|xa!`LNRzw(k1e?lTq5P7+i!sK9< z4I{p@VUGw);4M||wc1vSqNwaNO)IVMM%igZ9D;tofF-B30~y5SsF%mZfH9I;A!cQcJF?TLf%I=XNn^nYiMB5^35+`_-_w%&Fy0LLw70KI9;BHk+Q}`|e zVmuxg4I6BrX?t^!xveeBtt=j^RUL0 z&}!=Lf8tp=e|r7^tdea}rxv=e6ZmfOswFWED>#do;s8@*Qa1S%{i@NIvO-h<`yp{tHrrE0#|?u#QuKOYPIo~N0G=-udYd7!DoEz5GQjaaZk=cdGB zwNX5(oNwh&TzEbMR;}HFjYU!`lqDh)@PfW5p1109f9(&g&KC6{Oif28+qn^Fh>Or* zt=^mn+(K3{48`_9Uy`9dTmOjVsGUI*BP1SXIV8fWth9g7x|8uaOs&Hc18H88Odd{) zHf4~8c8H9(@x2dyXu7gO_SBmex3u{_YvgPp(TNZthu8l0rggBFs*DrhEl(+vy*_h+ z6}p!wf4pHnCXbL>OJva`K!?I$;aVU&*KF3=Rn5zVy1&40tav}6X+dHXv_$Gq+Y{M7BmTfs5oo>l{nB_e~#4DmKO0|VZ9a!1eWWHD`9(nVJy?zxi;q_B+0Q zYxzazcg4%f>@sVsoL8^6;;hQ62lXHf_ec(Z%M~XP;IAW78iyoWvJWQr_UvK;EnWL6 ze>1AERV(%Kk>bs0)JO`#H!p)mqTX2T+p4wr8Oc7(s_}%nIYr>AMTc31SvPM?yM0~V zs!b2`QtQ1}QUgMRM*ua?$4S3jwT?z^CM+--HZQ%!D>@G?ewW68o$trDJ?^E<+mcL^ z-~O0IE^Xu6mocng5>lftJyW*oT3#Xof8Hz4Rh8>PZm{m!e^)x> zrF=h|SG;{KwpO?{nIn>@f%SY}tv7x?zc=>1R4~Nw5%$h%6$JUb3eXGp&Crq(@p#*W zQ}Zhc^7)n6_m;DR(@k9eRkg+s{^ynWqF(M3%9u)!N9*I!t3~ zZq02?FCmCy8cJpj$s`4PvT9Fff0n|%b)S{@*}F%AG+d%gm(&$%Ub7HysauifRX3+0u@EJqHULjq%MN2++WbX zP-(kLeJ+bJu(Mj&7QV>HbIVn#@H3fPHVK7i)spE7q;1i5u2mD{LOn0+irf~vNrO&N%P@SHTkK{v5i9Qdvo>3z62R9ZQ&z za%HI!{nUKx(;1WR4dbSaJFg9z2@gBrIyyDi8gqb>mOYIxG}%V*f31=<70KnI3yNvg z!Xm7U4T+4FTKS0@YmQ*D-fO{;_G6{hMo#-Pa(nBIL9D{XW`R4Fti`5xYTKZAk$zZk zjwOqA8R-5j8k%Oo9-7FKC3`uH`NgB8uP4fU2qn;FVX^i3^26fiG4)twA}w_OYSinb zG$lYTLYlp7(KuRNe>)D85^fiMvh7zl`Jw6Vm1{#LslLdT2t-?l5;ePqG`0J2e z0{g2vuE*r`3=?iqZ;(5z+kI-(S?Fs0&`QOf1N*5is`oqsVk%>`LxA&a&n&?g zT+qh`-(g2RC}Wk%XBQF9Vb~5kbWE7R0hASo(!7n7F9)jga?S3c!pKy(?XnV+8MH>p zM?)nAJ$euse>3h|)Yn!BQA+b($$P2Xja1;~ptE6;-Bu{N(i#iAFu2;f&cCH)^@T>r zP~_3E?6|enTQ7wMj?k#&U1M20i^f}5I-{^~b-Pcd2?S06;Q3qE>y<#2nZHRqp0|v- zuc*C!e_j5@+{!1b9^h#6btvrHPw(skX{P0K6IF=$f5Zkx*zH=;EQfAHHK;P7-SLmN zu7~pyiDrXga&Raw*i4MH`yQP%hK;v2I9+~GSj4t)C0Nr+vkKa__-YlHEJ5)CFK0Hg z#f)2_Tt8dO<=a+e)77pTaARMs##+vxL-y7IISE$;#JXs#qy8w*OTAiEjl66pmrfK+ z8|kHrf9td5Ti!1tD{UFlAg8qxF(T5S8mKP=_q`R@T}$?MO=wW7QOUkX&9jP_q2Udx zUs9jdsI#HZ`obx(f(qzrx11$WqmoA67E_|2GOLwZtsXyHsKKg>vtgmy%kzu(WSg%{ zF{^RTHrw{Ray;5$zc*NDb1b_eR%}6g3E`3Nf2t2`HI`rEuDX_`9USr|;7t4&gJJ5S}sTOSG*8M^`^~fFd9?oideJ2lfCG(8}S&DP3_RJ`V zf0bpG_%@+cPgzoAG)h+=rurELvAXGMR`nD#>BBT&W>Kt-!p9knfHdh+f0$OxE{knY z>FbPk#Djrk6qUrJNV0x1S)eDK)s(r#k&W75AWadd*dvo5u=z6zl=s|xRx@+!ZHLTG z!BgLG&4$k2YN85)Cg@g;m{n4^**q}Ye?|*f`}Cfb+d{&6CA@UAO4e>cx%J)^2SwGZ z=Z_R?yxs@{FY|u&yHdicWgUCV*O%J9=K}WiUbkJs4Fy_l5w|tBU6UpwF`D*n)rOWr zoTAM+!Zzmbw)NFZ2V-w}mBA*mP4b*Y%|QWqsxDkPf0H5y ztO7y6uimox$bDgQb^;ta&uHqO**F!Qm-kgt@0Cm^LDniKlmWK z+89vWc4N=5$Ea=ZdYfmTP*Q-n9NxAybIJ=hpft?rG3|ANBs^rA$)T@rImjeET15^| z!4+z`ti&l4yGzTKFV#UJeu=aqE8`3e?3qdd#Do# z#+)c*Gb50Z_~4DlaNNrKccEp_W>?9P1=OSv5+FaH>C4|~c*qBy&K>e6_c~+!x&?Mt z*)GEkI>{~~_Wg(Jym39{&?y3e>yV|y8~a-hRA?i17JO?5vlHriB=qR4ybv}g> zg(Dg6`CMG5rUvMQog}Dve}SS60vC1y!yX1kanT1mCeWyRF)L7^Z9pwZVW$nIg#xgJ zk^MM0aG?ngsZ6B*QG0AbJy08fSpl+oc1EE}8-WQClOD@~VEic9K{_2K87H0>fG`ev z;zv=;BIO5Ou)0%6cRnE7Y5_#8}# zT;L69kQZ13^G~wgCvio?tFr<9l-1Q9J%hk_7RSw4rR>%y7iWv2TztH!j#;rO&Me$# zJt_rCd_iFY7Zf`?yu{g}@DeLm(To~#HZN+#(v>U|2SR9^e;@V1h5(TKOVu?ij>FmF zI1URYc|imQd(yRqU8qM{fPKdjotYgk;jArQLM>dvHfr^`s6{<&#y>b~kAGk>9U0-D zqt+}gd}dICv*m&sEUsZ@Y=TA&l(L)=hhV9t&>Cm}^_>A0thm*+%u=sY2Z z*ULB!Drg0~e`f-0f$k0Zt~vHio+HAqY%O~}GQDGne8?<{siuI?xsaAG7wJ?TA8el- zwZp_Os9;W@RSQTR;833&19W;B8a@Y5+EGGoxr2^gmdv&zLc4O?5uleUe(9jFHAb=( z&)Gw6Cb1zXuM09j0&pX4JdoRVq5H{1w?{#Ckb?=re|KS17%DFqYk!ySr33waeoRz#rv13*+Llr<1uZ)LPP)o&s1Wg2~@gC zS9Z1_H&*2id<5l4TtmK?Mbi_(FA@yesv(>J>(LH%obLYKCykpK;hb2!KbEQX!;qa<7SE-ir_y;iiyBUqoV+raGs>8fe~c`Q$YYUJ~P{Odr3A;ZGgTufB>xs9v4Kq znY7B^&4zC4od8t+EZDBd7n2JVT{v(9w!~$bf06b@(tEh`IN?*rjJw+44YKX_$2M() zO%J2BJ`0_OztX}8$n)h#oO18>V5n?&zfQJ$ZJ}-1RB9u73x!=qVhPyac>xYid`auJ;*5Y(awQfOeaG37X zJ2p=D>7C8)%-FqzxaG(0wNZP!r`a8=VEJ2TzRt#*)3LfaoL{2((T;8iIzFz5gdFt3XIb?2aK{j{;3rj?D!Q>+k>efA={ooDaKhXZufo|F{27k`eL{w|bzanSMK= z*evNaI*m4@h;w$XuPBx_dT^!ne}!MdlVqT-G)MM8Brh33+hat^3o18)!w*vJp=pQue;B-;;Pa`<}Not^md9+GC(&5A}5ues9lhtb1YVGDkR#KAB7!J zwau!zzk@$N9hX=Ne_%{$w`KZD0-8`YUumE+G>Zz>sWe4wh|~0%Y--M@Db-2? z9+WNxXFA4;gFgLj>mVLXYy4O#ZIG%EYQ9sBu4Fw#cuLVfLQj^^i}i6wz^L zOT?-Nv>jb=&FM8CH^GQM!0yI^hW;nq;Lw*jDn;XOb+tf5H|NzAFR^3{$WN?5GvHov zG<;B$0mnYk>44U0r43c}6|($d+7ls$d&j2F?(a5@oFw%0f4RXM(hy2!^1hQ7Vs`lS zZH&R+lhHH?RAx-9h>SQ}3O#e0rJ9(07P+ae7#4-Wt>FP@BOl`P=yIoTh<>WO1KdwL-t3Jb*jo{rT*up3AHNK&^{Cp5! zZ!{|1>?m&*e^5tWVC_iexa@aob%9N_JbpNS!7cc|&F}?l_B}_i#tr#VTf!r3(O~XA z_@^Aqmdy=2D7UfQU)aMdkGA2t%6RO~DUdZjrCLvm1a>+Z$TIwi*#OBSN;ud8x)QPn z5BJpLG%icS<6G8(D?iQ1!a`VC+?VFE3Zzt{pj>+3e-UQ8#~_RGYb$g)O_|zmZJpp$ z-`mmEHS-+# zBnRS~t!Lfot`-H_Jd=XER z3yp{jI!1^A=$a~BObT5EWr{6~Rb-J6g!Yr{e~G7Z0d~O~=yrh_rDz6vpwf7n^+z2w zPKHJmQ1;_gNBOj(Wy0(ubleUZjZ1&&T~?E_oYICUrWq||(^-^U)^rUpW91lg{Zz*p zF0QmWV25o5@mTRih9ccXo;Y=6AI7-&#FZMyxZ4lNmQ&O_63~!u$Ow|DD+Zb~t@gaQ ze{-^>hcg^6b1TiT8@fuEGfgt1i?7_FWrafK1}YcOm(yx8C56y9w!G=ji0GSgA1e<4F8eLEzgOlEnw?sffYdMgeZ| z1ey6YNh-}bXH`utD=f(Stq>Y!DnSBqD5{v)BrOpvLKn}VX4%TbSXi;HNItDw(SxqC zBv?39%&RADBr(UI>}z{6nzNaOe+Q`J%3B&$G(}|U2JcJ>+oHBZ#GW`}zxhBGWU^#ak^ihZk zorF%3>@%CleN3#OJuXzJv!z16*P#<+<2o%BdtoKZIT;<9knZHka{jH)=IC!#Sbf zCByuN#G*wm!R8--owC%8j^1Jn!l2)R5$%$l{v(hS1)AbX$X2KS7>0HRO1kvd>6rE; zw?s%h+VDU+Q@2wOjtN_Vf4hG)IV(d->(`iAWpPpD-r6dmap{ta!D^znK&C~qs)kTa z7E|{$`(0N(3B*{WIuR9u2(cWa;hinr)9jP3dIk6t-b7A9>E}RckE$;$$B8^juHt%nJ(t~m^kaN>v%3-Y=Ju}h|ucGwF zr>UE)d*m=7V3Hk-)m6@y4H%M%UIKi+jERZ=#o`T!W#sI1eKuYfMlkLv=2jVfT)lY$ zoQ1Q>a`FZg3pD6{e@GKzc5R!|^7M{5nZ%M?L{1W0ec$lp_~Q{w3y_5zqsF?0y0C8C zq!YDcpl#$XQ3nkFmH-}=ysIW)MlSWAOaZ2CVw7$CYG8%wy`q+zEH;!|-N3u-KzNsv z8<7~}w&*^koUiotRbC+UxvYYYw}3hnv36Q^)Fli`ys5QIe;NIRTIN!B8l%+i`$va6 z9f6oL=pmi?3`#RW7WqCQ-k907;hMnN!3xwV_S)<`=i41sIXZ^r8(+prN>-fy#t`iR z2bikc70s>JnO;G`rc-GBX=$c#c@x1YddES^`Ob%8TwrS>j8O4#Sm3;23samm#M8=I zInyO3&(dq(e*vb*ucB06>NN0yiAfIFtYVN8x5C;zYPv!7bXJ9q@APbue9_ZmhI2%2 z);8L!0Lci*B5NF1{gE)nrV6nz4aH2t2plME|)KTX! z79`Dnf0chI!Aa}%7;$ae^x)E?V`lM~b)?2q!|9ewETbn0GqJ4rngE?SNNPev$%+Zh zG`4L*wz*&{l4UtPwvBE-)vWJ>V=G%-nA~QFNOWjdpu`TZ-{}_nEO|@Y9A*MR5FBTI zRkq;wpoQ)RW67a!RN;|D@jREkAaXF75^D%;f2=v{7A^WfmDV$&1KV6UncOMoM{gwfmmJn!=2q9LL?vL1_%I9EWL1+B)%h64{tuRnAFiYs=d87zrR*z^N;^AriKZFX+avv7oGbxU!-qGQlHnkz~I4GQjp<8y^PqieAwD*@nJW~ zc|-WJ*kw4DDi5U&!~~|PF>eNhe+-}MD#^r7bPUOZh`lWhZrMb>Ig6N#P>VKT+w$qo zV6$o55+ox_mnBVIK9{^y&aAnYdTwL*LgQX<;3|e#T)-mJ76b<)KA=9W&i=HOX|zxtQ zB@g3DF3;#XiG+n!OLaD^Mx}J4Bjy1VrwB-4Y@8d5ph4L7#HgH&rx6>xHB9h=o1Rs_ zI&Hvd_8i9Q=Q-@>>E2}kS*%sR&6THV3>9ojK`)wC%poh^$X}9`e;;LRT06^Cj!sYp z0jillJAOPg1VGYR)@uG8%XyHk%)e9nzyu?Bl6WQHe#N)T-n3G2&%7sg04GS@>g`F$ z4-|P`vCoe&gmfax;LbQ0P+fdKvzND;de_?kZI?G<-dilp8;O=NIj4!0ddZx^st~L= zv?kS@b7}hf|N7sve=be*snKfhkZ2XNG~6L3$z@(S(^r<*!(5DSP&}~J2;vBHru%kx z`-4!uM!a519%2yauq?wIMz#ALEZ7PoMzn6^Fcv655qWYyyzJ6n9B$XZ@X#o`okF@* z$Qjzlb;yzRA1uR!qf+exU1;#srIk>IQ}_El!fRlCpD(M(e*kkCll=oEX(SLlG3Tx9 z9zO^FjdMNRXl({7zC0*QX{{6?`MJ!K0b0yipsur4H4f|rMqj>stQ_Ujbf88sX~?AA zs~Z$j&#vOqh|a0m=K3P%muq(>G@qrYatopyzI`68wM?XV=dG5#pzk#kA+|H}Ec(8L zw2CF7p$6fGf4mka7Q;s1wY)Q)EGH~Cc%we{docseImBiRff{Rnx+d(a8}*y-I^TWw zow`xKb-%v*?qlU8d*mnc+Oo>M~bM^+a3?Et)^s?tkxXWTnHbd4|I0Ogz1nn}cqiOu_x)c}79-Xk}n|B<#YY&mB zpW$STe+S};M>b*}MzVhjvXZQJ209l6T;<4|5r;_qNJ?Q6o@c)bl^>?y6VEu)tStLt zj|>s{1Y+6`)?TdGoJFX^5g|K6PS1=5sX=u-F3s`8-aO0@0adzw*|=}=H;ij)i_t3d zq&WkvfqqnT1$)r7XRgs*8ovQ7Eab#hjIT`4e=7`mnv+bO8>~1_eSW+*yo!uBVVB9Hqco|kepp(M?XQHZnb z-q^cZZOr{HA2I?>fqNX8dDeydG_b}qECbL02e%lo3DGDnCgjx4ES1~#54+yom9e+{ zf2(V9E&~-_cpIa7Zx1l*#?nYeHMBo6BP+HuHRB|>_rppA=Zf;*}c?@=~nr zEQcrqN?=cTpKrO>_1XIx9U_`7M#Lb7(8mY`XMOdwM8x!JbWM|Hrq$f9#>rbjnKb+m z&zQOE6G&U~4y;xTf2vI03G-i$rWGv==L3^CvTo<;{vHHL3$(O6 zPtM-Z+7S@xFlthFPhovu%T$>`piYn9&{UxMb*CqGHBfYR-DB=}8SB{=kzB7*L0MU8grPNSw1SS@*lvNL!A~ z+tVp~m3`2)_?g_!cY)^*A!9Wrm@t1SHb(2udi};Z}CIxg4~O=1L$%bLip{He>JOvOpdnQHXf8 ztnb1ydFMDWv}CV&Gk9KHINb*WT0Sra6HnMSU^dUfhrC-1U8p?7A&W8u!#ZL&KMWvS zi2L3EXe)F%$usto2@Uo?f4mC>cfK~d%iy#*Z-wh{um>^)j9j(|uFdsr4ptjmm4Ptl z=K>{V=4cUE8__6Bnr5T4!2xwZ2wf!{(8eKB8pN#*|BTy3LjnvoZlSql%|ckKD;+{k z!wjC6`v6~POxm0$ofj65p2_&gLtN`vKQj+{O@J(c%ZxjSKjZ%}fAF=LVHp0Iq1kwq zkTX+_o{(cl8q>`XDfL@8yo<8c$?~NDauFm)xX4&p#=hRVRywu_b2@yB?al&)`-IWp zgy|G^mCc&ulQm=@+tC4ha|xZBye_U)EKFsH=jO>Jd=$6XsL^Zw{Kk$N{8?N=Cv7%H z)5O&Ch2gPbuh7swe`=nust=Q8pxjsl;IK@Xzc=QynO7T8An{0C2Hy>)lTI>QhmH&V zow)|WYpK+a)1*&`iiLq-Vb0G&m&Df$>~`R1_TBL(mR1_be0^h(C(*Ozv_0L^wr$(C zrfv7MZT#A{ZQHhO+qT`?|F^sE!^VrP4|Ss|qarG9W!|`zdCo}&^@;l1%@s&#dLZk_ zYgP!l$Vmwv8zsyUQ#Sx~Q?%$bEuzrx!I<@ggYGAIgopM?fJPobE@?|S_GTfF5V8zi zwAz{%F@>aNNwexAk0I|i6^A#7`oEVSQ}&FAn!Qb=&}lCJ_cc7x0pN(SNm{9)rAA6}UDtCuKVU+N`Fc80b4-Zb$e>sWMvqxXg+I{YBl|WjavwHcONpfsL;Ge80R*{|!Soh0z!;`mElO z?0pC9HxQcRPYBR#YOS6jiCR8+pVnICqX#a|ew?}XfXderhTtjVyBZ@u$KW@OY396U zvdc%Rw}N>9G9tqq%l_cG%mCM#!n~*hJz3Habm)Xy`<6dxWyFS>u;kHXw{|$KAen3X zq|Etsp{#YY^t=t2%<4b>kxGo9@RLyaL<_zkLP$*Y@u~(zC<-b*g@dB0VkJ!w=z=tf zs795TOnQEvfyRJ?vIkdDB7nrVnE*rZSt5=s#64^Pz^lUG?N)<*M<+4_{3f4rF~U?7 zd#^8CB=}yt{k+3y@u-CKXf!MHkICy0fYHcV#0cHSqRln)6GytB8?6_K>cd3cC`i)S z?1_qcQFrzFP&k0(<;1~iT5Y_Mi<%tXY?%6m`;zr2VpzWF-Fzcek^9^7hX7Qf*_gBP@eX62GhMsCnz0j~IP)L~ zV4u*XyV~^hn!Hq=7+4oxI&)ILyz{ekKpxkhN|Q~+m)vS3I8bPcvs^)!?%QTyMYKcO z8_&CGqeu0>`AFa~P8gwA`GbN?XM{w=-WLhuXQ7{lA(;PhGp29Cwh2j-kA~W$An^KU zK-2+bNgifds84>nCNpf{<-I4&|0WU`;B;Ll?SVx#nOD<=3D^|A;XFdhP>mP*v5k%2`&C+5tYP48KYOUUP(cF$_Ik`C2De zes2D6mNeZ~#{@|5FXUr>rvpb}9av#|r7TB|01Heqydl}WT$x-`mg>Es*X7n<00Qkj zuwgt0yb$}wEbWeJpl}HC(eeJiWKU@yq<;IebYGBAelN|lkdIS`gSFa$>S9Q2fM1J; zvC#he0;n9UJat4`G$tzqcE7)3kF2vvX+!RbD2xw@UE929-@g*ih?@%z0{E$=XJ`=X zv?0U8Cq8PO4V#!+W|PTkqX(8`0Oi$TGV#AtvmDTxWoEk>lN`%`HLGxV$I{Gq1haEs z(A!T;=3tLDiJI|B9#0DOo>lclU7lA?ZI$+Zoz!q5wYAeD*<$>GZnv+hmeV06+shPC zo<_hO-67(Fqf>^CC}>f)=KPSLD*btlkhJ!7z{$P0wli{&?>qBa*E>*&fQ~L=J2M^b}}Oc>{@hE z4z>D>UMBP0sWYG@df!KYUaD)l%Ai^*vL}#9`BZvNlEy597%1>UlSXJu{y)G#Linn{%^Uh~8NR0o zmTtwMJzroWWse9!0N9O)IDBmw+bTG)`Z(6xLcsNEy4!881$KJ2?$}bj9099)u7B9g?+9Ld--m%Kykg0!^v@piV2r*r&p`HS zRvu$G{7F;q>O|H&v6dsQ4^V%pry4G?om;6vf_EHQz@fauURqp2hs-%v!eiV)l_6S7 zC{?LD!V(sUhyj!3Kj41959+YdZ1ocWS0V9b;)rCr%3m4UOt&CEdzCL|mco*Pf3F;v zdo}4Dy|2K%Fk!DK4Q~#H~P2;e3wJ+Xh3Eh78o>+LFkX)p-c7xD;}ld$ZmE1AeF#{+g-uuJSB# z$Gp0Xy5oO#GG{bQV#so>EhZBqc^Dm|7xy;O0AgMPZp<=nYN-4{rZ9#c`Izsj&>iN{ z_zFa`N*w5i)d(S?2uZ4&UlfbqxbNegNA0DU!ZJcZybh&E_Q#j|##B8knzb3X8td;ak#{2u-?b>lj z0A|6gd^YCgSp$=;x-$FB!e;p?Vrq2ukdM1=W6}ZIF$A)nCjgNX{t6c9Is!Q_pX8%X zyAZRjaRjExcLYI{P;T7vGlomy`=b!H{MUN0V(G31;Ik|fGLELm@^Yno^km(k@f$-b zC#BE^FcF?%wOR5JMu%L4$(Z|>zo?Y4fWA@$3qe>YF6_GrKN>P50YJEvo)fuSbteU? z^>FOJF6|}}fikhpRj|Rm!2PlMdg{pBb;0oROF`lXQEBnnZ0K6s^HotfP2|Q%W);H` zoRnH-{Y>Hr>&X85lAy$tBw|>I>N8HuemA#*n0Hw;B{BkCfuhYGOEFRoQWaofz_Tj* zSKQ*J!U_^OvLM8x?QmF;jHLk~XcXxZhOh1W`aV_*C2M@R;SeiNA9P>y!4pDAWqRx1 z^|2%l*7Vdh4_U^jsvnkAZ*bbcXsIAYO4e#)Kq-1tw%*hPddvd!5q!!XdJpzRdRR?XVnWqa$tfML+;1tr~`UvE3}BXvw%;lgO1CbQ7-K9CEtTqLY( z&;;le=BrguV%V#xlydWm0#GI`LIlcD`y^3)u_er1tWoEA@=W_r@EQbhvOAFJ5|_wt zrO%thtPY?|9k1cS9{hA%MesP?ZcI?yb>$f|bWnXLLpS=uR0jSR+G3B)0HSx&#Lzko zcRe3xk&sH|^`Byo3b(5za$HmqPx}C#<6>^gIOt59pA*X%6I^lU{Dp$UBrt1)Flynh zpaDmw6%dV`@JNCc%kl{a6;ntAvy0Q$F0;^LFYw;Sfi$xNm=pUfZ*&xHOTegGN<)4e z<2ZqIMHSmjlHR#EkVF;_fHnVJy>h{78M$5W7rE$*Y>1czyD8U$yb#H*x>@azI6;aI z2!eXil9t?w&T%XL9MttRm2qash!_+f56f3y445!7*i(XC*yx2sG;OsGRu z6O(oQ)XpU1zo)Vbfvg;(3&f){@%Uh19#iyE<;a7yf7mc;#AhTA01e}xO#7UMr}U-x zf)JaBaR7w;=f@ulN`vldAGY;6v~T3Ie%nDq@)4rdP3)NfqaWBWd~WDjKlcIsXalJ} z3kbrqVH!3k*$RHXNcNEHsvDM=4}zMkJ*4Q#Uvf zMjiNm4SNI`&Pd%kU|9;L&lFvFURi3qV<$>h({cXkbLfwge=!}cGiys^n}V~cKP)=C z+sAj7S4>nOB#PnwPeKlDrvnh~<5vYiyPA)``p3rAB#9!nyZtjE7%^S&fC8A^CTM4s zJL^a@ufM~A;$&#+lC~1Yrq3QX%8}EzoHf<n)!;LzykanT$Lv58>?k5&Ze582xpbu==QLq z_}2j=CN3sJq##`GN{A4(JN~tGQL?zw+S_p)em4&7Qx$^)z7oCt!WFxR`I&24gakm) zIi}?!4pSr#P(g<^mPztQG*0i0If|gnS4NJJRzHHf(ht&DQ38J)^Mp6zAo7i%N}@g| zU}h(p!%wEf$9$x1;_c0k=M5h*V041KOL}GL0ELytm0BF0m@zaYy~ZC_QJO^`u2vUm` zRFzfkuU=u5T3s27v5^(7wwCl_+Jo!lML|^jrYQOl#Fz4wzb+S zQ4Y{H0BDf~6{>8MtOYf`29*;_W{rFy<((Pb;vxBTuezfgQ_QMPS-u_b z48@H~VDt*eR@DLYM~T4-ygAk=6hvnQfyc0uWneLtRWOv-OzI>S71g^981ajg}%n#f2S3>HCgj=fVfOFJJ%U2t4p*`1z@sKGawIMLC_L= z19suua@H)pifo~mr@*Nzt1`#{9~yFKnGPN~F~L8zgRq9*IH*v@Ua0Z$p<(8ut^yJz zArg!PV2HU?r#@ILZWoVQB*8XXBTJ92>-f*2)$kL@BIZv z%Neo;!E8(thZAvkS&Qo6wCiwD>#KO8fTU1m*fGdyCbI>f3-z6n?n1E$d?}pQb3>(R z8}&vw4*w{wiA3wunMcK|^CJJ5JRJkdx+c|~!4geMhCe*h1R%$>1}&;iArXLy^7P;g z8bJF`Q?p|{%GOW}U52sMEp)`hmjK=1SJuC__T-0QyL|AvI^SL~DAtn+>yE3xJ9wT7 z#O&VJ&1Aipwo*G3(XqniJc0>9@v*Y4Zl$GmgL`C+xvL3vZsAj?I zGFSPW2mON)N(M_+xv+3~4wU6)Y`SR*^q?1w-|1K*cg&Th^l{w}6x<-<+q{f?f^KtrDab%QUY3 zfDkq{%q{obR00+r+2V!^a&?`Qd!HE&Q4U&hU8LjJx0fEW?0@UW-K(3cuaX^&t1*gE z!|~NR%S`B6_c_TSRWN-HS zB2}_kfNPsCTf&SNc)9CAJ}urH59o7y>Pp*mG0>u~tzNL^ikGrbk8?d}2V*xhoVjhv zyxsjy67Q!8oKz+v8?KVcE4y^X%-W9lajuRhT^2YY_-fsg@|{MRkBtzoDo1r0sdwDR z^s_=(&DIEm&RwUYo#h$xb{CJ&=H+YW>&@>2z;m|q_LZZ=+~!X+0_Wi*`=@)mUkESc zr{|%2t??AsyNhN+_b|KKQ`+t8R83^_I%yBjd*ioH1!EJ&d3$b8SEwEU$2$u zxqsXPko)%0-|~92vtK+;%ZF{_*%3L`a+`-+3wi zKmWhKmyw|V7Oy-jU1Ve7cv;J=K6GZdyd2&5yun*+Q+hFIMTAd zsqa^}zDaQ<(Pw&5I^TWtvH^NEQAvi34PXqYw$}<9q?Eq%-S{aXgFt(8DOo(p5@5N7Eb$GM)u43(Y z$!BKM)RYtN@Ne(^ljGvU85Y}2_UBW?j@93Bt99OcjC)g+P_?0AJCYNLS86NaNB`gy z_DrE7m7M6=r#q8@V<^@f8ez0R)u)4^84!ntkhLq504oh8AYX;$gqq`Q`F-$xdRSMH z7~0fEzTL#ZMIqGs`IjNWcFfKfeGlpBdln>bE~a8cBeR=cd4Q^Bzq&i$Pi-@HspU`R z=6b6O-aB0?p@pwx#<5_7K{lC2r%;?%ZkakBE zO4c*d0)`;H3bfN%n6`Z=oL-9(>?&XnMKwyMM?GSn0M--|lG}!{VLPy22zN?EM{h9N zfoujI;lvCT(FCHHsftz^qk-`_hh^vfy{n|P>$=D}(mg=rr3_Klmw!Sd7Xb60JdL`* z>|(8fziDT*V$`l6kbssnM0?9jGKue?H<#v+@Trg%pSSb0Ybe6;wTfj8$8vt*w2DR2Z!3@mh>b% zo%cvi*aiC!vOS?YF9eq0X;$fxWb)wmdi*3e?IST+8v1dAS?pt3tbj*i;qmLG;b^G$qvHW zpPjFGLY$rRGdJ5Q-6>npKb)U+90ALftkUv5XV{^h-^^TDCP9B*c3sm_1zrGmTd9k{ zA=7EVBZ+ z_O*dveSuZU)&O?{@P9$VJ8XQ8>2#meI=Q4mpNZKUO5+ZToZc?$HWP3nBT$Y;utP?H z`V0@Md%RI@hJ|B6$9L%BZmgBD(V)(7jYg0XW5ZAaT`~rSOb5c&H`9o-<2>o^7Uw!K?zoIgnk}BIkN#?Ycw%tV&$%WBxjW4|Jrc&uMOJk zB^7r3nJxg*P!)KKWLCB9*UugT95df?2d*I#eN9jIK>QJ$uJNG>%O54@X^m29IWthg zjSf3TxuiJ1I5WII4t0B8fN;r$)ZpLLmg9>6FF=D31@^c1;|ae>c$JDX=F8gj?@1#| zK@uM*hY_A19XG9pH4}~IRODFbL%7866a2OphRZG~QoMg}=7rXn>^OVde(r~Uk4y`f ziPVpLv-?_BA=L<^1lWGQxW{}#T++3K;EtG=@)#m;J}rYVlNx4$cVRJ#9gLLrtjWf$2(yCQ%=y27!-52WPGJUNlU2Ay z*NKgkDJK|jsuTVl{v`P{|8~2rHKmooxlN6&u>h};QOR?=`Vn=|Mw^X~c)!X{8_&hv z!Gah!>&Co0#qy5Br0N|2ygo82byl#ajsT2U2@d11U9^abNsUvqrHABBf6+}CQ~wt0 zXV(hciMvsK9GH06RXd`l`|fX}Hzj>gYd)%o{_`+ANpKCv?J@XE&3wY<=y4EamoMw1 zs-C`qI?KxP43=F0WC2SA`2}>$?))&i*a=~tAO}P&bQDqS(!*u^x_F9XJBJ_^ngZZL znD0YwArK{a_p*2ZbJ$5mM5CRbVxqO7ukP^u{V2~|LJBItKC4!o2S?JY`m$(copjmm ztWAndekjO@fFHry=ABCEZ)F13Ayh9Z-5|~HfkbPicnYbNrWXTO zCw~EtY)z0nUcgd!OaY2z^`LS64s*MeP-gkudr!7*mK*T1sv36c$)dj2O$0FPm$?ku zSK>8r0p+8WvaxWMbooeJy(^c@k2+5_Frf4Le_sa(T>tQns9pJDGmKu+uWk0)^R%yN zBHW(W6_m0LK#`nc|4Va@$3ueg$Ru6+_@^A2b|zDvdOh8+*nak_1`XdAF{Cdgx}E-- zwE!Yx?iYv-xH%tdP+}1;0E7(+C?HUx5~7G+VIygeOatf zES4OiVW$O;Md6%|k71xY?r?ldasg;e;F#@ajq@#=dG{8R>sk*V@m>=;=y1AdbA=`} zEIhg`wFsD_GxA%dACnmvJ^Qfz_U7fk8^e&c;S-f z%>r<&*NOrpS$=a!*s2>N>VFJZtfUTklD(7}; zpt@$94dhms5Q_jZ0GE+iC|Y>&drTQ#j#axyG9Un%KClqxH>O-9iry#(ju*(>U8gH6 ze;40nqOxMHqs;>=brpk;zc~Je0v)HM>gN?{I0~fTDknJ<6UC#;kHVQ1o^L_;VS?f_ zTfp~^YT29u3d4c^3(`iDryXrLmM~ulZM<4$FvSL{OVAZF~zak)yj;YN}E zt=6S>mUuv-AF|rJoSnUOOEQ#gh=q;U!RgxZjcsJa*BMqVaPoHQ=;NcIbeoC=7h-i^ z7f~RB6@A46SZm0VCFxzf{o?Ap*XXH3eDT=IWjD@%vL4%t;f>2`KaN z6*1FzT|AFhrCS_Q)#cm1C_$ssEsd|vHZ9`UD!gWiS&fTZhAM2+VPH_;yGq!rC zc;BDKi-+YdRh^Q%Hc9GnMz{4=I2c(N<)O&rviZC|Bze4F-v-MgD`g%BZ^xI#&SrJB zFf|iy9ggVQabE4{$ctYmkH`)ZH*qAt&JO>42AHkg`~L`reh3ViSey^e+hpO!FYkup z^js|gP-BfVFjVDT_02*c!V2w%=asNpqp5ik2)TN7yg0)w*gFluQq_iH-B~A3UXW*G zQ9Z9XOzVGJI@pokU#CT-=yu&z_!E1|eljQc3o-yxYd6nas*ZvhkmNPo%aIdV<{_{O zTD1?AGdH~t4-Q8K_X7(EM2Ls$g?;h+Ghqn;Li~?+yBOp}yipi->Vn^iT1Im0n30k? z5$F)FXjWf0W5^qN0RgjeE1QGI!LLL9f|46j_+2dSVnb3*tkob)~ zk&MkTWGN?~^oef5R-Y?$j0Wzx<<4J;6$OKq#o4&y$98rBCaEdk0O#+-M5nlm7}!_~ zh<4~_-YQ{ga`tqS1yRY9?wjq5xJ~6zi=gmNQ;{&YJS#D}C&3I!6gnVLH!+e6uwlE! zV#~_H780~0h4muFBRpD4ric^f;yr7|0J+BT_*|WvKtuIvfb0A66(R=js+{}e9v_y- zCZ&A`*!}OBZ~+@+nMC$V&`>ZA>u7T z5WgirKa^)3r^+nQT9&r;`m+}l?^VrQM-_hI@>Z#A0 zMqN4k$zb8)pLP(wz5W9Ck87v|(EqeP!(wP0X9|iU%Qs$ei@(2hP(%mKN@&A}#bi!E zhf~-VBok^jpznBgS@>l+Je2ASf@rv2S=s+Wqv%OV5rLg<$FEQ7gjbriJ0vp)v<5Pw zzY_hbCR}nIFF;;ol{_`}c%Z;tl6b`kYzt|^2MZK{t*P0ArB=yt^5tg$_yn>ZA$=mS zXLthA)U4LFYy%VyPO!m-AJhTm04a?eV^rH0mkoKGueUco#)zEKj9ZF{Z zE}|`|o91T>f)LS`LdsbM#8ChB(p{f!aDVVQEt0r{wiB5SWd?zhxa4d0OQ}KDV@w&z z3e0Uo?27wji+NJ3@xuN9elMvnL_w{Ucx}OL@|WiVugbZp`O_itCnZ%0Vjn8rD(#m~ zA4mhQ+ts;YKUx#PV-i?y-5j9m)XxpsF9_K~C`M3RMcjC>OmR_5jthbM>8eM`e-N!7YJJ?WtRrZl!Ht(;!qoLqH@$V|^%|JkKRN*Z&-gzL_t_sDQjQ-`-&gm14Bvmj0F7bM_b3g&qSLC|zF+aab>6#4 zIBVSvJyZ`1I&1%PXDgi_Pn?g3ffMHNdj1}W2hW}8Wi*0p`DXN)EdS%IAgtW%m7I2K zhfWRuVdA<4f@~Lnw;_JXTO&@Cz=Cn2qm_~6E%k>3S724C>$Y3zgReW}r8wK!h40l% zjAz5`ra9`(?0L7i9p|xq`}*V3rWmE1-5Jlj;WKz2k9N*3iH>cFYb%EN0mdPVFTcvv zxnETmUE;gWOaFouEeQ603Oc;N1)7J6F2dop@YL-pQQR1Csi@xm+{p&tu?>$US7w;p z*75G)?tPZnKfn3BJnW^`Wt*@#?3RWWJy-hFb)6yP<~1|@#}8a`;TnPWfY|MrY^_t3 z>Oc+tOZORCp0~HGs_-jshSP(II<9y8{$5da+pYT>v8fP#r6IqAnCrbeBTI3gl81L> z>OM!{AEhM#@vh<{hynW;`C(Ic&(B92R~wK$#FN=IfqST&7~L)P<`y)i7%od{$2S^; z_i45&qv-W;9BHgtlN*Uw+413~i1#sJI&dZSpXujSU%6Ms;8rP%{_<>)9>x27Em!7h ztH0O$GR^+xh>b4(xQ=Eqzw!0H7-K!O8pd*aP5>+(wr}KY{{HUw$ZX!3y2^gVv%a`u z_`VPN=GX_MfM0$&oyN8_Gj59HL-1|Sk@KM+c5+kH{SbWX&C_PtN_|I;r)2xSjRa$=?{`&5LfuOPej6&%`XaH+*z2 z*#NSS>Azpc?eOyk^~PKEz30bouliZze-w0fzSSIZ{@YLgC;$AvKKx_*PCuhvxRdzq z@SIzPZrwydp=_se=U|)Po|@3-*nY$~UHsoh5sj%$lt!g?sD)tgmFMv&B9U81- zj1Eoq!}K_rwrplc8BMy)Y2%N)xa##4^a+S%LS3J={Ex{b=RX1S|9O%7V~;Ie)aQ5)2H=Ina`#cK5MN6gdN_x+{K{3cXOPRAg=9uV_dQ?YN zk|pg4* z!2sN=dv=pouFg|YG~bMlF*I+N8RO*2wWf6HUQpSNZjo{dyeu0~Ja1P7{>D8@ej>jr z0;3ZdH`gGZyJ;7fc=knBc5zNk8^=va)|QOgT%Imv3Z-3aSO8gUFEWur z6h>(mr$m8wQb|ALDpN7cy0=2L!u$${RKBW<$)-&1DnWyhYS{~JV28}=cYtSn{W zN?op?Rmx6P?Wh1yOu{Q}6TWUcb1Gd-ulLqbF)pYlJdJ+9??cGcKPebrr`c}*Q7cbB zGcRCr%9K+sdgLEWWi(TY)fFl2S|}AfV;*IOb6TAybI*C3uNxbtoZ5S6la@?GE1N;W zQFYG&7l|vH#qW;mjn0Go_I!wa!|V(#O6)KFTwSZb6X0jJ+RwCEtI2Z|YU$Wnc3>IwXBfYra^0?Y9aV38NI3hSBX4laxWv z2{c4ffRF>~@g5>G17NzIfH8FOb9v?BI^32I?1>4 zSfWots= zN;}}F>$W$VbHgwHz{Uw6IcimWBo{|DEUmziiEmmedySpWSYnB(B|USBvlvZgM<)>< zHcg>=iBBum$xRDx>_TA0jeb%gIaRHkC|BY!nE?C0aKoE za)5RR#@$OKM#Q@~wzphrwJM0!%5bhcd2vX(=HsGpcF8-&u#$yeqt2yMs)pv`eNf7B zkc5QLVoG_;YArSei9x;&xShh|%mVuJ_#`PC7_iC!%G*bSB5A`QP6Qs1F8L*lQ!yeDfIl_#D2b1J5I`*P2@3FR}Mr5o-%! zMhKKhLHsJ*qE^-zP(7osQKwlxSeoUE;a}6K-_$18v#o|s)EzW5P2RfX+oIYuU#DH{ zcIi}`@)ubifz5u+8|UM}4gt&`Dr(I^tkHksr$fNLSFm+mcbaPrE{DCqY8{uigoHk` zYl(rz6Jvp3m6r}P%Nlb=8517Wjv4c2RSRERXAskOhjXV7g<^)>KTw7bOKQzo;e?n< z(t_W3DMm_Z<#tJd%9O{Nu?WL}3@*{5sne2{B``4hGQ-O_?qK*VECKp&wT_s;zF~Q! zFCp|dbzZ0C5)%f~GVj<$bS~MYypHHu&BG`hT`~`=;g_#aai++m60@?>E91wF5&zzU zDC`BrNIRn(tA`ahUuFOjYIjjGnl>V#lUF?3JIKlzT#0`tv5#R$MRtUO=)1%gDHYmL zEU-(}i*VDj)?X<`FacstC6nBQPoA_!iL-k4k`NyNs?Z~K=%r>!R0=2)w*AiYBus{! z8$Ei`Mi~{rnn7bd7cAs1;!kUPd}}n8t)m(*x^3aAP7L7?-n3PZ`7-@Dre+E>;yjB9 zU98&Gk@ibkwG~b{#qk$wVf~DgsEq2pmCKG0tftg3ElZBfcL2&r`;|cnt%!2qxk(%M z4%_-G<8YD~dz*CBRbhtqf}(j>>~hDBHFJv0$-beJw;rQ%8(wXCAd7geK1mV0OqWvt^IkVfGM$)?Z=&bLB78#viAQqNaj zi^E}$253oJG%AXSvrZjhz8rvd-mZ3o&C`NSgQXYHpb5$v0i%f5;ix#c%;$|dR?bMG z?2Ze4zeUxgb@F1EzI&;D>e|=Y9B!6pLcZZ0ddr~QUoKl2*12uRN_AaBB znNM%B7Mh?Qq)s+V9O=*=yK{w2jVKp3r)37ljc+tzf4tQyVmj=a)VxeARxfTMTvsXo z-K9|1>S8mPPaP>mq+t?D9lC}OA3mXR!g0oaN5dkU1_SZRPlsBKv;A0+(X0u<+NH;G z3CQubq`qJ9aOdslI0=VF)rX)V_*pD03(_Mqjy_L;)t3x8#LDzKW;4lw z;{LWh8<8VWz46hfa@~Cx2VY?5kZiYr(Dl4S{@qoMyP*MYy-icz@tX;HATVxqgdW@U zNKNZbj(z}q5%{-%ml&8c2&ZOB!mu`|6u>dp4_=9)V8^{iTTf#$QF^bNa@?}##t!dN zeJR_g`FHg~(IzA2pL%UWncT271A*_|N5szh@nWyr&B0gw=1zA=La5cciN!g#vI%1i zabluDt`dk$s{JOlWyB_A3snyF$s?^$(1Y(hM;nDt#8BhJ=;OK_wAPGrcC=dq3cxU2 zl5O{y06irWP(7wLu9R4QQn#u)M=(&K`dP&qf6unKy7LO>7L}#jB`b@RW21Pw7v7Vyd1nJt@+z-@WK;4N!ZLsDZd_b6RNO z;i*wrQaDmJcZJ3xQLuD=7L_stWm!VBrT&i0f%vmn<+-+QMAdNV1Z4`~ud-lXjW6uC9o76n{|8m1mo-Kr+eFZ^~jNg4}p+_Bxmj_ibdjFg4HCGf86R16MXGwLBO$^evheX5u;j4dVvWg$_YezDr0u6sg-Xe%0w@ zBt48I^<14a&g$Rmjo6;l!$oB-yfBjH0=N|z0mxMNiH zGD!sHY9ra^36=_=ziMY_=NKxkS+ou;p>`Zy%T9HrEui2iRv+$v9mD@TA+ND^542lh z&7iC_D8!PWm@NP!F>#$v%g+z|#wuEr*+Z!cuE%y~(NQ5C#$72%$hob1vCC0R) zvXp$0gS*}M%E)NnO?#C57R}Z^-T^gPe8Dibb1eLRcEF`2<&{wDvD6K#+W1&E3g2E1 z6*aVBG3&-AG^*?Jrex2CywZLxWtdqayT@&7%ms$8YJdkSQ>*0*S7vdJ2l-%ma2>f> zlV`hZwF&&e-Fn5?sdjx8ngba1@0S_Wofut`^_lidYt_Hi=VuO&C`^S}TzGWD>bUNM zo`Y5MS^y>fNYqN}{0-*|?u+F{zZh~z6n@%2FJhL+LYNcCA-8m@4@wq^kmVRlqdFyY zKv{+wB%$ks<#E_NHbUd=qkAvE-<@b+X84v|&bq$7Ks>i?y9L*rEM4NEabYg|2odLZ zZ{Mz3K@3y6tyJ~eP=wrjBMHwopJ2rErRyA31^`GTKmHzBT_FPojYe;<04N)kJ`BEm zZwzpWsThjtn{+P3i1g4xR)@BmMs4&MQ;K_nffjl&gf^*JSrR;gU_wxgN+psCcO0^P3gs;?0wwzwmh?jY{@)(66*N zKfY(yz6i8`Na*X6$nJI10kL<<5-kfCx(;WYSxQ0ri;+^YF@RJL{10`m+E|^En>#tJ zQAWMSwQ@Teho-Sl0@|(asHy1KRRnms5+-` z(FrXK56zxCD#JOyyw5G3`#YkMMCc0xCyO>KDHWnIS|?C=tc<&vTac|-kXc6nn{t*_ zA~S(fmmO<$FQO?@=&S8=4k9l?8StCVI(0aIY}nu0xPffxplJL zC`sU7X=>t9jBRE4CtDhPd!ZsK5My6fb=z;y;z+X$G?F*t+H-HIiN`QI8h~>onoTsw z@Vc)FkxIrKdtV7E%R^W(I64@B?Sy3eUpDHj#f8^*@m2?Q^5CtltCyFTxIAgFIxiNc zT#7y(7T2;Oh$U?E{V#c0;pwha_{51#R-~7A+uUxvsQN(!9!`ZtZ2?W#Y{rPpC!!!F z0c4c3FUL3Ho$~2Y*li<2>6~CL&8ki6`UpM45i#kuXk&8t?rdg;OCx| zpZc9O)tBrqPCfTkU|uq%4WMbaa8O`v2Q+2EUafd=I_`)<}NXZ)& zEk*fBO@Cn!J(8DGkvCKYoD;w&An?obYm3?^AQgEydJlt=NO8};0WdzJd24u$+s*t! zAQkA2l%HPBE?3-&-1+`IAg^_Bi?Z?PapK9{5SX+`9y+{-`vUWMcmM79;<<^NmNO#> zufu-GJdTzJaRs84_>r3Hn>}#6H!S5!p#4nRFb%Dayo$~*OXgm%o zLN=p{VGe{ThCDtI4#4bh2xF`sI!S=_KjO8>3XSA-Llp@ftF8L9r}0GR|JFV{BfCY_ z0l!sg!2VbscMb8>YM8+iW5n=Kf~{qB4<5Ez5biFU*`(m5UbcKE6BP=`Z(5!*rw_+x>+Pu+;*P?R9!1`sc9gu9)1Nk;SJ%*LGG z(wxobSU5gnW!_jA^I{~BL`Ou=t}Ar~uM5?|*9^wAq1fKG9?cjWD>9mmyzq_C`|6r( zRug@QL7zXetrrt=0R+*oio6e9v=L!xp4Jhu2rjfy*bG$W=Reo7tOXa3cfH68;Ar~^ zaw&3!feIy+16bR=R=tEYG+mpi{$4-vT*a?Kt}&>kiyu*%+i{QwV`ZRnwo!vNjTW+h zJiTy{aW2`aOfT{L>7)sR_g5YA^d>7ij6-x6HE-7&<&of5pK?FG)MenAoLO(|4;Qfu zP@h^mo4iKR_;XD`-`^Ux!-Q4(hPp?1%8(rD3JC<*28=MIP{|2jr<Vjp-@pC^5+s*$mcu$bDqXGXKfj^Z+)m2)}D*BF(l}KV}t^P+$UMUPgPGcWpx0u>TWp&x@$11f+(vb|@11|Ma`9zOn$Gk*q1QQ&57Y z&J3VsORag&P7UyQWTUM)<{Px}Ab#vPUpBA2j#e+g1Xj=v5Gdf^*BHbV9ik%xdc=}m zeG(2IDYw2+wFk2%B0uc8hBZgVTE<;iylxIi;NA|q1n6WFI z2?#kgNJfS%wK+KDsD2Nn@MZA^k))RIuOY%9FQ1V^n9&ITs&$R=kC&1AD3?UEop>jF z`?Pr*-h)W}3wn{y?xfX2o^nl*LjFZwv(w2fDmEk3qh5GVIY`I%ecd5>*r@fNcrEWg z6CB^Zja<1qF<^&n5H%#7U1>^cV+ih3UYXahAS~j=jU}PJKLEDuqlB zz7i`8*m%pPp)*72(C!oW?x6Pv)(s-3QAvCJF2_*o{+wN|<&v}4vn4k2c+cdou9fx* z%KOA(^rfe{+yMpqm7^%P^^IA)hY>UV7{9Hb6oe}>s8%FUwW~NL)jeA*$KSpLcsU(7 zsie=yRliOE$qMQ_F~KQZUY|TMoqWHg$MvToPYV9cb%()KsZ3zJtLbnLtE&NL$_^As zfi6kC2JiNdUv;f+u5|}0zJ^*PiYj)TWCB_#K51r`@SNDD)~nSh{kpi#^6rp+|=yWIDxdEj0{U17xF z9muew*=t^}$kab6#)eSlVT6oy9O+T#iWczusA?ty!l!dtOToR^fjM z-nI2~G!HT#Woh_wSPdzuZ7>RnXl>gB?uc^`8VjZu;3gF>0hYeFBQC1~5dC$ydH1U{ z#xVwOlx80Se%PYz_Y)dDJcDtuOeAvoSQK_$f5RUhsFbC5z=Ze6T!*(l;KV&#}#xE!0ES-PQKhfL)#%Nu3%bBP$iI%4M2%K~rV?>)$icy#NojJtCFo*xWO!tsR}c5$rP#;t#bPL-0V z_CSNTBdCRc2gbJmhrs8!02jGh#MMF6m{UBssi8sG6OB>!%aZ(^ImO9EuC=Vs3u?AQMigb8>B_Vb|siZ2T2S?9oM@0rAUV zCa|k8iZ~M;iohDsYfGmAw%va(xZUixU|O;ESQP_ep4SV~W*$pByr?Qv4r>x;Vg2$2 zdf-s!hOIzfuD5Hx^)8;Dfx?j(`)}l!9zv=x6z9*x*mFUsPVpZ|aF?i1aElxI9a zV?7jC#ADc1H@?M__&1d>&q%PKe+$5AWgM5Qn_dCqZ|z1mgzX7{%jiCck5rixkum#E zh4kLz&+dlfXLt=zO?z{bBsfa@>e^F);5ceFNjobeseQ{3oZafeoK4k^HFjKt2~4lXbDFvL zE(npKZyr+ISkjHG-&tjpB5k{CO03&qr;s%hS7EtWuR;l|*QgEv5(-nTOY9E!aWnx>Bf>2CvG4!mrd zcPzz2_8dX4QNxpw#O&br#Hj#FIyKDDaOg8cfpGQmdz~K7Ml+FRq`h5S>6Hcs^6QU4 zDSxt&y86m%qqh?Go_v8^BGFXDgFo>VnfE#vnW9T{34-6&LHye+G&HdGFZrFXq``-xib*SAPR{(2ySuqVJuY;ka zH_d;L?VktpAJ1u)o2AkH+LhrK3;I5T{2qA>3LJ6q{A?h8fd9G6Fg{O_4i*DoCs=S` zehW1~AOwN3@cCI&A$XRme73S0LGojzAAfKv{2)OW`P@mf?dm9v@1m<#V*6Szj4?5}?SFJHEdnyeJOM6KZ{{KW4R`e0Ax-h&?M z$9|(X{oa)&@B=-gRUy zVC_A^0aA%q4BzSA>lr-bR^V$;Xj4Kjm=#5k3-4Wi_k5e{zqLT;y#L6*!#a8Qy?B3J zby)}YA3?4K=WgCkRCLxHJch*le2{thdL8myNW??L2og^fWlJ*(p87GSi2~3^KGE2w z|2?a6@W*6$0>4S*Crm4!c`0gaD&e$bDi7HTNg}&v69R6U?2LMh2Kt@u!amJ?s^D0|FrI>oI4XI1 zh{y;&$>fZWm1E94$l`%lsM3Poo~jajtDXQ*5Tw#!{|~?-;B23FRjPlcp!)#6 zmBT%TY(UYv@!&dio$%@T`YEHT3wco)N3k7!%^ppYypLe1@KgnU)X##^8tNkj2v1m& z!eR8|fK6QJKye5adfUw#VGpJuv`f>}Cp7$~7W5lL#JIq;Y@+4o6LDWHlWau*c-obT z+^+CXG(_t~754$|A|np@?N)zBxw9@4aXcbUCg&Ks+5r{ChR@_@1u@))YvA8HfWOrP5!{S3UTg-8Jxj$c&`R93%b+W0a)wAnY)*d&lp|tCOZFs< z?kfQ1MlteACWsz{j}~|K#j&_WdKH%N=_@k&x@E9CH|on0XfU@<5tr|_1v>ALes`T% zj@GP2U2+z=Vi6sejTnv2%pL6_hJ;Ol^#~o-p|jXtm0ebar%w^`KJX(BmtgkH-2|MN ziNW(ECy5T|l3QX+20?!eTA)fv>r6JOP$7l})i8M&ZWk!`E+nuHG|;kIq);1f08s4+ zpK3j>+93@=20DLi9)chF`e`!`-F53M0lFmXozwq`S(s;YRLfThzG_I2DX`}#g3lnF z0fsju2NBum&rEx4B2JTB-Kr1|T`!=x5V%engvKIP=}1z5y~=-8qOL&nM?@+3wFVFa zw}BD~5IP%Fny3O%UbOV5`wh*#J`Bc6kJCwfMWE!(S{OeW{29?4C@T@;SrU>Z$|ACT z7T5E5JjYHkWx09-V9+4Yo`eJH!b4wm!JPvApp~l(%oX_-7?crrYo_`0Eh|rWRqa%**q@r z2;os$6{T7L8mO47WO-~eh0$!w3@Q>z{YtN1UUB9Gon#hrwig2v^9q{O88EF`K9eb5 zi=vT^+H|$d;|y{NnC0<&b1-t2fq@7{4wi0|XL6$aE<%5VV|Ty9CRS)P&SEt7x8sd= zLK`L08ZQ;-HYgHPlhM$xAnst$=8G3^U%YsGmgiYc|GWogLBO=6KY_uXyv(Yy57mA9 zu=!zMYqaE%Mt{ymg(a(O$7ZwDeKnRVG{s8gwR_HK+*NJI4jJ1G75NL`VJf*i(5GFS5qFxY$G zrW1cJ;zXhvj~^~i`McXP_>5d?CJ>pSP&5*aA9;Tof4~X;^x_Lx!9pA93%mDZR66(08fGscHXNQSIKJ-L9l5gTg1&l1kX&8UG zC9gPyH6o z&Mz*Hy+KuWP-l>_C?1RR3p+6T8;W;(S!hScMB11&?gX0<$1P)(O(8V^P}zSH@&V=( zw zKMk{a@x0J@ZfepWh(~GxY;3aw_W_JkII+47u3}rU#N^pL&#KuRQixKE1PEk*b;1J& z;{3_QrCSdFcH&eA=1w_<^iOV}VGsD$D;9P4y^W!0LT4i}koA(&mx+JV3CNYmh0+sD z-*tL3AWUv?xK`?)qXZf*?f7ICmo+-J& z?-wSglAfJOFmlX(1_+R%9gIwJ7tP)E)Zy%KK((?d61Se5WxX$tCjEY&+vG$g$A})Y zeS2wk-P4Ud!QAkAuxJIyvukLF0?@#%ihW-jdqYvQD7+vFKgN5L-U}9zj06;0O{<6W zQuhUENl>gnRSSQm$f1YP?}=rYk3&I6plF-{?h$foGAPaDSbTBx#n;i%SJ4+= zNp5H4wn``Ik6ahqLECVn z$iL`*Y&&mWUcRm#!5O`*Mmo|$%w-{7d_qh9;u9#X-jsjn8YlBYO`gdaXaMk!mwzs@ zvN&sP8O#V5|jz4+uOw>Hd{UHaN8+ak5PXU@%UtL&VNT5Y(x zt<~Uc>GEX%kN>J(q(D>=zJP+CPT*Tl!&GX~t3RNEMzH3XIw1%xy`?owg)g#`7 z*25$-y!9Ow>GlNbB;4-uyL*SrOnNig4c>C>u0SZ{kKp0c`_XvnaG5`b$E`-p@x~dt zw~m@)$yQ2k$n+>qdyN4P#4X6QwSnS#W3eRHc0BZk8=|+(rIPz3xvg+CyAa=wjeP(z z{0M*jTPWJVjI50UvvW$p^ni3KgBqP3VER6XN|+qoj#6W^BF~yIQ6{IGx^s&bQm|1} z`@7yCf48Cw5NdBrY4sS$VPbcYNcoO5n~tsG#$CyAVqK$%JemI81fz2a=t^QC!RKvK zjTP)O`b&NUr2KC}hM}8$Le-qhdn0T;Sjm5!GWt*ZR^aH~Dgv0CWE=Ex8>9$S*Xg$k zVRN-?5vR+l9A-$JId`~ugao*`kh5yxJdUVyGvt>#TgOHJoxWwX*2FmQvhGXu1`L11 zUzI0!_=?a0cVc^9#BYd;3GyWWc)Q;J+hu65-jWkBmWArk(?T_Y+JK9ec=5?OT+A1r z44i+ql%(TGMa{pd?2AvHlylI*eR!qVRuAmJF4JJ$VuG=WUtkSjy36ysUe0TDLJ#W= zJ$vg?e{KKnb#Lv49=^83Zmpu5eUX1K#g^w`QHGLtX`~CHh2V8!6U0F@?Mz5+yPW4r zMF9CN6ERm+4#|T9dyOxtOTzc z7;curnLj;06!$Yl4tVU6E&#$KR||rRr&|e6Up;~=tI8stC}<7+RTk3WeV(bpXMO%4 z%s58{*tDh zXVtgMf->1`ROx`-8&W+r9J_%kqC_6J$r+R88i&T)j+GIxFYBLX|ILjiJ*U$=OSwcw`wKwC`fS zFa9WwLR$DB?Lp)0B&$Y=>J`-@p8Aa9ps_%G%@{UmR;{fX%V{~r8ijPt+^6S;BW$+r zsO!UX;kVSUhRoj~X+1c4vp#~sHiQ`lxi4O^H7VrwjAF;8Zis(N3}zYKiAA(85`hVM z&k)MiH1TOdel!5XthFI`t2mhyo)HgMjbq^m-^&PzKtM)xFiart07jIOPYetXaWtuo zhTYa>AKT||xW-NiSHsy>_rwogzF&UuY(M;9fsi!uRa~x)MXqFW$E=1~dbbdEM|<>g zqQHER73!r)(A$6OJKf$o{AvShM|_(Ma&>hG>!ply(OV`J#_mIMNr+9$vm~jO&|IHE zz-jajfuVmQt4H79v}m2L1m``VsRAK-x@nxq@p`%nadr$)h5>P?RBT=#pwi*{v1(kA zCg;badIr3CAx2p_7Z}(_o#Xk2wo*VPfZry0wq(QuouYra#|!aI0kK$vd8u8MY0o0$JdDf6N5r&#Nfk8PO3v!_J*Ug@F>|x-#Xo`j ztn0p6$`pTg=R_<3urkPRIsL z4vmK3UKZ%$lKx4fFr(_b7s-wRA|4y-hryqAks+*&H@zs;Qrwz&bLcuw%}u&A^F2{QZR@$Y*15ZMS~ zzJGN~S6it%`*0!-_;owD$u+G~c&?m7InYbIR$^-0#WuF4Iru$GPbLd6YLnkddfL>~ z%}9SwItz$RlHq22MvkEJJndqXS-`uw2tt<56J)7sMfGlEK1ZzmY z9w%1n;ycJ%ohi*3>?fK72kyDi$L10mlIK1PHv}rK}Nl2k_uHYcnu0*`8EC;ul1`5f-fJpOs1x)gZ{;TcoZIst8AijSP zVvYivn^!3a7ZU|tP%Jpe3%yMo8E7ig357Bh+z(#N0wY1h9FwIXLYbJxkOB*CE~s46 ztU-QI;6r7znlPqXUG|H0Cv?8yN~@&=RTx+>z?-5fN;E@^5RwjplzE4EeSour5oT2> zzWE~ESj)LV5@?=j=UIM=}5OVSofjjYE=8|=nG3&=CBxrv&rsT+* z{G#^Sx{z?rx4}U?`&TZc+vO*;Kjfa z-OWzG31EuSy?Z3+6?%|xs`f#5ii}p=BFBuUGoAK>T^s=H(sQx{S&?5g z(~4I@^BCvk{R@AO5MqM}olk7r&T1J;N`6NmQRPA! zrnYnY;FBBd0cgq{aexw<{kiBLY~2OW(O?(A*KIX?g1vu*Lw3wwLWkm#vZMHy3Kkue zq|941#&lWAvO*k-18Vd@_hIa>8@dSIFZOZ5gh`~7Hy)LEUHDenru}PX&CG@;rZi1< z;+=R}6Wx!-4dQH(U2c#vVw{bggb1526SZ3(1D23T-1oh=z(ferI1pP(xx~h0~s{#+Gyg;BN!kpPljAfP>7TRLjmXkz*YAbbGsW*q;k0${zfG#(?P zG{u~g=8(lc=zmoxZ4s)+ctUy~B+q~gDFLg5(nK{F9KIYVFT&~ii0ncyFYkSO_UQEG z59fc+zI}QB^x5gl2d5WkETYS%-l#E#XxNAo*8}>amHe1}CAEQ-0uOJ>EVb6+bZ$)_`!{0o zwC!$j4kqf+Ta7hZYx`=k8485JE+n}Yz&w9I&xzhqztyR%4e_c?DIZ$S(65A0*e3OQ z>TUOZcO!9{u4Rt4Sg#L2jnpMd_|-<>P+y*6yj?j?r!z3cb)Rvr>k6Pe+_Jl&Ic;(P zwDWXI)|Sx}c7NB$6S+ierTAMpn*O0$znkFpc(8Fxp;VKJ-?-7(_&<*LhdkosURr;n z!2|cyd%B~B0-zWV{Jub))JEk9iLaCCZOyW;UGlZdZ5P!Il63xdXR?2tSTNJ`yQsxF zGu1ET$c=VU7gU5G23R*Atw4r*ntfulEyn@NSrvG#iv(8N57LE6uzWuqI?t=!=R z%5lLhQI2SSUyKiKPT5Rab_W*&apjD|EGMo3AEsO_WDMEb$T$MvLXq)<6{CNu1d$P< z|3IgWsogX>Moq2$4^jK?N7S~%ehLflL4pvw3f_)sxLztmJbV~5oXHw_9k^%~E*$0& zvm{MaPOSZjI578o8v)<69mF;ZGi%-`@zUENw!x`&XbIy}4mJN@d%_1)!d=hb)adZUQ_6g&r=&cgbA@4EM!_Bp)Q z?)dBaigh{*&_;L~hz-gMv~v*G-JzNr6uP;zQFXMh+RYv-8b<%dMe%={Bkg)wy}>It zez#Pz@rh-yeM#`)v}n7C?p<2C8JXSYygh|@V$7z8!*f#A!J&kE(U!w*v#ZNBLBzwX z9mxLgF3vf#w1uc+9$AgEe1beFh<8g_P$-?|$Bd&&X~`L?5OCz=A4w?&*cGH^P&LRQ zP@bGSBjcpICjPbKYTbWXzf@Wwz>}b|jD?De9Z=mJ04#@MMfU~x>n&e5UTAj6m8jt{l z+Vji%598OMu3&Yk-Wd-&fHz>!Jj8Ux)||4f5=(fl5xC71M+<*5G(Or__b#5}HRiDL zl;X?5#~@4wS~VJ|#~@tH?;r7rvT?Rx;&(8t4I2=rqId9poMT+)BRQVOsVWWzqW+tB z7>`w2sN#UZrUJ4VNj-IMBzF%enJYLmp}1dW&LnY#Ts2H5gA?9H>$2x87UT*6SBJ7t z3FJoBZf4jI-XMP`Ub>HZgEUK{=1ADHVPbJcrx3R9crxM@_F&f!#SijIMWd_&2alDQ z#&1OLS@h-6(b3_pFWA$B0N8VN6|3w1v6wB(=&Qr8ghoCyL)YFVw2#YMOt5uP;0%0FwaD-$QcurYFz! z1E;$J{#}bKRV7T4Ja@ES%XCJm=<9dd4KGf!9AX*asyx5E|8c{x>UYwi3J@%M>oyGi zqgEgNIuTUAe?<8&oc~VtMab+719Yr05@wqmW5?b`(jK4T&Kg84Z&3z22547$>%4!ytBv3e*8gmb@vuepXd3AWS|0k27_&TJBl`zmrcF(CdW^asbb`VOpDP~; zw-$%utE3uXC>^kHL%h3(`4krz_w4uH2P;*5K(13m`z{%PC})&54eVN;eh=g7wGZs` z;8Eze47e4s>U}VxYnElt$^m3b9bKz4{QaPPsu$d5b_ zZ&7rLi7{cVKBqsnO$W`Gs2-4_P{4M9dv=Rgz;j^UYk*WWH(W@B-jFm%VUU)&Wb2yi zmdzzK^guJXWw)hrJqN6ofqec$aW6yhB#kJl&8zYcIk>AFOsk5>;<$XZhl_~~zcKnS zSY&@-+*FB79_;#V=^gxY7Z)3kz7}%HTi?M*YL##ATj7PIS${IxQ+){<%2ds=64BZQ zASb!5GzJ626+o8ND2d0w}d^Nv|ap z8(HA4N>87A4G^9t&Z+yg6BAoIdM&V}!MZ^u1#@oY+q4E zjie4c@_OBx@)L^eGhY_BUO+Xfsq#$Y4-HQj+jDlGVa zM;J99_@Ft7Cg55O@pErQ4!(Oio=AU)dfe-k9j&5ioXT_@%Osk|Dwp|qzS{lXc5Uyb zkcpS#F_8vK_Q9KL8bg}B^YkhM_{K|}2@>wu0KP+lsDU`Od7}p6EWL{JEQQBuBk&P8 z4`SDp@{B3UT%il9FbgEi0v*=}Cw}?2f3J@Ze}f_7KX{b*Z)c$Rw=>oTkU@VPug8`9 z(o((Q8euBbA|pLM7LSpFP^(MBe3lvWbq<|lSlzz~;G`;z|5BmUI|3O3LwU(06xd`R zO^I=(89NqKaw0^^-MWj-i`&s%HcQymh>cE00wfV^C;gOVA2p+AALXG z^=e{sPjSx02e@$bB0d%;;wyi|X}UxpAqe}4K~haa_u}S&pU{m{p7-w2Yu|KA z_!00jW%teZ2}y-phto!!3(Q6LBP9p?$+u7Fy=@e>$pXFdF2QZoanlXf>N$kDSx?!I zT+c3JC`EGHva*!(<|Q9-KH=p1`Q{}baz5kwSGr$jCE%al^XHAd3mkt`UDmND(dC2Q z;~*PBqyA7grdNK;Z+QLlp4qQl%^+N@1TOEL_^$O0-BjEg(etM`mN4dB7tqL>R(iA& zG&=&n7h`G`-}fAvbyV8ZDj`ShQLtrZ|W1MyhBDaDtbDo9r;#I(Zv&3NRysDPXy zHkChSa|e1C2c`mTva1ogee|9+LhH}`*I$KM&0AkE`tBBxEwz6+o`~B=yX%bJ_bu60 zo8-0Nsg-JN?*j23P%-J%3~8A3H@|DGKdSA+Ce_p0Ht>kOUoDjT97mA0<<0J-qf1*i z$P7Jkh9k~lIHGs&$@$}c$COxYjgSSD(JmRY57CpU5QGgZ7Jvgr$&MIAIm3J};8dz% z-n6;Tx)s;7LcxFdXO_1y=?l0T#OW--P}k@>o+u7-9;vackT=j?tzavB_0$_$(d)kw zlpWc)!j5GQId;UWn%(1-Rap@J0MBYHQ=KA5PL)Bh)2WxiUM$D2kud?bV;oQ8aVVyt z!-iQugeT{Z4PL>Ix5O_$|4;S_5|=!zCw8$N0E43J|3rULNFO=cCT+2^{AjV(n3AIR z;*)Qy(GQSK>XSa&ap@F9hz5wpZE!ihBMPNl!#f_TMU|AX#U+?mBZE1I>%>dwte{43 zB2d}V`TbmJB4(q z#)({jpLTzli6hE9<=od8!rFaL97gGYPdb5dCl+26Weh>!=!~Ixc%7B2v>q9lYz~$N zRlSw~x%U&G+nqgvXERQnNT*ik47_C0gfmS9G79WaUWg};AO34Fiob`)qaQdQ&^PX1 z9jW1TaupZWf&D(vqQ_63aiRbv@_05ci}rGwG3v8iTxa>~B$FZ0 zQmpgZ|8fhjee~>r12tL&Xk)IHit_#$ddqZqmSiKDnAIR9prQN(`@qc{kO~$2TR_DE zoh{-bQ4$Zb2PT4>!_N6r6G;%d*@5c_2n=b~a77}d28^1x2ImHpS2J+6N}cBgz-fUJ zw|9TZNT*p|h+>{q$;1W&n43$_0j-d|y{4Iw0tSdfYT%2xsfJ|43l+_Bh)TdMMIWK( zr_TnCJ5B$%W%7@oh^J={&rk0@JQH`HU!FfcySx<7&L5qL2TxDWA7l15?&sB;mwp>S z&|mRdVFI>nT)_o^hpwV%cnsJ9zgDby7NuM)2l$-JRIo~P6k~Qd)+C6h zmR@j=KHI`bDBw~a#c71EmwUZLk;-K;&&q;2f+udmc{BAH(kQFQh6o6cg-sFXAyq=st{^kGrKX3p3@awNh z|Mbtd{xG=x`>zkbJaXTWXfq=##&UlNqWgs1K}+vie%yXxChJ6#;c41y8pq1F+`M^t ziSH3b*Pn<3=X%wu8jQhOl8Tm5c+mmAtVk8!qcP|GxVbfwb2Poj8fFzEmWLT*05o8R z*bVaOu&yS~rsX7{Q<*;kd2L>!^_Y;oTZcy?Y8{1>WZMOWwEl2TFPo?Ggvn zDMW#u@<=iU08B+A4xq2O6NCBSE+?M_kx3V{A?jfu11p4iO~Z9}nzrA7S;Nt8fG;p` z1i@KbDL=`o34S4j15gwX9bbQ!2Y0b=uJ+Ed{Kmim5p}UOwTk}h!v;jO+3d7aMr^vi zw1|#_>VvzaiPr%GsIKH6aR7g*WD-wT(7S(L*vBR;%XbViz=ZL9Y+Ftl6y;%k zIb%@M)h;Vc@8jkZKWg6Xy)io>?|Z&I2b+V7-)r#no0pFb)qQZ+ht_iuCt*?rvh@eg z?jp{dNmg5n(nYT0i{Bj{4c4}D(V>;!{o$+Mf4!-pM;jU%`on22$yrlP;DGIoGRt;f zoP%d~fBCn6e{fgy{_B4~p>u<`wQemAF5F5u^-c9~>IaWZz5mba>;QfPc%i7A=UFwI z_YZiAp}1*>nr~p7-LMT!@tabGd#pM}YIyW56sTc)Lyj1W|B?$ z4q?0N9y@>J`(#V6;vyy$OEgi5dBN7S;;>EB0V>MzIl_3c zYgveyN--G{#j|387;H#mK)}QKCx+3etEz=K)oP_eEYu{H=|C)RAHo0JCU#~a-{>(| zMpTYTKka+z5^E8sPEys0TorY0HMk5;Tx_6-I6);PaH{v?Vwp(frLZX2tMoVg;Q_6O z*2VojVruhUJ{^CXBye|Y8)q}XnQo1O5tOe$_$}x}6px=jd?;#~T2|KUb}zmm>T_wT z-S(>8J}T$hi5=XiJJi4J)xW)E{YUbRH*EPPUQ~+?{qlcw@5|Nt+1k5jCrg#O%+;@b z+pT?jyV`o9Jm59+w6(Sfu>MOGk6$M%A7yX^dcp?z1Gb)ZtM$xlVw_~gni;U*)eSrt z?~EzlxNWeEh%W}LHU^JnuEq+2YusynmQLs?NYqSfyA*O_ z!OO{UGHKRKXXr$YW1clg$_7d2WEmG|%ptQz!p3iH;KIJrj17$BWAWz((u>rxcEL;rD-dtRi!CJ{P}pjbxvhdj;HNE-@&I z-vTjLa-#D7->2w_5+Sn4wc{Doe{0rz!^`GWwUpcC*z27^-bMc+ps!Zq=L(bSQQ7m z**KZNXb-`t!R$IEFD^<6zCawm$@xhJo|GkcXbjOxGwm&NHAP%beB9r>><`3zHOk|O z7^zfEW8=Ee$P<-hvv{mi$XL%wayA8{Ffl9Is|m17B?!yli2{J9oUzqpe}zL}BT|1g z$D3UPz|i?XOk^=1Wip>|yBxCPCvxo?S<^s7B35C0@e%ABTQ=s1izJY%mH0+U@HlW1 zFk={+D$MId-U_@V=Y!XLMSbkNp180PtvO zfosQrB7|*C$E`RafJm5TS;48pTugs9B{dr>zJKJ@4&){?C(FweX5Ie$N%GM)$4d0z zmw~uaIdGc;d+@;N2BP;=IX_SUMdV+&z1#vfkm)SaLuDx6;IUR zV)7}~kDU5ij^igom{&wh;#`f(j41P---GwXPxI2jZC=&xa-m9C{bHX?w=C+pQ(eqd zth+sr4c>x$R6>&u)rD#MP_cjCKf1`lhY}rTok(RL3f3u9!+VuWIgZPfnLo&LrM+;-d9PGf8nrYR~q+oQOXR#2>;R{|Mjw-;7C|TWudF z8lLGA*3U$3Ca|AK0%0)@nom*FF9G=PuJ=1ke2Ow3%d)k^z}eCBNq_|Il6P>soP#%! zZ*V`k2KSI>&`iF5o<4>QgSD4W<%@@Mq|D}eR}a1-(K3I*6+3@|12k}d6Suzb4$$rfSVy9QNhJjhD`!FubP%Zs?pfBGAui0DuWpDHcl{`d{>Is>d9N7+=kP$x5&M_gNo^m4sRCM(#_{#Lcm3F{=G1c1PWK&G!0CO{+?$(V zQEvTBa1IL6FaED>48fXF@c4oqr|sl#+9`juwae*_bHjgV{hIEsdBbd8@W5Wy$5z|R z{S2^eA%i2V@lT8u0{_w`jKsBB?5n7AX zJ1|DRgZ|-C=7oBxm45Mrn;tJB{aZwe!200)_I<5Fv;RZ=C#n-#o8h#lT^fR->zb+y z>T8-}iQRwOvTz2`=cM@5EcKc!*~D!yi_n$;_(1dy+EV=v#6jN|Y~7jjK#vX%56L^#gDM@yFv2Bv2GaVWB6b`Op8e*Cr49as1}9sYAp5=T)#A@hD$F0+ zFA+3N*5IBkDlE6pSI$`6UZXLVVdph^hdpi!BxVq zjfsEMc{wh1@G!e3_c3=I4aQHOj>lQEusH(8p-R`QO+**0X*%Eqs6RFh5sU@)HdUzW z8W53T$I%|uQg_jxK5^cQ-5s91s9J)1YBU8eB#b`W#q!>51|TpCKRPE=6YJ=RnMxzEwH`2_2Vp6Y?dbjJYa{V zFgFP<4VcEpfFDcaGhx?x9z!IW?=E=Q(Yy&r9Cd$o10ab8<}wTgq4$E@roASoEp~sI zXGi)AaHMA+dh~haq8cHssQLDGbb7Uen&zsQBLucSllUT#Z}$q!Wl3X>?Jlm5sD1ML zu$}0pImM}W{3v)2Vd7)N7Rjcf0(i9q9rVcsz&HZ)yU#{{MD~D9FlRfk+Qyrd5I`7t z4-EcLiM=oWZo>W?cgdRfAglmi(-VI}9PBNXWZds%+ZR@ewpxK+Xv|L>J>hy;Vt=#{e{lfmqJN zyUf+qOMTZ*@Xubo%|52Yx_W5}_|3cTxIT|BDc*&+<;ECKPP~4dAgx-{BI19Z*+~>! zNo3N4qu=ke=k|y2c0(EG7vr&rt@6kY1 znFZLdt-n-Xtc{VxOq%UfE z!3vyb&mC71yZ3VmPL z&riW1r$Hg~k9Vs))wv`At|Zb!sW+>&0)F@K2q5Ac9m^(1=31rk zG|Lw_j~F}}4V#OYt7%c@6{QDZPts+cp}!S^n_J(!Zp>+x#&E**^@K|#M!>phCXCK8 z0y!e)B3#M(CDTrLa0!2|n&GM;ruFpRy$D#zVGpkdV0uoRT$H%LHP>Ac~zMuHb*sMKiDz6E&$QJ%yUE zY!o3p9bhmTbV&C!J5dx(nZ2_5?w82S*ko0BbDHDRb&aAkWmKML2(Ljr5}@&`||SMw`Y$|DU$L2 z>9f<94^A(F(Tu1-nO7r32|a2MC5#PCC*mkf4k-QKu&2USvai)45aSeLcPECGO(K|u0rzCHCgL*5uB zY%XWa*e~80et+BZ=B3jU+F{Wh98NeQ-!!fZ{@RJ*0T)0m@ez)UiIZ(MyPv%s4#oGU z56|zPK06EE)MI2ig8lmshQ>@sl8}v(nAs(bU}1m2)411jVrzlkP1G{URzz7CA^`bU zjWwOD0$h;*vZ??Idnz(efg&~MJHlFv;ZOi7(HQa}T8;_0A~UQ77ziM+J}qhJ#5rMO z8g;FH2l&`}!dVSzD6m{zZ$jhLH%SpFQIOSr9jB9%L`}=Af3FH+1k{69m$Ggv2j#7 z$09i7Q|k4{wan{llP2RlBLKo=yiJ`Qm*#AA9}L=6%gbQ^G%=F|GJA4n9a z?S7Q0!(@aXP&#;$$}p)Sa{7(rbssKq;O!5XInYt{)%GY(*KCmqm0xN@I5xDEstg;t z${=cg9bk|Kv^gAZYGPu`%pe>UOH4ul;62bIjT1LhYu#v55#``UGZJo=jc|`cx!Jzl zDmUAEO}6Gm5CEg%1rBse#n$YsQ^>2yY}l;N_DsVG(0TL5Y7Ch?*g*OE=&_1F{Pnrj z>W+6rCoeG9u|{k8^!g1lPiXyui9MbjeXN#>MrHpc>JZYL#l0V zb5u1kbpMa;?zwckG;=eLtNVD;3;PU)v+)&0Nw1v%gX@&R*IxTpei3>rui^qQxgiS@ zsoL6m;wO_H<#?e!^lOP(E0^fC{c`=WdqLef7TCK!FmgBkO5aCajl3kn@MK;DT zEE=%41eX__AVa%Q*PLZJAEuf2Zf%PD{zgJx228z^v z5RJEN)_sUv^Vk`mq-S#WodWpS$tsnLczj21J{uAlj=Bh)LT*$zeRC_l9}h@>6M-k} zU~o_>xi}ac;1N3*9B{TbjPx2DP$of$<648ctd&B?jifE+Wi|v8v!WU1#2y~+ejW2G zTXQ)AuqZI0jT2cElnGCwAze4(y?&h4f(OHROlXXIN=d=LN-OqCuW+<|Fz==5-4mYR>(M8ROdtq5)1 z+L)ZrWXhrV2SuHz6^Hh6!i(8@(8-zrW(6pqZSvzR1=9g$>9Y}P;6dR#&Vy5SRlus) z%*EtyFo}VNf+yJ&z=N*m3gUCP`4rRCF?t#MZtJv@Bi?$z={Cv_!0&B;_@sTjx%w{8 z9vvOsx()sVFt&*r#|sQx{pH{O-6AD?RYEbkUYH+$mAZ#JOJ6jyP}@X8uH$WwP2I|9(P^9-HCCS8)Q|doKS#>i zh8sxoU&y{hTKJt(Ik($D@jX<;x8DaFZ0<$Ty|bj#!|7rDC}LToH~xaUk_1 z0jLt8S2LJ99UXbEvUtKN(<3Bw$n%>-ZjLg43*knu(B34Q_69qNHGT)Jl8tx+x9(T! zTOQhdjnb?aumh2RYPz_lbVhVg?Ct8N>)Rq%1~So(1`T(Tm}*F@SKD=c`TYy=adUYe zHUIW&KM%lX46=D)b6>xg($9LV(MoAm0(V1~uLwp8DLuz!}DS<}mzAw>5ha zn%g_^7M*EEZRmUAD*jT*yo6X@G9!&v7SaYEy`7kg?Hj!r9^+ZI6psPufksE~)M#bi zIf3XZU7SBkY{^ox-U!h8xfPt_Kor%;#DijlI1q|{&GUnQmrC@sjoetW+MXc48;lxA zH3U1*$|~$F0zJ;-*&IB!3G^&ap#6-0O=!bm$J;1+_b3|!zLrnH2Y~kGVV1pyfT!_mq3;f3;nyb!CsP}g{Z*kS z{joR^U)|}z2edi3d~pAk{bI9QYhO2eUL6uDh*s6r=r>Ui@9%dEzd;qEx}%lh%tae_`kXgVa=V017|L^rd_D? zr)m}e;`b|PKxAFk2ZDp&>R5T}TWG@NtpfvfaID}M-c{g`;6osywh!zqn;Jy}Mu%~> zRNXXxXq&P460Y@bJ^76U@rJQsK-_L?RU;4AD>Hy~mw`EO*FLe5`RpaZqSPuP4#a0j zsyeKW52@{dA%k-_owLC^tsWA^8s;tBy0a^lnv~O_LnJN~T4 zsX;Lm4k$akX!WZCCBFRntHYz=tuH{yv2FzQx2*wI*;)rc`B7BG>=V_c^LI(3EJ4IMy0ha+FQR< z+qSxwMI^{vxLGrtvWAPX33iZSsh4T&BcAI0Cr)S#1QRGAtZBy-3Vkg(-8y1vtL@tF zNswZpA|lQVbbla(?<6{PZR%#!hnhO_Xxj9Im-HF54ygf#HyH>Ap|pfL3CTae_s%Y#hFsoFip+Fo+QCeqfY*q5Jhdt?UMvBNB%7Ks6y)=hL;G%$KG0NU zIVvArL*=fvyLa-7zY#Sbg>XWWLr}X1woor^a4YRcZ#!v+!`sp%9$c57m zj3=lK{DKU(H*b7vD&4Te-;hmz4sizFygVhZ0K9sp(SL$Q^Ee&HOPL((mL-J#Yvu~E zE^-6Wo*!hdDN?*XH{?axEhmYd?7EIy(~*R5IBhx~&jM-E`2<7OHrOi-PqA(fYlsl7 zMc4D-ZOygI6t+2U(HkweUptv#9d?R+s7i+^xl zEX|bkq{Y%>x2?YSdaWIt7f$#AWAF8PAvbG(GSll-TBtGytS>!;EnJ>-*q}XJ?)eEFk=kh>7zUToC1?r{eBa?Z4i$@fh%~@av14h{jl3(KCm2Chx@W-Z+^9G zCBKnfUh+6@Fj}6kQn$2o-Ix&Q%X^yZy|goqt$f5bZMKbhZJM}$y{wM|2@uZvxNZUc z!R)wz%@H)1&Xxpk@3O}0diBk24F(zb!sbZ1TqCEZQ@XLTTqop(5X|4%O!R7x+a`Wj zcV>67Ubmg~)^%$qJis8g4Uk|hF{Jkg;~Kzknv!wiUKDmM%DPWVt#pl4o;?CfIfNjQ*f9unmo8m zPMsQSIZJior*a_9Q%=fd0uY?QVm%V*Igr!JkGFM$RLuOHz5pQ*G8Vy-_^~L~RrJAK za9zCwowUp+qL=03K#vboKR^o*l8YniBQ6N>oDc5O!f_zL-$oD#EY)4w@TH9Nn)aW_ znzzwph#eSz5QjojY}(uhcm22$3CJnfJf{l4cxZ1|w~aB;N5)8X`t1YPBLZUj5g%(x8; zWv;<$$>8eF-kIBFeYhF4MhnbvJfdqA&*mlAATbPoJD1mR*d+k^qe~qk$QzI$;on0F z&BqL2ZnU?Cm7f4yc2&R~1^8JVa*D~h0Em$1D3WXzk8ws-I)>4ziMagk`9~Mn^97Z+ z@!N)kd@eEwTj%TlQHT6M8M<8TetTmW-^_M-#s{XyWP1o0CnyzW4fWX}KVA}6k}mX( zLxk#oZ!?6V)|8u*f-d4}aR6=zdIKA&MQscBAdT|?GP5RF{WKrX<12;L?IYD_pmDS3 zvUn-e6^%(ee0m9u!9V{G`_BjT&(LVy!LA+onvS=h%7J^`HBz_P2Tj*K5Mh5iG~I#} zJ#LQHy9Z9%u{v=hdG2?A`0DpxA07=hHukK4Lt|h3u1iagHncQsw$xtQ+&0REb9ZH) zP`+^9Eo`7w+b)8kWlamspjN}#9Vo2-bl}#TmXA9x(%PsRBig}c6gnr~kXkJ<1Lv;$ zAlY%60==y-Z4)26;Rjmpg5?a;Pslb_n~0IT3?EaE%`<;AH?QyOHtNxNYipV~Ju{$x zb+LhV-Q5n&uN(ERz@#{_G@5ZPD5d#plt0#03rr zk;!O4ov_PT0Qd$|$RNWA*fqcdwYCd92shOP5U9scqw`B6fZBox0F$l749HzNT@lz4 z($cObM5X0$GFX!?{iLC{Vi1{;Gb848aa4*4J~DuUGm@Fo^iSSi5AtF|fTzl}g? z;y|TWah|0*`3OM^bwoy^LEaJO8PUt*r{B0kA+6aprpho`f_=eM*yC6OIV19ad8$&HWp=wKx?8h`9qs3n2veCSFK=%4209*K}__eF%k< z(%Fa$;gfhYn&LXPN&HsKr+`wFtmRB_eK~=Z#3a;|OUy-=sG;WugnA|}alzPR2&h7L z#ykCDsjv1SV7w$CIABEEGE0kp7!X{hnFch|Nz!7JtBX}Srfn?eD$eUrZFVXaTusws z$UY6o1_tC!EaCzprH6DH^cW+!gLE|T@RT`bmw^~eI6Ac@{%DcX;#7Qjc=S6_sBwl- z!{`sMZ(sx~F7dI7wCgif}mYg&>A2t-Jv4ETMhZtMMuGj_EiPqYeu9d#UaxDx{n z!d6@&U3VSd5e?);YD6TAq8XezWE=Y{3}PC^UhV$ylNH_n~Ed4qcMbZ+QCgcCN^ z&Qq2)&O<|<4s#0|A!uqtd#^Y&jn|$1A6o!uOfsb4#Ma`^tc9NmHyFmBX$*N^GHteW zQkF-hlYehFsdk(89Jy8_LEJjJ^Q&|pVy~fq^8S0$@1rY!IofABJSP~W$nB!L zg`2^HQ7;W9L$k;RWQsu0r(CG#Y5bQ;y8~+q)+`EPTjJoriIdV34z>z~MGsYxt>q{r zQylaUJb*0CC$5$!(!I5I-Wc(R~0+BRGmcxt8Iyl=MgCV|oO}pZ>6VmN>9A4O5=mbBxInZ-jMKm7a2Qsw48m}sTuD@ftW`9>A%*Z!MMjBqvY9?l}+3~8GwQQAhLIsHh-h^MP#kv_)z}q$#m+# zIB=zJdsfRnK?|tlTz3 zR(JH^@2BT~!^?}lQGI~A!FFT-$Zg_#lV<`^T#a7FdMU((mRUi=lZh-%R*Y=}dXc1B zq>lb{nJp1KcA|At{t%D@Cv{9$=reBuA>6ZDz>ob3T>HDb_hWcIt0OS!E@N=j_S#!M3&NO!f@k`0}0E2YW8i)(y5&W8{BRar;3T?B_-pd zU%~Sps+l(V2m6Td5A=p;=p(LNjgq*S)1PJ~H+a@a!fXP4(^w^mOckX5qj(bsM_8X* zLjDIII81Gzg)yQ1JP1OKyhYAai24O3SC*R?&x=H+M$dTmMlP0#Iu?&){#um?Mj$Sw zyd1!PDDz3QlsQZ~%h@4=au?PWmiwhWf3Ljwdt}7hv;KYDmuPQKvkyU904gaWFYfw2 zcW&<{u}yvKM2vZ=!E#fkTeMGiN^?ucst)Rj$1GrX@WSkzbgAo;*p4CdI`G>j42uvh z(XN2#mhF(1zgEc74;hqKTgSD?q`SoCO|x--Rji4vLoJ@gqs4nu--HhcN!sBOh2rnF zf)f4s-mLe8{MnA%$*`XLC-BI)?~lH3XwE0^wG#vnHy)t&W8;Kv2Iy_68{q6`Ci1f7 zmUfG{eC*34gZCDK`DUVP(s8l{eilEjneI=$Pwg5Ob`j|-8bTxSW251pdY|HWqHG%J-*n*zswDU_ zIE-rYQ}5Fm{SxsnY+jATj{wR#QmLB8*yL-qiu9kh&<}H29%zJXZ0~w5%OcW$KiHBN zxk5X95tjFS--a!2c1u-##1Pe<;ua&P!Pe0}ZN)GroN_=tZ;Yl3+=dx978tB_n>d*^!g73ep5ho||gkS4-3Lc@YKD0Xel$!H?SRb`xL z0d5&nzR)tT{l?g?Yer7ZXc?;rYqs`%nj}JA$v8nmVQ+!ok4%!tl&W8U38FEE#v2M_ zezBeNGx<~RQ}pO|2>{$p{DQzJ&Zh}w=qUW^5^_)^gCZb_VVMS^%&Vfj&hm1; z63axE(=1hhL%6MFV0HG)#ypaJ7T^awEpa0`3&dW+B=-3LM$>)yVqC`p5<&^V0 zt7h}8BAt%wp-GAtO4*TO5|y~jI4ig|?C`}z%{QqLYHpq~5vfv>;?R3Ajn4rnzho+B z3Xgi3=?5B&8DmK&&|3gGxdIJ3@|V)lVVGx{)`h2q9_j$V^ID023sC=xyXRQcWJM6) z$Wb1T{m1uH;XY>Y+b!@=<)yG8wiH>*&bNyyDPy=soOXtu_rk$RE`Is>KQNaA*C4LJCcyXxVK^mm8iJe|R7%S=+4H5OSsRWgY%Q{j19sw9bL=)K%~ z`s^GNoRN{`J~VLlW|?F;q+&X~|35%x`07x615Uv*iD&36Y8;CVPxNG|QaV!@P>-8) zNdgHQvwGh=x%d3C|5I;XmdoOJI82nx)5C=x=;1h94AF~!8a;e6o{oZO0cqgbqb0Z*|QCg}QqRoz~B2ED> zz}T4hPUgjb0cSZPbKoBi#a%gmeJ%3|z_TuvvW!P@0>RthXH=Ci7bsh(Qm}JHA>?EN zEfXQtugl?!^!6dRgIuY+6bk(*^c@GHAoIUeiq>-~3v`W!PZYggzq>UalY{`5VHeXW+m+~N(>NliJ(^z?dc)0z&%JV&ko!$~7L!xBJqe}B0w@@0W*1)c*+rNCj_FN~hZG2(4V!8nP3 zE->xHU}^KSTT4CF*{sIP?0@<7Q?x(H{vdN-)S0_M61c8t*baKXHD~Je6aVWo7Aw@Z zd2xP*B4Ylh<5i}YCH84ONpg~zuqSEV`9`$CMWr#(O@Kolw5#eWN6`CDd>?|#A$Q8J z?xj1chPGKvprccsO_|J)?os9Lj&QtxqbXIm15I)tW%fwF`#xA>VlMJ!c`#B>0^5d1 zCV~A7YOCd?Bqb^E<9zBy@Fob*H8<&!PLvh#T(x!lE0PU@bfdjxw{K3pus)e2BJ7g^ z=`C;MU>-o5>|WY-Wzw{F;c{qGfgjfpKp9_R2KJ+sBXyiFI2~_}Vw@#HbjabY3ph$) z4CP)Gl|pKMehS_2>P9|4Va#FwN3H$!S|1)WuIJZ$&!EHyg9Xthq6e&hi~AbyNddbQ z+50dr%ollGczp1mBoBEE;b~4kjis^L$LQZYD-W(YW*r z)&5c!(9h|WgYfum=Qcclr43tWLx6b)=1ph97weOnm_?qIh)yx3wbaX%#E<|i*Wut# zp)dNoa-Nt%7vuTrNZr0IkyMCv0!`|#|LcD%37t|BJ4N5YxkUeX!Nk$O?|b@g-ySJk z`D7QY=7ljF2*Wm=i9tbFnR@R<*0T~%xgZUK(gMY&VhuZG4*@%Wm?`eWs}F4pHF46@ z(^JY*W#?2z5jD@J4wvLZa%LS9S_{b`h)ryUvux|MV%#nG$>MRsj0BpvMq=W3dsyf_ zqzKsQY_*V0K#hWVZZ`}z$=>%36jVBvy{<8r5yrU&Nj8&Rur7uU@8ighNbAd$yK|0qB69e9(GTjo}OZt-@YyP_Cha_XimZ*%QB4<4f*A?i{?`ZWvySHOisC*1{08O z+AnFliGOk3UP;2JZScSM6>{HK$bDZS_kD%j{tCHW#c;1y1Gl>bZeN+(4W(?u4_^9u)okAvv$gZG zxgLR^?H$X1)BcjG(_XFa>`fG$J^b+QHnnDd<`T1OD$K4cA-kbO?7OcFyQVPg+PbeH z^QdxLQ|%oUfxSle>+8TaOS$%yc6~<`UBe5CDz$D|$JJ>h{j%|<=%p>R_K!ZLI)vCv zig2|*vbC}}uhYdli7J013j7+7h}f9ehimqtVE^xLG?13>X58ZIg@1PeQZT zrO$5{^V*Z(9?%`>neiJz*X+VuiIvd)CBIG>*;dAz8(G+!nok=`{E1W4uQgd)$GB}d zLjhda&6%-?1;C1JGYweubkJ5I$ie8Fhc8}Rr~~`m1s*P$Yc#Z;rit7Np$-Ek9{ga? zq~>;i2d0K+(HJpAXjb=ldRiOdo`1&HMY8*94R?1*svaxYB8y*xNbWpr@~UF(`6-x|+5!|3Lix zLB!k|Z^Y;FCx!4Wg!Lpwj@QPc+8GkMoz)qC_m|J_l-sMyRci0F5$Y9n-F=(yI7#S- zwQS|KB{Pqb11`&7&P9m-#cbu9XD^C;X$lmjj5UOirv!}}3`8&WIH^{FeX41Zi2CVl z?`QFg)mf2DP~;F%kHJVlVmto&>HRMrQ0JURAN76ziw7ZT4Bht4GmgL`UBk+I4oZ=K zN)LP^0jke5>SP!at{UH|r^(o4r78CgHkDBL8F=>bc}=6Wb-Lhb*P`|8lf|ZIU5mE4 z3XeG{zw24a_Gv%;v)nXIdS%^?D_zxPtOPdJ@E_e85-Jt9*}uU((_J>gS4H@ikzMyF z1~uI6_tf50rzH{gRbHvb8TjAC(%8L!a_x>O4+{}ve|Y|MuVaj=s11GJO(-{<$>^%Lx$u=wC zl=o;AJbGN?G%^F*3v2|@>HO_I^=||9Z@oW$_?rR#*ZK3kd+P3;fx7!~_s_q7qhI4M zrKKaP|23)nNH?=-Oa#`8xGpQ$z5Uf?VEMS$J*UG4y?n*3bvVEb%XG$m*2+r zgpL+XV{Pjt+cdrQy3mW9%1@D0+J9;zc;bPw+}RaU3~^n$JYU;^88>pQTSXe14+MAg zpnZ#M_4F}94EMSR_HWtThHGbk^gb6T=QZ!JC(5-&q=Tt$y+YxAdZ|D3WZPEOpv(hpm5qQm8amaPGgG z))u#(b{20Qusj;@nPvsqW*y^b#I+@^r;Sp{GFE%U{!-1+VEuu5*Borki>Ny}qkx@2DfGkTlaFrKSV}@ZGC;~P?PDG_@f<=B;nAhEZommX!K6~I6_|{EU z)roZNKLJT$XHgR(DaQQW9_hM8NH>IaNJyts#u3uQt=bCQx_eF(i|+F6GpfW zdvUndjxO1ONT$$9rY`5=;7dw|esmM~Sz*jeqf6onfnX4bJpV|A>mc*R(g}YbDBleT zN0KIZPgNwI%G>RKz0S@vB$#z>IhJa%CH-%KPRVq|tao%rOek&U8vfpQrOD52mM%YR zwBdJEKMj*Jf-0HF@Pdpg|JdrG7llFMmJ}l8e+Jb-336Ggv-Z!^@9Y|O&Jz9FdXWYK zr){*>%b~$*DS2qpu#nQm4n1C_8$@UmuLrV_l@E=Dl*k6=P6U_swCDD)r=ifTF3&IpfFIU7NFyl^8!y>akr;P zY><~8sc&&5BV~;$Vkea;fDIuO3H}#>3gC@xvKwW81liON%8(#~?CJ2V(Ajv-X^iR= zSHNgAIym)7ga-pZ`u?4RQ(9a|0rrjEmxxHd$didWJ%0S`&Ychc9qX7>^MyfjB-UiO zNJ=W^txQqmR44r;d%$at4T|FJypO1o8tp?4(V+Y@+!8L?QlOvKph!_dNok_KFpNXl z@QLDoPm#ttu)V}!N4zRn5|^q;*A!=0b6zY`fwMf#XQ=HLIRKrHjWb%Od79>z959YU zjSa;qEB^2zgq=&7(L#0l3{TmkINF?p7kz%>{6&%$-$8QT#_YV_RK0hQwkLUe_j&3l zk@G)Mma%_sSa#-rhmWZr@tkBqT15fo9h+c(1>FAa<|YtXHndhaaQ5HWIvo5&&j&cV z5+RcpobJ4tj3zZnHghuCmUAPLqW~U*T{g>L3O>g!)U4UeF*Vds7U#O-Z=}Y14L49j z4fAP}5({wr`2GNpG6$pUQRC{4_P36xaqVI5r&SWVt~oO?HLh~W8ft7wS^V3=XPG@k}fUv%QMj-A$Ax;&> zR9KTYOQN<8>=k+O7s+fcV0cnG1c-gyg%E}U<~1U&1ch`1R}QJ!#$MdFQXIZ3MD2E_ z5YWFBJleLq`1s4$*VlZH&uhBAZ|qDRfBBlP^U-yv2|Vb#alf)Y8(L!|iqHi~;agji zVxRxD_RWrDbW^k8jCY@Z@PLvXnK4m=NTTgptH~uGmy z-)y&S8gs+IkpN(pCGz`u7x~6fb2W*gMGb`n8O-POR!rY&K6^1>oYgfu5m}%GC z#ZK(Di?{Tb_3YxNOX$g?o1~`qXl+T&wa->e&EvO>NKfb}8~2TEtq3vyCY)6L)DRZZ zTI)5nkbBC6lV7EnzFj@O31&gdsb_mWgo^rUxdD>ud`eMHKM>Eq-Z<&hKzHfvrtu( zoh6)*8Y;xIzIANdB5L?4yJLbfM%VRvynVx|FB=8G#@xt578&_Q=Vqhc+wU!dHIkJ} zm-a%H%{g~wd#A6ZMuHHyED6HuIxmODnX-`!e3&RDz+Do5yWCS;t8=Z~*A+*>58VJ0 z?xyD2`qWrDxB-jF+c(xrcBNhH9p7>6>9uLOH-hf)^*uTlbWu) z)>=*WKVX&q7XBBo-0CoMCkhTV}5(tLc*pwHXbZ_rwm zXnqqe))qCJ;#Pa2R&R)wCN&`{$!2Q8);B{?Obz6Tbs>=(Vz-OwHGI$keR^igwDGKH^OW771B8jOAD#x)q* z@wGL7m_j9ajG0p{qAyLd|9@D_rhDqTZut&s z*wAnV8-+aKDcRLZ;i-92vgG$TO=eU(xRaWHGhkt;SQ53QB&8Jtjr4I%NwkG4x6Mk? z6F#hD*C2{EHCMW)n3}-Ly5p{CQFEnxim4&#=7#8LP_sc4?V_e^$fG+)ybv|df%|c# zm7*u!(MmlB^6u5BA*|kaNX@n78=P=L626JZ1w<$5q7oqBEvdm1f(v{@)8nb(fJk+J zB}tT?xUqE#sgaA5iZ8FOBvDNHksIZH1pBtBH7drtf727G$!1bP)b5{s##g>d+Gv{^ zxJj?(5o(69wZgz(6lRgsi>pO~+rnTE$-%zn8gHx=3&ZS|FQIJ$yX}hR^L}b}h+3tR z&^rgNM%1{%YTHrcn%@{j5jEG0p}m=Zd1+B&5yG~l#x}pX#S&^fg7sA*7bta$lFD`s zx{j&ouTH#1XV_e}_?nVvH>Uc=%oBbnDrmTqs^__%N8;U<7kjXMlvplr;A-&HY_oMX z?wcEvL_HStw$#uQ?}(Z$0vCGj@SCG&WA*KISRH+3xp%e-G{NAv@(A%0D6D{gM{ZQU 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%0Dk!p=(_dR9*24BdcIZjD4D0UrY< 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 M1uq7@Nd*7^0O0a=hX4Qo diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index 83b7e3ad7..736b363c4 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -831,7 +831,7 @@ exit 0 It 'limits legacy config env-var references to the allowlist' { if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } - $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" + $result = Invoke-BashCommand "git grep -nE 'FINOPS_HUB_CLUSTER_URI|FINOPS_HUB_CLUSTER_RESOURCE_ID' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" $result.ExitCode | Should -Be 0 $paths = $result.Output -split "`n" | @@ -847,6 +847,59 @@ exit 0 ) } + It 'requires recipe package hash validation before extraction' { + $applyExtrasScriptPath = Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1' + $applyExtrasLines = Get-Content -Path $applyExtrasScriptPath + $applyExtrasScript = $applyExtrasLines -join "`n" + + $applyExtrasScript | Should -Match "\$recipePackageSha256 = Get-RequiredEnv 'recipePackageSha256'" + $applyExtrasScript | Should -Match 'Get-FileHash\s+-Algorithm\s+SHA256' + $applyExtrasScript | Should -Match '(?s)recipePackageSha256.*throw' + + $hashLine = for ($i = 0; $i -lt $applyExtrasLines.Count; $i++) { + if ($applyExtrasLines[$i] -match 'Get-FileHash' -and $applyExtrasLines[$i] -match 'SHA256') { + $i + 1 + break + } + } + $throwLine = for ($i = 0; $i -lt $applyExtrasLines.Count; $i++) { + if ($applyExtrasLines[$i] -match 'throw' -and $applyExtrasLines[$i] -match 'hash|SHA256|recipePackageSha256') { + $i + 1 + break + } + } + $expandArchiveLine = for ($i = 0; $i -lt $applyExtrasLines.Count; $i++) { + if ($applyExtrasLines[$i] -match 'Expand-Archive') { + $i + 1 + break + } + } + + $hashLine | Should -BeGreaterThan 0 + $throwLine | Should -BeGreaterThan 0 + $expandArchiveLine | Should -BeGreaterThan 0 + $hashLine | Should -BeLessThan $expandArchiveLine + $throwLine | Should -BeLessThan $expandArchiveLine + } + + It 'declares recipePackageSha256 in the compiled deploy templates' { + foreach ($compiledPath in @( + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/latest/azuredeploy.json'), + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/14.0/azuredeploy.json') + )) { + $compiledTemplate = Get-Content -Path $compiledPath -Raw | ConvertFrom-Json -Depth 100 + $compiledTemplate.parameters.PSObject.Properties.Name | Should -Contain 'recipePackageSha256' + } + } + + It 'requires an https allowlisted recipe package origin before download' { + $applyExtrasScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1') -Raw + + $applyExtrasScript | Should -Match '(?is)\[uri\]\$[A-Za-z0-9_]+\s*=\s*\$recipePackageUri' + $applyExtrasScript | Should -Match "(?is)\.Scheme\s*-ne\s*'https'.*throw" + $applyExtrasScript | Should -Match '(?is)\.Host.*(-notcontains|-notin|-notmatch|-notlike).*(throw|fail)' + } + It 'keeps connectors.secrets.env out of scripts' { if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } $result = Invoke-BashCommand "git grep -nE 'connectors\.secrets\.env' -- src/templates/sre-agent/bin src/templates/sre-agent/infra" @@ -858,6 +911,39 @@ exit 0 Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/hydrate-extensions.sh') | Should -BeFalse } + It 'removes dead telemetry scripts and source references from the SRE Agent template' { + Test-Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/telemetry.sh') | Should -BeFalse + + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + $result = Invoke-BashCommand "git grep -nE 'f10eff7f-b995-4c41-8347-90f0f55d5969|send_telemetry' -- src/templates/sre-agent" + $result.ExitCode | Should -Be 1 -Because $result.Output + } + + It 'removes legacy telemetry flags and env vars from deploy surfaces' { + if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } + + $deployContent = Get-Content -Path $script:DeployScript -Raw + $deployContent | Should -Not -Match '--no-telemetry' + + $result = Invoke-BashCommand "git grep -nE '\-\-no-telemetry|SRE_AGENT_NO_TELEMETRY' -- docs-mslearn/toolkit/sre-agent/deploy.md src/templates/sre-agent" + $result.ExitCode | Should -Be 1 -Because $result.Output + } + + It 'parameterizes the deployer principal type in the SRE Agent module' { + $sreAgentBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/modules/sre-agent.bicep') -Raw + + $sreAgentBicep | Should -Match "(?s)@allowed\(\s*\[\s*'User'\s*,\s*'ServicePrincipal'\s*\]\s*\)\s*param\s+deployerPrincipalType\s+string" + $sreAgentBicep | Should -Match 'principalType:\s*deployerPrincipalType' + $sreAgentBicep | Should -Not -Match "principalType:\s*'User'" + } + + It 'passes ServicePrincipal deployer principal type in the CI/CD example' { + $githubActionsDeploy = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml') -Raw + + $githubActionsDeploy | Should -Match 'ServicePrincipal' + $githubActionsDeploy | Should -Match 'deployerPrincipalType|--deployer-principal-type' + } + It 'uses deterministic subscription and resource group identity for support resource names' { $mainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw $resourcesBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/resources.bicep') -Raw @@ -873,6 +959,61 @@ exit 0 $resourcesBicep | Should -Not -Match 'resourceGroup\(\)\.id|deployment\(\)\.name' } + It 'defaults to read-only identity with autonomous reporting' { + $portalMainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/main.bicep') -Raw + $cliMainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw + $createUiDef = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/createUiDefinition.json') -Raw | ConvertFrom-Json -Depth 100 + $deployScript = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/bin/deploy.sh') -Raw + $recipeAgentJson = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub/agent.json') -Raw | ConvertFrom-Json -Depth 100 + $expectedConfigJson = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/recipes/finops-hub/expected-config.json') -Raw | ConvertFrom-Json -Depth 100 + + $portalMainBicep | Should -Match "param accessLevel string = 'Low'" + $portalMainBicep | Should -Match 'param enableSubscriptionReaderRole bool = false' + $portalMainBicep | Should -Match "param actionMode string = 'autonomous'" + + $cliMainBicep | Should -Match "param accessLevel string = 'Low'" + $cliMainBicep | Should -Match 'param enableSubscriptionReaderRole bool = false' + $cliMainBicep | Should -Match "param actionMode string = 'autonomous'" + + $accessLevelControl = $createUiDef.parameters.steps | + Where-Object { $_.name -eq 'configuration' } | + Select-Object -First 1 -ExpandProperty elements | + Where-Object { $_.name -eq 'accessLevel' } + $accessLevelControl.defaultValue | Should -Be 'Low' + + $subscriptionReaderControl = $createUiDef.parameters.steps | + Where-Object { $_.name -eq 'configuration' } | + Select-Object -First 1 -ExpandProperty elements | + Where-Object { $_.name -eq 'enableSubscriptionReaderRole' } + $subscriptionReaderControl.defaultValue | Should -Be $false + + $actionModeControl = $createUiDef.parameters.steps | + Where-Object { $_.name -eq 'configuration' } | + Select-Object -First 1 -ExpandProperty elements | + Where-Object { $_.name -eq 'actionMode' } + $actionModeControl.defaultValue | Should -Be 'autonomous' + + $deployScript | Should -Match 'ENABLE_SUBSCRIPTION_READER="false"' + + $recipeAgentJson.access.accessLevel | Should -Be 'Low' + $recipeAgentJson.access.actionMode | Should -Be 'autonomous' + + $expectedConfigJson.agent.accessLevel | Should -Be 'Low' + $expectedConfigJson.agent.actionMode | Should -Be 'autonomous' + $expectedConfigJson.subscriptionRoleAssignments | Should -Be @() + } + + It 'declares Low accessLevel and disabled subscription Reader in the compiled deploy templates' { + foreach ($compiledPath in @( + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/latest/azuredeploy.json'), + (Join-Path $script:RepoRoot 'docs/deploy/sre-agent/14.0/azuredeploy.json') + )) { + $compiledTemplate = Get-Content -Path $compiledPath -Raw | ConvertFrom-Json -Depth 100 + $compiledTemplate.parameters.accessLevel.defaultValue | Should -Be 'Low' + $compiledTemplate.parameters.enableSubscriptionReaderRole.defaultValue | Should -Be $false + } + } + It 'applies subagents after their local handoff targets' { if ($script:SkipBash) { Set-ItResult -Skipped -Because 'bash is unavailable' } diff --git a/src/scripts/Package-Toolkit.ps1 b/src/scripts/Package-Toolkit.ps1 index 5b6301a92..8943edecd 100644 --- a/src/scripts/Package-Toolkit.ps1 +++ b/src/scripts/Package-Toolkit.ps1 @@ -209,6 +209,23 @@ function Copy-TemplateFiles() } Copy-FlatDeploymentFiles + + # Inject the recipe package SHA-256 into azuredeploy.json so the deployment + # script can verify package integrity before extraction. Runs only when a + # template ships both the compiled template and a recipe zip; no-op otherwise. + $deployJson = "$targetDir/azuredeploy.json" + $recipeZip = "$targetDir/sre-agent-recipe.zip" + if ((Test-Path $deployJson) -and (Test-Path $recipeZip)) + { + $deployContent = Get-Content $deployJson -Raw + if ($deployContent -match 'PLACEHOLDER_RECIPE_PACKAGE_SHA256') + { + $recipeSha = (Get-FileHash -Algorithm SHA256 -Path $recipeZip).Hash.ToLower() + $deployContent = $deployContent -replace 'PLACEHOLDER_RECIPE_PACKAGE_SHA256', $recipeSha + Set-Content -Path $deployJson -Value $deployContent -NoNewline + Write-Verbose " Injected recipe package SHA-256 ($recipeSha) into $deployJson" + } + } } else { diff --git a/src/templates/sre-agent/README.md b/src/templates/sre-agent/README.md index 82b0dffb8..00bc6a6e5 100644 --- a/src/templates/sre-agent/README.md +++ b/src/templates/sre-agent/README.md @@ -110,8 +110,7 @@ bash bin/deploy.sh \ [--cluster-resource-id /subscriptions/.../providers/Microsoft.Kusto/clusters/] \ [--target-resource-group ...] \ [--dry-run] \ - [--force] \ - [--no-telemetry] + [--force] ``` `bin/deploy.sh --help` is the CLI contract: @@ -132,10 +131,10 @@ Optional: Example: https://..kusto.windows.net/Hub --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deployer-principal-type Principal type of the deployer (User or ServicePrincipal). Default: User. --deploy-name Deployment name override. Defaults to a deterministic name. --dry-run Validate inputs and write parameters without Azure calls. --force Accepted for compatibility. - --no-telemetry Accepted for compatibility. -h, --help Show this help. ``` @@ -209,14 +208,13 @@ The GitHub Actions example passes the cluster URI as a script flag while keeping ## Migrating from env-var-driven deploys -The old deploy path accepted config through environment variables such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, `SRE_AGENT_NO_TELEMETRY`, and `connectors.secrets.env`. Those inputs are no longer supported for config or identity. +The old deploy path accepted config through environment variables such as `FINOPS_HUB_CLUSTER_URI`, `FINOPS_HUB_CLUSTER_RESOURCE_ID`, and `connectors.secrets.env`. Those inputs are no longer supported for config or identity. Before: ```bash export FINOPS_HUB_CLUSTER_URI="https://..kusto.windows.net/hub" export FINOPS_HUB_CLUSTER_RESOURCE_ID="/subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/" -export SRE_AGENT_NO_TELEMETRY=1 bash bin/deploy.sh recipes/finops-hub ``` @@ -230,8 +228,7 @@ bash bin/deploy.sh \ --name \ --location \ --cluster-uri https://..kusto.windows.net/Hub \ - --cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/ \ - --no-telemetry + --cluster-resource-id /subscriptions//resourceGroups//providers/Microsoft.Kusto/clusters/ ``` The only supported environment-variable inputs are secrets: diff --git a/src/templates/sre-agent/bin/deploy.sh b/src/templates/sre-agent/bin/deploy.sh index 3b9a5f53c..e40373733 100755 --- a/src/templates/sre-agent/bin/deploy.sh +++ b/src/templates/sre-agent/bin/deploy.sh @@ -38,10 +38,10 @@ Optional: Example: https://..kusto.windows.net/Hub --cluster-resource-id Optional Kusto cluster ARM resource ID. Real deployments resolve this from --cluster-uri when possible; dry-run requires it. --no-subscription-reader Do not assign Reader at subscription scope. Default: assign Reader. + --deployer-principal-type Principal type of the deployer (User or ServicePrincipal). Default: User. --deploy-name Deployment name override. Defaults to a deterministic name. --dry-run Validate inputs and write parameters without Azure calls. --force Accepted for compatibility. - --no-telemetry Accepted for compatibility. -h, --help Show this help. EOF exit "${1:-0}" @@ -247,7 +247,8 @@ CLUSTER_URI="" CLUSTER_RESOURCE_ID="" DEPLOY_NAME="" DRY_RUN="" -ENABLE_SUBSCRIPTION_READER="true" +ENABLE_SUBSCRIPTION_READER="false" +DEPLOYER_PRINCIPAL_TYPE="User" TARGET_RGS=() while [[ $# -gt 0 ]]; do @@ -300,6 +301,11 @@ while [[ $# -gt 0 ]]; do ENABLE_SUBSCRIPTION_READER="false" shift ;; + --deployer-principal-type) + require_value "--deployer-principal-type" "${2:-}" + DEPLOYER_PRINCIPAL_TYPE="$2" + shift 2 + ;; --deploy-name) require_value "--deploy-name" "${2:-}" DEPLOY_NAME="$2" @@ -309,7 +315,7 @@ while [[ $# -gt 0 ]]; do DRY_RUN="true" shift ;; - --force|--no-telemetry) + --force) shift ;; -h|--help) @@ -414,6 +420,7 @@ jq -n \ --argjson monthlyAgentUnitLimit "$MONTHLY_AGENT_UNIT_LIMIT" \ --arg kustoClusterId "$CLUSTER_RESOURCE_ID" \ --argjson enableSubscriptionReaderRole "$ENABLE_SUBSCRIPTION_READER" \ + --arg deployerPrincipalType "$DEPLOYER_PRINCIPAL_TYPE" \ --argjson targetResourceGroups "$TARGET_RGS_JSON" \ --argjson experimentalSettings "$EXPERIMENTAL_SETTINGS" \ --argjson tags "$TAGS" \ @@ -434,7 +441,8 @@ jq -n \ "experimentalSettings": { "value": $experimentalSettings }, "tags": { "value": $tags }, "finopsHubKustoClusterResourceId": { "value": $kustoClusterId }, - "enableSubscriptionReaderRole": { "value": $enableSubscriptionReaderRole } + "enableSubscriptionReaderRole": { "value": $enableSubscriptionReaderRole }, + "deployerPrincipalType": { "value": $deployerPrincipalType } } }' > "$PARAMETERS_FILE" diff --git a/src/templates/sre-agent/bin/telemetry.sh b/src/templates/sre-agent/bin/telemetry.sh deleted file mode 100755 index 97aa3a02a..000000000 --- a/src/templates/sre-agent/bin/telemetry.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash -# telemetry.sh — anonymous usage tracking for recipe popularity. -# -# Sends a single custom event to App Insights. Non-blocking, best-effort. -# No PII is collected — only recipe name, action, region, OS, and coarse booleans. -# -# Usage (sourced by other scripts): -# source "$(dirname "$0")/telemetry.sh" -# send_telemetry "deploy" "finops-hub" "westus3" "true" "false" "true" "false" "deploy" - -_TELEMETRY_IKEY="f10eff7f-b995-4c41-8347-90f0f55d5969" -_TELEMETRY_ENDPOINT="https://eastus2-3.in.applicationinsights.azure.com/v2/track" - -send_telemetry() { - [[ "${_NO_TELEMETRY:-}" == "true" ]] && return 0 - - local action="${1:-unknown}" - local recipe="${2:-unknown}" - local region="${3:-unknown}" - local used_recipe_flag="${4:-false}" - local used_legacy_positional="${5:-false}" - local has_cluster_uri="${6:-false}" - local has_cluster_resource_id="${7:-false}" - local mode="${8:-deploy}" - local os_type - os_type="$(uname -s 2>/dev/null || echo unknown)" - - # Fire and forget — never block or fail the main script - (curl -s -o /dev/null -m 5 -X POST "$_TELEMETRY_ENDPOINT" \ - -H "Content-Type: application/json" \ - -d "[{ - \"name\": \"Microsoft.ApplicationInsights.Event\", - \"time\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\", - \"iKey\": \"${_TELEMETRY_IKEY}\", - \"data\": { - \"baseType\": \"EventData\", - \"baseData\": { - \"name\": \"recipe-usage\", - \"properties\": { - \"action\": \"${action}\", - \"recipe\": \"${recipe}\", - \"region\": \"${region}\", - \"os\": \"${os_type}\", - \"used_recipe_flag\": \"${used_recipe_flag}\", - \"used_legacy_positional\": \"${used_legacy_positional}\", - \"has_cluster_uri\": \"${has_cluster_uri}\", - \"has_cluster_resource_id\": \"${has_cluster_resource_id}\", - \"mode\": \"${mode}\" - } - } - } - }]" 2>/dev/null &) 2>/dev/null -} diff --git a/src/templates/sre-agent/createUiDefinition.json b/src/templates/sre-agent/createUiDefinition.json index 87e82bcaa..25d538b3e 100644 --- a/src/templates/sre-agent/createUiDefinition.json +++ b/src/templates/sre-agent/createUiDefinition.json @@ -101,8 +101,8 @@ "name": "accessLevel", "type": "Microsoft.Common.OptionsGroup", "label": "Access level", - "defaultValue": "High", - "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "defaultValue": "Low", + "toolTip": "Low grants read-only monitoring roles (recommended for reporting and analysis). High adds Contributor on target resource groups for autonomous remediation workflows.", "constraints": { "allowedValues": [ { @@ -147,8 +147,8 @@ "name": "enableSubscriptionReaderRole", "type": "Microsoft.Common.CheckBox", "label": "Grant subscription Reader to the agent", - "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", - "defaultValue": true, + "toolTip": "Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.", + "defaultValue": false, "visible": true } ] diff --git a/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml index afa74e4e7..a13358445 100644 --- a/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml +++ b/src/templates/sre-agent/examples/ci-cd/github-actions-deploy.yml @@ -29,4 +29,5 @@ jobs: --location ${{ vars.SRE_AGENT_LOCATION }} --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} --cluster-uri "$CLUSTER_URI" + --deployer-principal-type ServicePrincipal --force diff --git a/src/templates/sre-agent/infra/main.bicep b/src/templates/sre-agent/infra/main.bicep index ff49374b9..67198548c 100644 --- a/src/templates/sre-agent/infra/main.bicep +++ b/src/templates/sre-agent/infra/main.bicep @@ -25,7 +25,7 @@ param accessLevel string = 'Low' @description('Agent action mode.') @allowed(['review', 'autonomous', 'readOnly']) -param actionMode string = 'review' +param actionMode string = 'autonomous' @description('Agent upgrade channel.') @allowed(['Stable', 'Preview']) @@ -54,10 +54,14 @@ param tags object = {} @description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') param finopsHubKustoClusterResourceId string = '' -@description('Assign Reader on the deployment subscription to the agent managed identity.') -param enableSubscriptionReaderRole bool = true +@description('Assign Reader on the deployment subscription to the agent managed identity. Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.') +param enableSubscriptionReaderRole bool = false -var targetRgs = empty(targetResourceGroups) ? [resourceGroupName] : targetResourceGroups +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + +var targetRgs = union([resourceGroupName], targetResourceGroups) var agentResourceGroupId = subscriptionResourceId('Microsoft.Resources/resourceGroups', resourceGroupName) var targetRgIds = [for rgName in targetRgs: subscriptionResourceId('Microsoft.Resources/resourceGroups', rgName)] var namingSeed = toLower('${subscription().subscriptionId}|${agentResourceGroupId}|${agentName}') @@ -84,6 +88,7 @@ module resources 'resources.bicep' = { defaultModelName: defaultModelName monthlyAgentUnitLimit: monthlyAgentUnitLimit experimentalSettings: experimentalSettings + deployerPrincipalType: deployerPrincipalType tags: tags } } diff --git a/src/templates/sre-agent/infra/modules/apply-extras.bicep b/src/templates/sre-agent/infra/modules/apply-extras.bicep index 4adbe17a8..4cc76f86f 100644 --- a/src/templates/sre-agent/infra/modules/apply-extras.bicep +++ b/src/templates/sre-agent/infra/modules/apply-extras.bicep @@ -15,6 +15,9 @@ param subscriptionId string @description('Public URI for the generated SRE Agent recipe package.') param recipePackageUri string +@description('SHA256 hash of the recipe package for integrity verification.') +param recipePackageSha256 string + @description('Optional database-qualified Kusto connector URI.') param kustoConnectorUri string = '' @@ -88,6 +91,10 @@ resource applyExtras 'Microsoft.Resources/deploymentScripts@2023-08-01' = { name: 'recipePackageUri' value: recipePackageUri } + { + name: 'recipePackageSha256' + value: recipePackageSha256 + } { name: 'kustoConnectorUri' value: kustoConnectorUri diff --git a/src/templates/sre-agent/infra/modules/sre-agent.bicep b/src/templates/sre-agent/infra/modules/sre-agent.bicep index 4eb264822..ded39f596 100644 --- a/src/templates/sre-agent/infra/modules/sre-agent.bicep +++ b/src/templates/sre-agent/infra/modules/sre-agent.bicep @@ -44,6 +44,10 @@ param experimentalSettings object @description('Azure resource tags.') param tags object = {} +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + var sreAgentAdminRoleId = 'e79298df-d852-4c6d-84f9-5d13249d1e55' #disable-next-line BCP081 @@ -91,7 +95,7 @@ resource sreAgentAdminRoleAssignment 'Microsoft.Authorization/roleAssignments@20 properties: { roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', sreAgentAdminRoleId) principalId: deployer().objectId - principalType: 'User' + principalType: deployerPrincipalType } } diff --git a/src/templates/sre-agent/infra/resources.bicep b/src/templates/sre-agent/infra/resources.bicep index 1fd023349..3107d9dee 100644 --- a/src/templates/sre-agent/infra/resources.bicep +++ b/src/templates/sre-agent/infra/resources.bicep @@ -34,6 +34,10 @@ param monthlyAgentUnitLimit int @description('Agent experimental settings.') param experimentalSettings object +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + @description('Azure resource tags.') param tags object = {} @@ -66,6 +70,7 @@ module sreAgent 'modules/sre-agent.bicep' = { defaultModelName: defaultModelName monthlyAgentUnitLimit: monthlyAgentUnitLimit experimentalSettings: experimentalSettings + deployerPrincipalType: deployerPrincipalType tags: tags } } diff --git a/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 index 7a8db80ef..85f6e9daf 100644 --- a/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 +++ b/src/templates/sre-agent/infra/scripts/Apply-SreAgentExtras.ps1 @@ -120,6 +120,7 @@ $resourceGroupName = Get-RequiredEnv 'resourceGroupName' $agentName = Get-RequiredEnv 'agentName' $agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/') $recipePackageUri = Get-RequiredEnv 'recipePackageUri' +$recipePackageSha256 = Get-RequiredEnv 'recipePackageSha256' $kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri' $armApiVersion = '2025-05-01-preview' $armBase = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName" @@ -134,10 +135,33 @@ $zipPath = Join-Path $tempRoot 'sre-agent-recipe.zip' Remove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue New-Item -Path $workRoot -ItemType Directory -Force | Out-Null +Write-Output "Validating SRE Agent recipe package URI: $recipePackageUri" +[uri]$parsedUri = $recipePackageUri +if ($parsedUri.Scheme -ne 'https') { + throw "Recipe package URI must use https scheme, got: $($parsedUri.Scheme)" +} + +$allowedHosts = @( + 'raw.githubusercontent.com', + 'github.com', + 'aka.ms' +) + +if ($allowedHosts -notcontains $parsedUri.Host -and $parsedUri.Host -notlike '*.blob.core.windows.net') { + throw "Recipe package host '$($parsedUri.Host)' is not in the allowlist. Allowed: raw.githubusercontent.com, github.com, aka.ms, *.blob.core.windows.net" +} + Write-Output "Downloading SRE Agent recipe package: $recipePackageUri" Invoke-WithRetry -Label 'download recipe package' -Action { Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath } | Out-Null + +Write-Output "Verifying recipe package integrity..." +$actualHash = (Get-FileHash -Algorithm SHA256 -Path $zipPath).Hash +if ($actualHash -ne $recipePackageSha256) { + throw "Recipe package hash mismatch: expected $recipePackageSha256 got $actualHash" +} + Expand-Archive -Path $zipPath -DestinationPath $workRoot -Force $extrasPath = Join-Path $workRoot 'extras.json' diff --git a/src/templates/sre-agent/main.bicep b/src/templates/sre-agent/main.bicep index fd4632140..373ccd0e3 100644 --- a/src/templates/sre-agent/main.bicep +++ b/src/templates/sre-agent/main.bicep @@ -25,9 +25,9 @@ param finopsHubKustoConnectorUri string = '' @description('Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment.') param finopsHubKustoClusterResourceId string = '' -@description('Agent access level.') +@description('Agent access level. Low (read-only) is recommended for reporting and analysis without modification risk.') @allowed(['Low', 'High']) -param accessLevel string = 'High' +param accessLevel string = 'Low' @description('Agent action mode.') @allowed(['review', 'autonomous', 'readOnly']) @@ -54,12 +54,15 @@ param experimentalSettings object = { EnableWorkspaceTools: true } -@description('Assign Reader on the deployment subscription to the agent managed identity.') -param enableSubscriptionReaderRole bool = true +@description('Assign Reader on the deployment subscription to the agent managed identity. Optional — required only for subscription-wide ARM-backed reports; otherwise scope reads via target resource groups.') +param enableSubscriptionReaderRole bool = false @description('Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI.') param recipePackageUri string = uri(any(deployment()).properties.templateLink.uri, 'sre-agent-recipe.zip') +@description('SHA256 hash of the recipe package for integrity verification.') +param recipePackageSha256 string = 'PLACEHOLDER_RECIPE_PACKAGE_SHA256' + @description('Forces the recipe deployment script to run when the template is redeployed.') param forceUpdateTag string = utcNow() @@ -69,6 +72,10 @@ param tags object = { source: 'microsoft-finops-toolkit' } +@description('Principal type of the deployer.') +@allowed(['User', 'ServicePrincipal']) +param deployerPrincipalType string = 'User' + var rawTargetResourceGroups = split(replace(targetResourceGroupNames, ' ', ''), ',') var parsedTargetResourceGroups = filter(rawTargetResourceGroups, rgName => !empty(rgName)) var targetRgs = union([resourceGroupName], targetResourceGroups, parsedTargetResourceGroups) @@ -102,6 +109,7 @@ module resources 'infra/resources.bicep' = { defaultModelName: defaultModelName monthlyAgentUnitLimit: monthlyAgentUnitLimit experimentalSettings: experimentalSettings + deployerPrincipalType: deployerPrincipalType tags: tags } } @@ -144,6 +152,7 @@ module applyExtras 'infra/modules/apply-extras.bicep' = { agentEndpoint: resources.outputs.agentEndpoint subscriptionId: subscription().subscriptionId recipePackageUri: recipePackageUri + recipePackageSha256: recipePackageSha256 kustoConnectorUri: finopsHubKustoConnectorUri forceUpdateTag: forceUpdateTag tags: tags From a1133af5e8f9fb6fc1f7015884e545ec4b17775c Mon Sep 17 00:00:00 2001 From: MSBrett <24294904+MSBrett@users.noreply.github.com> Date: Wed, 17 Jun 2026 13:09:56 -0700 Subject: [PATCH 18/19] fix(sre-agent): refresh ms.date, default actionMode to review, drop generated zips Set ms.date to today for changed docs, change portal default actionMode to review for safer defaults, and remove build-generated recipe zips with a gitignore entry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .gitignore | 3 +++ docs-mslearn/toolkit/hubs/configure-sre.md | 2 +- docs-mslearn/toolkit/sre-agent/agents.md | 2 +- docs-mslearn/toolkit/sre-agent/get-started.md | 2 +- docs-mslearn/toolkit/sre-agent/knowledge.md | 2 +- docs-mslearn/toolkit/sre-agent/kusto-tools.md | 2 +- docs-mslearn/toolkit/sre-agent/overview.md | 2 +- docs-mslearn/toolkit/sre-agent/python-tools.md | 2 +- .../toolkit/sre-agent/scheduled-tasks.md | 2 +- docs-mslearn/toolkit/sre-agent/security.md | 2 +- docs-mslearn/toolkit/sre-agent/template.md | 2 +- docs-mslearn/toolkit/sre-agent/tools.md | 2 +- .../toolkit/sre-agent/troubleshooting.md | 2 +- docs/deploy/sre-agent/14.0/azuredeploy.json | 2 +- .../sre-agent/14.0/createUiDefinition.json | 2 +- .../deploy/sre-agent/14.0/sre-agent-recipe.zip | Bin 342755 -> 0 bytes docs/deploy/sre-agent/latest/azuredeploy.json | 2 +- .../sre-agent/latest/createUiDefinition.json | 2 +- .../sre-agent/latest/sre-agent-recipe.zip | Bin 342755 -> 0 bytes .../sre-agent/createUiDefinition.json | 2 +- src/templates/sre-agent/main.bicep | 2 +- 21 files changed, 21 insertions(+), 18 deletions(-) delete mode 100644 docs/deploy/sre-agent/14.0/sre-agent-recipe.zip delete mode 100644 docs/deploy/sre-agent/latest/sre-agent-recipe.zip diff --git a/.gitignore b/.gitignore index 198952770..5417aab06 100644 --- a/.gitignore +++ b/.gitignore @@ -387,3 +387,6 @@ src/templates/finops-hub-copilot-studio/knowledge/query-catalog.md todo/ done/ release/scloud-occurrence-report.md + +# Generated SRE Agent recipe packages +docs/deploy/sre-agent/*/sre-agent-recipe.zip diff --git a/docs-mslearn/toolkit/hubs/configure-sre.md b/docs-mslearn/toolkit/hubs/configure-sre.md index 8a1810137..309dc7bb9 100644 --- a/docs-mslearn/toolkit/hubs/configure-sre.md +++ b/docs-mslearn/toolkit/hubs/configure-sre.md @@ -3,7 +3,7 @@ title: Configure an SRE agent for FinOps hubs description: Learn how to configure an Azure SRE agent to connect to your FinOps hub for scheduled cost analysis, capacity monitoring, and reporting. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/agents.md b/docs-mslearn/toolkit/sre-agent/agents.md index 836779c74..d677010ae 100644 --- a/docs-mslearn/toolkit/sre-agent/agents.md +++ b/docs-mslearn/toolkit/sre-agent/agents.md @@ -3,7 +3,7 @@ title: Specialist agents and skills (Azure SRE Agent in the FinOps toolkit) description: Understand how the FinOps toolkit configures Azure SRE Agent with specialist agents, tools, skills, and knowledge to automate FinOps and capacity management work. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/get-started.md b/docs-mslearn/toolkit/sre-agent/get-started.md index eefc72449..1da3e0191 100644 --- a/docs-mslearn/toolkit/sre-agent/get-started.md +++ b/docs-mslearn/toolkit/sre-agent/get-started.md @@ -3,7 +3,7 @@ title: Get started with the FinOps toolkit on Azure SRE Agent description: Learn what to do after deploying Azure SRE Agent with the FinOps toolkit — first queries, scheduled tasks, and specialized subagents. author: flanakin ms.author: micflan -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: quickstart ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/knowledge.md b/docs-mslearn/toolkit/sre-agent/knowledge.md index 985a92b4f..2525342e7 100644 --- a/docs-mslearn/toolkit/sre-agent/knowledge.md +++ b/docs-mslearn/toolkit/sre-agent/knowledge.md @@ -3,7 +3,7 @@ title: Manage knowledge and memory (Azure SRE Agent in the FinOps toolkit) description: Learn how knowledge grounds the FinOps toolkit's Azure SRE Agent in your team's context and how memory keeps operational learnings available across sessions and redeployments. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/kusto-tools.md b/docs-mslearn/toolkit/sre-agent/kusto-tools.md index 6ee383c9a..1ae2520f9 100644 --- a/docs-mslearn/toolkit/sre-agent/kusto-tools.md +++ b/docs-mslearn/toolkit/sre-agent/kusto-tools.md @@ -3,7 +3,7 @@ title: Kusto tools description: Review the FinOps hub Kusto tools the FinOps toolkit ships for Azure SRE Agent and learn when to use each tool for cost, commitment discount, anomaly, forecast, AI, and price analysis. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/overview.md b/docs-mslearn/toolkit/sre-agent/overview.md index 3c8433299..902803cac 100644 --- a/docs-mslearn/toolkit/sre-agent/overview.md +++ b/docs-mslearn/toolkit/sre-agent/overview.md @@ -3,7 +3,7 @@ title: Azure SRE Agent in the FinOps toolkit description: Learn how the FinOps toolkit deploys Azure SRE Agent with FinOps and capacity management automation on top of FinOps hubs. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/python-tools.md b/docs-mslearn/toolkit/sre-agent/python-tools.md index 01a869551..f1b4e654e 100644 --- a/docs-mslearn/toolkit/sre-agent/python-tools.md +++ b/docs-mslearn/toolkit/sre-agent/python-tools.md @@ -3,7 +3,7 @@ title: Python tools description: Review the Python tools the FinOps toolkit ships for Azure SRE Agent for Azure quota, capacity, budgets, anomaly alerts, Resource Graph, FinOps hub health, and Advisor suppressions. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md index f16463779..9c9c08a95 100644 --- a/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md +++ b/docs-mslearn/toolkit/sre-agent/scheduled-tasks.md @@ -3,7 +3,7 @@ title: Scheduled tasks (Azure SRE Agent in the FinOps toolkit) description: Learn how the FinOps toolkit's scheduled tasks automate daily, weekly, monthly, and quarterly FinOps operating rhythms on Azure SRE Agent. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/security.md b/docs-mslearn/toolkit/sre-agent/security.md index 0b7d89305..f8e5afb90 100644 --- a/docs-mslearn/toolkit/sre-agent/security.md +++ b/docs-mslearn/toolkit/sre-agent/security.md @@ -3,7 +3,7 @@ title: Security and permissions for Azure SRE Agent in the FinOps toolkit description: Review the permissions, identities, run modes, and data flows the FinOps toolkit configures on Azure SRE Agent before you deploy it in your environment. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: concept-article ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/template.md b/docs-mslearn/toolkit/sre-agent/template.md index 80047181f..a36aa9b7f 100644 --- a/docs-mslearn/toolkit/sre-agent/template.md +++ b/docs-mslearn/toolkit/sre-agent/template.md @@ -3,7 +3,7 @@ title: Azure SRE Agent template reference (FinOps toolkit) description: Review the FinOps toolkit's Azure SRE Agent deployment template, parameters, outputs, script flags, and Bicep module structure. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/tools.md b/docs-mslearn/toolkit/sre-agent/tools.md index c7bf92a09..e10481581 100644 --- a/docs-mslearn/toolkit/sre-agent/tools.md +++ b/docs-mslearn/toolkit/sre-agent/tools.md @@ -3,7 +3,7 @@ title: Tools shipped for Azure SRE Agent in the FinOps toolkit description: Review the Kusto and Python tools the FinOps toolkit ships for Azure SRE Agent for cost analysis, anomaly detection, rate optimization, capacity management, and operations. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: reference ms.service: finops ms.subservice: finops-toolkit diff --git a/docs-mslearn/toolkit/sre-agent/troubleshooting.md b/docs-mslearn/toolkit/sre-agent/troubleshooting.md index d11ec0516..32a7811ec 100644 --- a/docs-mslearn/toolkit/sre-agent/troubleshooting.md +++ b/docs-mslearn/toolkit/sre-agent/troubleshooting.md @@ -3,7 +3,7 @@ title: Troubleshoot Azure SRE Agent deployments from the FinOps toolkit description: Resolve common deployment, tenant, connector, data, and query issues for Azure SRE Agent deployments from the FinOps toolkit. author: msbrett ms.author: brettwil -ms.date: 06/04/2026 +ms.date: 06/17/2026 ms.topic: how-to ms.service: finops ms.subservice: finops-toolkit diff --git a/docs/deploy/sre-agent/14.0/azuredeploy.json b/docs/deploy/sre-agent/14.0/azuredeploy.json index 4b6d42abf..62832fff6 100644 --- a/docs/deploy/sre-agent/14.0/azuredeploy.json +++ b/docs/deploy/sre-agent/14.0/azuredeploy.json @@ -78,7 +78,7 @@ }, "actionMode": { "type": "string", - "defaultValue": "autonomous", + "defaultValue": "review", "allowedValues": [ "review", "autonomous", diff --git a/docs/deploy/sre-agent/14.0/createUiDefinition.json b/docs/deploy/sre-agent/14.0/createUiDefinition.json index 25d538b3e..3b17beb78 100644 --- a/docs/deploy/sre-agent/14.0/createUiDefinition.json +++ b/docs/deploy/sre-agent/14.0/createUiDefinition.json @@ -122,7 +122,7 @@ "name": "actionMode", "type": "Microsoft.Common.OptionsGroup", "label": "Action mode", - "defaultValue": "autonomous", + "defaultValue": "review", "toolTip": "Review requires approval before write actions. Autonomous lets the agent run enabled actions within its assigned access.", "constraints": { "allowedValues": [ diff --git a/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip b/docs/deploy/sre-agent/14.0/sre-agent-recipe.zip deleted file mode 100644 index 3205d3261917753562b85223c53a3494861f445c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 342755 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

+ZuQjJYIib-ITNHdWMXC_ENmM45O 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 z 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

9L{$WKm$<&9PR3j%+v7BFLZXXn2+_x4}y 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 z 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�Z!Hm$Rcdj*SPS&*}Ox=v=`u-=MTwbTuyw>Id5@*{g&$ElsDy=X=Hh_U~pfr~# zW$a^&e54eI+V}p)vKFo-)rSy1VMMTum69% zcWBm;U1HDFYr}yZC;Rq8v+*8O461_m=@3)(WjeWJET=?$pWON(n7%i+V8(Ro>kKE- z2E!MlCjRy2mM$&*X{)@`18w$npp|W!%^zrpZ`_ZL_YRGl)nT7^^`X#~KxPO!{~zfp z8w!O!zH|G|Z-%!&8{Yo(*Z;`#cKib!ul>#}B6?w_j&I#MFg+u~8*OZx4&}pX5Zi^ z7R$4&QOg>Z>R0w1^wVd&m~G|s`Fer$?fR`V4{{jOTU4=z9C|P)HC)Bf$rchd8}B{f7`LWOAkyu4X&)s&sMnJ>Tge!%xHGa>?SH~BU#>|UH$OwW zXA}w5>KGOC%VxR&i%{Q|g-dmVZ}UWkJwhF?KkV`W*%a zIE-g$v*>n~VhU=_vg}JsgJhab8ut^?F1jylALL)O?w4xqY!Im|1^gjWdaQk#5cj*; z%(hFaZH+?Y2}ZgW{p9U}Kiw*h&+X$ZkXx7DH7m^WJg zyq$q@-vnDxoSMmBfT8SvAg8*8nbM+Aq+geDjbn6{57X6y&(;|m0 zTHbDWQtO$&qJ=Y3=Q+#@9>ix4dhwtzKMIS#iR=Tj2S`oKLUFE&{SA9V&afx%dfIYU zHJrlRYzjL8bPle<96Jl%e5zwVVdIQe9fc7-tVD_1RS+9MxH_FSPo6!FSFyV6po$-( zV(kvD8ZwCPFqQ@O!U^97Mgq1Ec#3=u*>>}d(^Hcqgs|e{x(HXtZe|KfR^N(4J7BPV zn1K%TodyaQL-G*NjUq4s+SX0O(b_+v8=Zfe6KryCyTZlZ@M- z3mH_=&9;@Z0BP-`S*Q*Froho!))&^#0Zwj$&S_K7Dxh-Th~$51)KXmG9iX^Eulr ztQ9SQQwhy)!D|v3WsEFt2L(KRF$zr6VKAo)ZRQOIN+Lmd)ol~IJWEhySm(>gi^YO+r~i#d{(%8NgpcJj#`&anuQ{?QRv_69mWKbmi zhE_Z$$Dq>si<+{D>*G|tPX0OhH2HUuFQUyk!=v{vO)aOFJ@%2hy>Ny~f~RL6;97=~ zvS7+$l_jMx9Z=1K%}yGfTjeOcM?43MT?xMkXo6_MHt3(Rncdv%2W)z_)x>P=PaDt0 zRx>sNox@6Z;qqBDL$;hyNUu$va7f|uZlyQx%_N*5REdLin2$Vp_Sl(>UCqG$@`03z zQ9Dqu%*J~^xJ=fYLw8%%hd%_n%=_|2ZxO<7JJcKTncat9$u{hC#Pb&U!C}ST{Q4i& z>s4AzkA=H^EX?gmU6&KY?|AM#uBx{p1-*NlunUErksVzqbn$`lkC6W#7(a(k@3=Jl zLpU~IFgNyRaF%|9KZ8$_Cl$p-<9osU5RY?giQ1%^gQl_e$5J(dV(3hUCY6x}e4@Ci zIz!hT?{dcl6QP43yI9<|-qX zR+p>rKM_Ce?{xAHb?^89AO7I?wnG_$kG&n4IQ#(&XS9zt z*a_c29e#Uzx5l^93cp@*+-V?2Id;37ywb!GXr+8a4d2xUlZ3IUpub;Ok?lU&SlP(H z9S17CvS&cqH1}gqV*rNV^Wr!KM5yEsZOy!Hk?>>5!L`^q^P z5gHTwzM7t~C-yO<1NXgA@SJ5+bg))UxMN(tkwkirIn=)}{U&q&rk_z}+i%yMaOa)9 zRN}&T*i5e=9gIS6=w8tEXr%=Jbg$HBZCRn>Yr)5Kr}R;3frb# z!5(O5dUwcP;iq?)-{QmrA9jX3mc@XH` z?9yrK3hjcopuxUyPs?h88eQ*GL(@#Vze{dMHc+=MN?f|{bbzZL2JIarpCq5&zCB3p z#I6gm$Zpaa7z=&WCclLV(B@@lYNMszf<AsY?od3PwX1S~4DVvGx(ED-FlH^!QS*_>)FyD?qx_%Gd z9iBb;;XU7zqkm;x;&2nkj-Q!tKoqd|XWthuN#NNs1!#VDAO3~s$+Rw^rTr46u`6q-<@ z_$LaRzX66E)No@+w?M$E1lI;F6Fi!M&4QksO|`E0o9py!VZT2KCN-2!WrvLRSh z8x8c%01AYLVBmBBBte7M4i+}C_aLFnAp&Xzv~WiB%avY`X$su!0P1I4NV<2{(Qv<4 z0H6W>xy@|E={aZ;;B7@SfG^dmp-coWu*$eF+0Xsy6)d4>3h}%lyzI>^!JuP>u+A1K7SH%?MPSIh!E{Z*I6+I zoOz*|j&BFo{{4&l&;E4w^yK;1)WqS{9q2V1-sigLz55SNUOak!_Tbt5)33k1e|mcM z{A>L4$)kH`_fGzFnj9ye=}t+GhO@THLRS#ym681oG)+*}oNg0ZtdHVZv%o*ge0qk> z7*^~n2gzyMI1b{rzTOW*FVXkfXGOLfuQz;VTemlxO1)V>a@WT*k=hAAvWr5|L%@S} zrQ5MN4qdMq?E>tTa06b)dvxqAYwW+I6WIF_bJq7#2y=haz;(vJph(VXm?1Ab-UEbk zK`e;%B8rt`I>&-hTL5Cqw||cJ9I6+YBwB1$H)fttCXkk7rnVMhaj=}7QJxo+>6m;$ z?YXltwjg5eU8-imcm@~=Zq>7N`Wli!b0(CbQ%7g&L#>dubP9Wyt~Wr~nhA<4@`?Vl zebjq?I*pk7k{2c>gSaVe+)On+N+Er1Th2u;@SgGv0~XDSL)Utzn&+3+gA3uD>#e8| zE{(nkCIn&tefkb%fb+y)LwH>as*P$S_pHI0>^n#Stog!U^oQq$)cvpnR@!@CA^&06Wig+jhf)!Dx=}?RBvSG$DI~E zADEl}bR0!^cM$Udc}07p^y3~#fw~RhDqm`*rzb|pWhb(;+m30I^ z{UHqX1N>Ve=CQNgcQfZ*w@IE6s4{{kpX0?h9Pb}C**Nc_gLXTL;{^&y4T__q^VO_K z_K9Hv@>7*9(+YND2A=6NkwV_|d;6@s*3shbtsCL}dG zFVXY<@)bP7TyszN44IP|5ApA5hxT0E@hPKish87##Wf-;EnVXGo4@aUJvo*-FK@fP zy1bp~O?NxHk9)SW-NJ5Re+#>B`nT}rZTn%j>JHm;r!Cp_f{txH=TfN3>odAh_N(&R zFQ;P=$i=$@24+<;k~eX+ruE(GD$%~vbX07F9;>yT3~$oEimq8qc24P-I#^Oz0mihf8ov_djA59NPDRl# zJ3UE$baE6wE3XNH`N~9<=wcT2=fs#4% zEZP+$jb&@6+pSZ2#Eh%gzl~~aW^4Eh8#|;`v_zL+$>78asQJ8VyO*7|qwsw=-n;wc z^tqGGB{pO+%lI`;pPxLsA6s2&-?>ul44K?G#(paXci7r(3VP0DS&0?4Kl@AHx6MV{ zqr?9WH{?2!0S1XkIOjRpm7Tn#&>m3Q6Uoc&^r>o*JSncumoGUd|3L~LiM6BRUu7$m z!<|VdIg;E#G-=uf?tBn=K{kHPRNg-j`?htXfRA8)1-Ar&L!fkYg6D|^;Qc$=$AWxq?ynFv< z6hx}rfP|P?iqR0fr2K~X$#4GldGgHnk=WSZg+|H2l4%AV1}Tx&s?;czIQ6q z=|P9qP|kstvhk^@k3{rA2n|o|+fo{{Fh2`Y(@D&Rgm58$Akmyle33< z`GBhlb3myjQ&Exn;ql#*pMW&GtM;~ZIav8#qAW?p zH9dB#on3u;c4z+}NPo8*oi+wrG6qu0+pGw+Wv>3#CE?JnqQJ`zX?F}s>^o0HxD(VU z@61e}k%M?x%DCEV*WbWLsAlKY-(r%+N^WvTE6Rqa z!FL6efwl-SuB>vZhH}7D^^GWyos!gk3}H z2CcA>*P92zxp!QC{O@%!<(!rx*2(x3YYU`fMRuBbdHYq^CzwDw7Y^K&DBQj0qs|5> zFOec*7VQoZ$;fjPS*S@N7YZ>&BA#h|oAAsTq}$AHh#kQuf_s~K?Hat|pB2@9(CGm6 zW1G{{LDuq?_iSi>Weq$t^I>r2cvei z0+`&Jv(vj@-+z1}mbwQg4WQILEC520==_W{$9$%*M-oqJR>{(6TvB~GR zKNIUS-z}W#)!5kLy;Mlm`0k~(ReSc+`G**o%RgP z%-#hK7E#LWRWl6UtIb5&GPqmmat}eaEig?ES>})|cfQ!A%zl$G*AeFmjgVx&K2haP zuRsDEZBCaSI~Tb9oP$8hfXL>}?<~NjGZMq0bmWLvasSb+L#N@V*JlzHc%0mL+#C8d zNIvcH_VXDj?RRZEvbkD^$I=bF#iGTf!{kovK9xyzJHH*u*2TFczK8SauP;FndhLUfNGOo=m};-}MI8>~z2PbRn{N-Pe(ZZhk-R zaz|>ghN{SlIrBagOCy`MSGs;>Sf1W17C+sND|ElwsjQ`_I~BKHM?J+iI0;8CZxaxV zjRC>D|C;P+Arz;*_~4`D2af@J)8Bj)!D!R&*!^0&`PJsuR5|$M&METf_0C7>m$u(s zT~XhTjBFY=_B^YTAN=`yL$T*cnNJ4*EuAb#AW+kqxUe7k=Jw5Sny#JDJoC1H(``O1 zjz;4L9`LOmHSDcdZ?v*MtCPCPa&jcV+;2Tl@|8X{ji;Q^-S8F2`1+>q-=9M zcGb;4BXQ1nK{~PhH%U`=BZu!kiEeG*NHJ+@Qpp&zXgrx6cKn!TvO_n4z=tzqSZ# z=ZGZY^!teObjrAJ9pq0DO~kb&e!7wMJV+8R#-5qx`jA_AB~Y@OP1d)`OIKbL1oZ3I zg+dnb`<=P9yjCpWlS{M$Y`oEu-b;Q&xkVBT@YC8A+FZ0bTY<-pFU zCu5b4^CY9eyPAtc=+?LC3NOa6y@hpmd)0XJUh^?8+jbD%%c^1u^i~$bnYi_on32qh?9P6V63n02tl}(T$LaW( zOV4ox#ym|j1&2w%oj@Dz*Cfj>K=euAp*J{Y?eM4vCU5D0_x>>}>SRSC)xH)`sI+|5 zf)%7PB$drjSVEy`$6__0T$K_3fWl=&qJ7!Y0ieo@uqk^{ZJWc)k@Gx-BRCNJGV z?6O~X5to_7Z30A=m%W4E-kQUu>wa<3qFNoSx8%cFK1{&G+iYm#FvpOd@8YMU&F}=m8X4OeLtxR~|S;ggomg|vDm9R%SfhQ?}Y;{r9 ze9}`ZOv-1EE@S|Tjl+B|ucmPDz*mXZHco3e)ghd4o>bEm&aU2zgU#d*+VQ<(o=thl z)?e(s>0B{7@=66ue*WsQ@IMKJO}^XPzAM5eL*9eGJ`d%(-`my!clj zdtO7|Lr=foQaye8`uDxZPy0{y4)&k#{;P{ld+^uiPae^uijGJJNA=*Z&tL56bokp! zry-J6sI$z;wg2ki&9m1}5B~aGI2zigl9L#BN>gL{GA)q$yg3tjbo<3Fup^Sv_x5S96;^qv2->OqDkVZT~Ac0QxKAq`- z^rY^?F&P8@6)Nvo@}NxXbdY3?$ity#!5Y6rO)SZG{R+f#L6jnY+(S<;dtTt-rNPEp z#7qwXjW&i!Z+dDQ>QZ3+Xj7afSxU}Tw16%Dj>e`;RcR3O0*-ujKlbHH@iCZ0VL)4= zs5F2Rk__PWMCSeSSDK@qRt1*ESehzaGD@gL){V4EvV1mK*E<2IK`cr|Nfm^Hf+@l8 zmki!r)jo<-0^lD6MkzsAyB4k)3Iqa?ybYAENIY*{wON~IzeV{}Xm7Vufoa0X%@oDD z<`_^4>c9aC=Y8*wv^+SLhPwsP{M^I3)4jr^yaUoD(6QB9f4bf;ZNA>A(Ae>&-?y1h z1MpQ;WI_o7R!^lmDa;292vmp!MVlxz&+s#VWk{9c?%RF-9PEyA@zF)0%kgZ1_6gJo zb?*3=Dgw3ACxmVcPcZuqZewihy&JKtd0hw+j80rPO$I$wTZi@72a)rmL6Kk&ct#p) zxl>dQ^+m$&>dj%PDu(1v}q8alqF99Adr4&27L!TBP}Kp0oJ0& z4-(+1<%k}Fp(N5g6`&D+F~Io9Kal%WQP^Yg5|ycw8D0ZM;0o}T#*j65C;(Kd)c;6Z zUNo-MAIwT=)Pr?Uk~HDKzb$gq6on~J$y9^w`D&k@k=NLJh$Fn+W?un%thF4=Ngpmv zSgC=<=q$4S0Ob$*wa~wRe(tY3ibZelxn^Y8aHRDGLaev5qSc#^EOyYc0M9QtUSeBO zo;01gIJ9c12>48MA^yC>?rpgtUXP051@aiKXQn?$Ms`(y&ChH3=(BUX;}NgSFB|K@ z4)y@WsE2o67O(j@1$7=D?hBdiFW}Zg+%HrfXw#ekDe3KlTXv}`YnlnD_1(kmtu63p z3ejkMrH$Cd?G%i|9RMw!+xvTS`XmU)E~TJ^2BFRh^r&$I3k^qj&EEIc?2YKNNg&+h z(pGVqRJA(~qCnUl$nNFOGN_?XFQR20XT}B5pMsX8@tSZr4->K#{(&V`zxif3J5DpM zGI{}5q(`m1vt-5qLB1EPEFKP+VonQq<-6B(wLvgJGJJw~Xp)TS4hUP^;WWBymw|-m zX?|kKx~#VK;MYZelod$}jP@%*vYTxz7nHp&z?-;Vz#*Rtk&sz5pG}T9xU@JuwM8tH zY4K1uu*9ga#q*5Pva0)V9`d|i2duDih(?2zjy>-#Xg`pKEY}daK#Z5=#~T+#mmU)^Ul6Xtp|uu>+!XINNeOAS!-jk(P8x+MBzQGzT5crPg3026+5)En30v@da5GqY8f~Gi^TU%F!TPcUMq)4fVraQ5Ah-JAWpfq-N{#GKevzC= zz%%Wdg<5(QVK>yTXvPQk&5RH3w-J*$pB#a_efV4U1^N=uC%eo*T7WJ~{?LDm@a+Pc zuj-3wLF=zR*q$|B3^xBD>S_$u1bO->+yME+PfRMoQMU()q@07lfS1B51&hW_H5m{V?NI7Q%HlKcUJc_Fp7NKs@M&u8PvQT;SET!x<7%NKa5Iy)jO z1`+}?V#eSz+{V{oT1~U$LWHaH*%Y`yWfQ?@YoUOh;USS*PgdtNHc6(_G#_K&dQG3X z^!}~L`3sRN5`@y4q<69<|g_jisK}r+}fA4%B0emRWZoCuMX_ zJF`r9JY^5WNoUxtq1&XLO;4pqU07|dZpmRvY!pm&k^&OJ1w6!3X;zKzD6(U=EVOk8 z2sr@iIO2@wvk5PgdfBF3UN2f{7OQ_`@@_Tl+Voj&j1yv@@3cCNq;S02e31^y0t}!x z4*rqpQ)=^r{PW|c*|2?jIcB()^0iqO=O3pe`$M}=7`uR|ZLXM&M$r@#79fZzro0r^ zoc5`ulb}T(;Z9z9#zV@fQd)!vFRu=nQtfIU(~n#l&ucvE(>_|q6Vc`wB8I+-lOpkr z>6RGo3C8GmQ7{-ywPhib5V#d2_6OKciJXC0%zT*Eb}qNor<4O{;oW=DRNyd2r&#nF zfXYO@Ze_oSftyzuR*03!>xq8(w~_UoeuPq_W5X|Ij>9`|^OL+d%Uvy){0H1hU%OU_ zd%&s~vb>f#{7W#fXiStILCr(6v#`(Xh9QIf#f9ZDcHtaLT=$;{MOE=yNCwwkBVC-S z2tqkoXwqNX9oZc@D_?UceFy`HpeGz7N!_5P0q=?fkhQ z7eElegm?bR^uS|jmCLFD_rj>E6Pvam%kBeEL07F}FB0L$M!rczOjK(Vi&xbGB}6&@J1OP3H{Hfe3+moZna6< zCdqyWC)d9M6~7cE-Y~oQ@X6mk$&96u?0pWuGR#9q7TihAW1p2kA?ug4#0ooNF+^ER9XW^nRzgP#M?4}`k(PE7YYK{T8s$7rqF_t{8-f;{IRztij;?=bTGk%{ zenzP$O*)0DL8_GPM4@SLzLM;};~2w4cgrLt!mH1)T|Uirun(oHYzK3#wiY^GW&r~} zx)fAu&3jltY0iCkafbJX3{NE+HX^FJazJQVM-Bsr;qnd_F0yg}CnarzN-8 z_BXqH-G_i@8#zb@$F_Zd$RZFT+#LEW0gE}ex^>I&smRgtCDN$19V2u#Shka}a$eO} zJjR|BgBc(OJb4t;o%rtk*6|fTpiDRSImYLXVQ6#?<0q4O;?aHV`>w@?GC1RMbu>=6 zy@W#Z?JTmk(;cgLd9y9iV|GPL3r%`#2ZiiRt%cwV<0BpRZ*cKG|dS*xFH9Pls!If0=3BfBES0n%%2>;eV?yLa*P!v>tz6P^$c&GEOw~c}x z=ey)op+($9{=FQyi-PJ#_=Upvrt2Ya3+a)ATKx2*k|!tDP7@^}yopE+vL_#0>8ng|Xw-GSh|Irf)U}YcVWdNn4(raoq*>7)SW+7i z=~e@S)XE1XN|)J=l}%fBNuW1&me3rJ$iK;Qx)l6J?9!3XNb|gs7Z%$Ia}9pZ>$;*Y zag&?W8T`F9%J!0?FK+;&T4TS-7TLN`IT6Me^6d}V{VinvL4YlXpwngdw`ih7j4=|# zdqdQ*uS_+Yrg4n3lBB?V%h!!cEI2S*5G@5ZmAo-TmUcIWF~PR&i207uCK*9%6|w7+ z{30YFG_GLzO`7ScU>c zY0jty$RJCNVfmel`hRdmS7^a2xFHMD<$0h3t7qb_-x{Z)y z7t{n%xfG+I!#iVMJW2*9v#GII9y;!yxY4^HN)P3RL(~8M=t6)2feA*i<@nBzw;wOl zu94k*_-vsLw<{lMyvVZ@idX3$yj5$F0+H$=Qdu(QfNK4$EY9lVR&6wuiZ#^6RO;hA z2JQNkg{@e#Qg|MKtM=x|y5y^%RxyZ0uh(*8Kxh2lYjd)f;5FVJHx130_{Q>l8(S%@Ksh6YS0;O-)679u{Oz) zBclk!D$jvX23Pr@1WN8h$HsJZ8-Is3aL{}FBh96VdxU?4rBldNL$-*(MpgbYT!q(M zq@LxOu{*4403`j|OxWctkkxr(MsJHiSV^%1n#x@dTO8rAE@_l*3QHqT;-$S)+nWS0 z>qYx{-l?z6XDXdu4&C#gtFg-vPPS{YV{IeDpX;$ejy?+*=+E`)TcB}I+0bN^>(|?s zVxPQ^N6!y@q^6yL9fW~SVVPNZs0k&UX~MhZct1nNw4BC%D_zm>{XhNGYPg#$JGYg z8?j=N)+8^?G6Z3cxK)FbgZ8FgcAPr71Fon0&?R28V#E&qkv)0Th5xxyV!@WBjQ zh1XUW#%wps?4Wh*Ltv6#6&^VVe`g4lomVKCD!B>^tyZ=}17n<0|KqB+UR>FrB76 zudC~fOLoclPDo;3ljxRn(^Ww=e0>@|Y0_`E8p@=6z#)*Yy?i9=Kc1z-{uJWMmVoVF z9^UzH@3wjmlHO>y_sjbaKYr|)KkqH_bNlYcKdJDv*g2=2|MoA3ht>P<{zd+Ac(@_| z#Dc9uCLv?-K|>qBqgDgOD#VNV;f<^o4atieDGLQKFtqeY+dxywb#pAih{`I{Sr)~U zS%o+ui2xaS_IB@yOS-$3F59-ZX5HaZtr~;n7V^YZ)*gsQ<8kY;0`n+)1Um+f7Y5mE zsW}3V-&cyAV3p8_MKtqEA7Gqag(Oq6j3-si5abcE>WLQNPVg)Cj*dVCyuiOOXuH`N zYpq%vvP(sb-r3b(u6H99s6|ke42NJ<_>g_DtADrk{-d#)1aP|*y-p+C?B!KDKCXA^ z5VK&aOkwRqKQ4sj=_I4T+ZRh9+=$stWzXQ{f-sAFNTC7CCI4Mk!vXZ^YjiVYxJxZp zo0IC{lO)Y9cBwayE+kmjv$B{?-I6|hn!G*&14kJ~cnhLiFpLB?7SU-R7qjx!=t+WE ze+*`UILfa^f8+ebi^-=mopF9ry&AnJatMzS$o4UW=%)CBXjiJ)(Z6$oRFu$Wa6dX6 zNno0(cwG>hk~-dkdi^9H&s1q`cB z6^R#OAQX={EJ=%J1LigMWX^6i_Y-XH7MoY`XS)MgX^3O9sy@79=`AS=?UoS)wi8+_ zp=cx1nF$vthQwKpG7!m!mT{R{hGKFzDSX|5Bi{Kg!=7y4H9*RzD|*TnwYH*%;L zl`t33GJ~pynREcD4J6nROug4ZPavj)m>dnB zAF522M3_ydGW;Ytk6@sVG-vB~5wdw}+vX%?SiAOuRyR|LR(dp@` z)FB=d8EizZt!A9SKquP^Lhs(Y6@<1Dgq|Jql2h<=YiE0shqE-x;PE6@$dVRHnGl(kk%kGqOV%c`J`RLC8U$Ojb_QD+q=1P$)yhFQYDhQ3pYg?X+Mr=C+e6!6wpU(ck4McKd#ti zjsUsYP^%3AOx%-5lJ=J!3&`*)ZH9u;nlTxMOkMG#}HZBaK><-)ho*rp3w2rK_A*=o>SP=+&+y^2Bt?STU zm#XTrZ8>lG(8~n$S{dUK>N&#aK~nQ^Q3~-XaESpavSd#l+LP(!gVXmJF((g=<3E^h zpOF)@3YP17_^@EA@+n`RFmP%-J6@U);ZJ({?(GmO;9d*#bDC zGebvdmZkYvgp?gzEO`#}Ik}8}fWu_XrYJ=KG5g>cE~Gh9USrNg&Sg)Oed=F>qE(0o zc?EJWH1*`^soGFqoW3XUGAba>~3$!dgsQnX)5GCfwnY!1Md$9yPJpUu5#%#-RQooa+? zfLiMVkRB*{x3R|ze}|GS2GQArekka}{r;*By% zE8ZU!WuLaDc~;n1W5MRwH zYpKc1!EB={n_p&2mT5fA9YtlV%I2E@P0^bOvJ{9!mz5W^a}C!-J4W!USvc*kXOPqI z^MPj?=>nu#x_4jr`p}bfUD{9794n020-1sLwN6HpV6{p5McG$tABKIhzHLdWOtx2u z!7P)1`o;k`^V=y)M3u&Z@m6vj_!3DBsF{^832sdE?8l{9IF0)@n~ zdr#P`A`#C}XmY}eoG-=^Gk{O^g{TLG3D?)97xcl*gaR0Z@yXzL2};1FxLdBOjP+N>cogK#sABCfDNZw(;6 z76XWDKgB+cvBMIf2HK$r+*(ZBT18ryW&4&gVPs;3qO_K5i&WEZ_CwNk1=_D1#U@9&%lqhC3OV}_i zK?|U}uyL5bump0K~c1DTg>dvlv{5Kw^O5r#Yk9tltfDh9Ez@dz3U8ii7*!eG>g zIoYeiJt4YUrq#(6Q3;k{Vg!W_9>3auI=6(O=DH$=yb7o7R%Or$9}1MOGZFF6H2@8iOXpC;dPb zT731lxm7sZP)NgFarogK+N60wx|zc}Pu2Aih$te~8Ep&uG8LE2uo%o>b>e#XiRFd7 zX99O7J4-5hTfh}nALBL^_Z)P3!(K|=g=PsNG1CYwJU`VxGBLQ9nwx{h;(>X&d;cq% z7D3meS%s{BHBIoMT5yJ_mZMp<*;vW^xuS|5&8z5Z-%Y>q3-&t_dx|{Xq7!z)FRyWRil{ zE7><thcil;-Ok}yOS?pjd7adCX%1r-8(Jnk9v3M&Y-2)m zuw4O$R50n@!W2cp<6z_8i!^sMorB|~Oa?VC9gSsC>LgU!*J9C=!v`?=S#ico*Fq~D z>2e!sm1OyBV&>_DiHAde9sc92KGfGYZmGjNZ}XG9ILqmQub;{O3PTM@aD9oo0_X=Q z8PpGDAa;nm&N3R1|3JGRD9}G`S)y$|&uYQQ1~Y{tX{V}zhkuGPV=2?<1gI7Z8|sec z6+`0f0e8R1f_By3YSr}NO(K?^(X-GRl7fuj;cP4eal@=wT;kATk33$pDKtIzcJ7R;#~L3B(ciw_?r$$2`NO`sX&+hGob^2M?ENMo2hl2i%J94lJwHVo}Se>$ia zA8@AvF>3mwvZr*u_or3@jJPf@(%yy!-`f2y`SMUi=VN>L3>FHLt&#fKavKT{Oj*qG z;kp`kQF7C&sKdTRqfK_#a^-xzmxhk z{{3FuJ+^(LY#@9_>*lfThA!g_xamLdupeP<`a6JLwmbgmAD?5_?9!?+LVNvNM>pnn!!!I7T)#G#j?C0;WKG5nDk>N^nL(*N8bobhIo=fi7hn zQ2I=lhq=!$n@y{BfHCwXGK(5y`9d6jd}Bpg=JupDp|No?(H%#hNQHn*1O8>qk5!7E zJu@0Q+X9FPF~|R*H;2AwLEDV_CV%KK3jWA}g->h@M54aC#E19##s`ys^enOYk$-Zv zS%-I|$)f$$9~9>ze`xRESoZlDm1qr40Q=|$`i&2P-ESs)HG4PVLvdv|32-???k;sa zVr$3)dU8g2SU;pgR{Zt{P%1=!+-jfq!F`qY5{LJL`+;dh^FZ1S!S&^4@vERgZ>+-3 z600J*&+QC;aj}_sKAaXQEwVrzUM{mDr4ojJT7Vm39Bl!wAL^Hv&!x)G(L|l0IR}X{t-NYBnIzx~2K0hcO^XUlf}mL7yZ^Y= zHJQ&hVVcngDL%RdqCvaibvP$P8jM)j242=7{%<`fTevQ2C9v(YXb6`Jk8a=AeqMw( zaK&uxgn4aUNruBdy#zoEVmv_1+uYbx)-`K<*Egf_F?KEB<}mXa$B~;Y_StFQISI_{ z=5v}J`JrRMOtGH(jjucVWoH19KyJTqvq~}4z!*z@(Ppv3?-4(b=KSrnfGpg5)#_f@ zQ)KlfMC!75_@zGkTrL8hmijus=J!(5(Fy}r_4)Y}QDgf#nacIg$W*Q`SXbxOAK7@( zO=eD0i2rgoTlgLcksp0({sQKumRJDfs-ZVX!-Hb};~;j{G_&yS+1dyT|0%gumrreA zJ;k4M*}ceNYIM%X964gm%yKq@$8MZii=M~+Ln$CYwGQo0{OuHd452D2`0j~uh;C_D z{YgG1nr`IsEKzMMu2I(0z%O2IdrBvmOR#!QQJ2X(yc06=O~H>qTGmN>g<^zoPf|aC zA;xHiyl7)Tfr>nv4Z->ZO(sLezu@~bNx+zR!}YGzAv`^^(DwkFux(DRWR&IVO>Mh(dKC&tX0+^nH49*!^k)}=DKo_yhTgkGCPh1uLXf;*BiC- zb(=t`tlNmPgNe5gu@CmAS+5CY&ir0_Euxw)kX4#DtBlTCvDoD{*SWPA%!|pnrfDPs z+J9#ex<&(*B$CEZkm7C;;9%U+njWc!6NN=LgaFd|W^3hS%?(T>;$bzFP|UNFGx9bO zE)UMo+M7uFMRdKpC-4L?M;#QyNoW``VwEP%~t+*nq}i=30HX* zNYiSxEw^SIS*J#&__A47oR--8PyTCr&WSzM@{F@ba3{*Wd1JNH#OkX4@3>5_s>@)G zcF2NIO8aRTs(vy}gO0%_tF#k3^%_dyc(~_jAh)w}cbd5kW^#=XI4$sDBkN$F2mL$#J+DQ!TXqJju2%4BW>t%DnmLZ!MT|2YWIfG9ZL*;fK2q=p)48~fVxdzRC+huVU zw`dMDDPIg_VcG*(uN}8`^P1``*h~Z*&7J6XX+GrV??DxMCjO2W#1kFz;2!CG%sM+=iD1}q8BS+71C)gGyI@aZKRSK4OjFQ>8RU${X==nX9U(uc2FxRkcZ7@+5us``I4IqMISL{_Ju>A>#%E3D z_$voM+Ab5~Pz<5wsW(5k9s0OQ55YEQZd>;kL35KWH8APn(Q<_^o?K+kvt2En;G@%i zwOg)^-e}382~;C!*>QT==9L@l^xVg;J8}MdcQK^1#{D>FPe!1`OfAP8a{bM_h;RbY za<%fM?SL)ezx9AFvia@xtQhgQyv7I3Xw5gN+8w(V zXNIidvRijB;brd}Mn+43d}3|mEt~%qq9xB@!C>uda{3}Fg%~dkU1awyWONU2mvB8~ zQG-?C+rrU0S7z|yilg&MLWqfNVgkZRK zw2#vRXW1@<#B1qD?A9n+52195Tn?Nn8;dHo`D}f6NkO*_b>^%V#BoY4t zeO5KBT@=u6$~KG>b(y5bufG>AKqlNMR@@A@Br%Jf>;f_#n-dE3d0rt_SffP=qr{0OIlGt!jer2 zXPs9YhxyxzvlQ`K)BKd@bx~fZ#Uj)fU9d_5(+z-?AEo12Nl%zznT~40QUv|cVXh!> zaJX0vCP|3Zn6tVpX7KB{DC#sH+sG}|Aj!a$x|;FohJzML{g(wjDD*0VyKv4fFXE}2 zJ{Pc%lp7w%U<@))+#*JP7Xr`_{8H#8E2aZ}3dSFG?ol z_OL{q`Q3~`ExQ-{Dxl#oROw+Aja2BmEm~Unu<9gQw<+e#=5=ho>b^xkJw5$moelPH zPMuaKJ=wiSGt}lb>sl2!^@L)ZtuW@KI&;1dOv%{pzZA-3o72HXE;Ww_U!(-vCK_qa zs-}hIh^jE=Yb9H2aJce9#aR{3jTeWxwS3Gj>_(1jdo09*5`_;45%$QWWv+>fn7!6* zy4-oncgIv|nbtQ8enkC$DOZ7<80h5It8*qI1J2_h~;4w9h)T3w~~Znyy^FSg@f zJChf8quHtGCK$4cu|70g#NbeBr^T?FP^%5xBG{wQ@P~pbx~A-&u?;L|4`N6g$i&%= zxUEiG`x?U}$oMM3ztHRkzPl_B_BH~n-lP{#7^ z$cqH*feKFYIx0)J0Uyx?JYBjMCOoY@Uf7gst-@# zsDFAs&59D7o7aDvRdvzXP#J}*oOF@{QB#_u?^`9?$T<6>$l-TBgtiZJtMQV<(nBc{ z1>|4?J^}*4RT~UjWD|%AC#7cfF+a==EM&}Kbq~OQtAhQK=C7s|`*n82l03;S>U2<9 z5w-?Newa^7KFZSZaSf8N8k_(VyWd!4TEXQv#m|I)mh>t*` zryIPnvNI_9_|=R3w{M=Bk;<`>yIXg+ds}}tSjFGo9=v%K%6G4~b+5Pm{ig{bg7u%w z`lB=h>{z#Im7+2$ZI;3lCzC|0oR>+k8NhVlmH6t}c$?F9A?wPpO749~?Muo~dF}B ztW1GfHJtS2N4MUPP}exlv~O}CUOBOzvJxMbUDgAd`?;B{c!!~EaG+vjO$r`vg-u?8 zFf*dbfNxf~Ep4Q=SR?+jL}@xjZZ!9uSgD=4l=wBuaKLM#!ZkP@*0930xilIk;_BE! z;i_7;-r<7c8GXzd;2^i+)Gr`Jk3D_CHH?1JV#PWS?QfW3lh|{f0Cc+uu28XOyzcG( zfy~pv$qczO;-n5vW>p_}MwU3rgKv=Sf%jHXrVyXuRI03#OmIiU)K#-`lnl7RSpq}l zR%Y^7)dqV~i0wGyr69#-Q(^5&#uJO!6<*d0F(fs^=1p@-ZAMAQvE4MjCuz~%F~n%F z;5=r?@bIt}lERy$lO@D|M{y!tloGKTKg`PPqb1k-5FjU3t6(_k1`-m9@L4qP3^J+? z3gCU2voA56FE!K?u|xk0q=zMf@XwPOw-oKSkPeFaXp&(0coHI80B@IscLDBha*c=a z@3LSP9CGv2od4q<}3i&BA!D2pjCYk02hKsM1){W+?6 z)dEhPx!HHEU7ziK8}vc<_0L5{!59gr0>4Zk5Q_ZA&mlVQ1Q03uBLE1~KvZrwVY|BHXsk?av!)dM6?4h;09bgUXjRXg}O*+Jpskm$xK4oMEn9ZY;6Qs zfil%8G4g?7prlT;sE61UsKbZubxMV*w}6?XlkutGZkF5) zx=L9$*yG~@VuYcE-3Xgg&BxmT=8}Yb_`rmkEG`n`SCd!|1F1_9pnyxTMgvHVw}kZ* zJq`oB`{e)L6#V#aZ!P8;`CvV021hI=&PNo3fALiqlv%u2`Z2MpL172FG-t7Q7Om8i zY>=uegwV6?+<8{Rg6Y(9Ipb*YV-8)8MnkX?rxHdbN(f;WbecNi(b}jxUFIuCES=z! z#${Mt1Ons9-2nxuKgKj&2(vrH7A?D%#U~BpXw&p$a7kW~OPA~SD3QT+WeHG~G z$Ny7wYbV~J#`Su3oMs#*K73TSd{V`qRqdWuZJt-nPpm-K7J6ze@Z9oN@CHYn-g^Aq z6{vysnq35fa6M1+lOPkVHbscdUz~r}r^@1NyZ=?lI-~r2gd-Xhd7b7_&POZn{4+xK z+Q=r}oK1&iG$x^vV$1t+4$XOkz(0vk@i5R_{0X2-L8G$enyG~-y+^9WlrWTd9nKBLD;|x)J&0mHcauG`HDsk76DLZOn`$;d?5R5zX_vaBs=90eolc zm|?zh@5ZfUoqsZkHc&T^A{H{;P>ts!WYq8l27+^71vl+M@dPpI5+N_GkCqh3MhI-a zPSl`n%%;Pn<`~ZsJ`j%#f1%7HM8306ycbQ=WBh8Oq){?SGt}hjDU#pfQY4bem}Tfo zyae{plnDUdIDl&65LJx=E8`}$E~F5nrfvDYtklrLV5Sz7hyvAi9Ld&)^4ll1#CJ0THWw$^+>j5-1W=tj<=4NV=pRwvMZjUG2;dU zx7NQ46N$ew73dy29hPmG!_cKGr0Wj{Rg6O7zdMzYPB$c-v=)mgY7-WGK|8{uWN^as zp=D19c-zx)nHZLf*6c~+kijt@oWLn^To$wOu_pqBZed=yjE~?#9PzT0@dQE=zeS8@ z+n5b2ZSHaw0Fa80PO5Z+?d7T)Xxk}7tzZCIv4jnhiucmI;(3*#nE`BeY*Ewz+XP}G z@bZ*1ex6q7wS2^nlhYK|*IsT~j$-X8sQO6$?bmM$Y;k^m5|UiBQd3r~mR7tAu=(n? z4&bxHL`osLaJ2TM!$8+j<(P-wILl`ds-l++Pt&R>d*D?uneco_Po~wdgg%e~H7aow zDRspzkkrH8(4tv<`aL@-a7Hk@VSvY1Ulr7BeIPIBj*;E|f`SHR1 z?fZA{Z}qnC-uu3H@B86)@8}-?b8qzE-uHhV@Zo4Q{4roL`s2N$?d1N}kG;|0?so6q zgJIHp@aG4-_uz*gAKV*l|M0{8;V4k--j95k-235PZ~NYl_j~t-gHbQ};m`Ma!>tEf z_lKkVTleoJRx#0`G(SzUbl7(%%Ni(iWJra+fg1dE^VsTQb~#WmWlq(hljAh^4M&{7^lo`qIXn`=m zb6fB-A&3TQ!?dn$XHVVIgj!A4H|({wA}GQGc*TQ@A5J=Y3?>yV4f(`^1G=0RnJ5JB zrXn4phh&=nJ12#L7{+RlOd*67ZWf}E0%W|y2pO;oR5T2C2T2K)!~rtoOyKu|e428S zw+uH9?^y9LcK(yCX+IiKa?@cS*Q^>wx(aPBxM3H8LEZx=y8mSBAB>)U?0CdX%K`?5 z0lPq9qik>nP=fhY@6-i7q}J!q(CIoYPRrsb=h|NrHTq?Lhcd@s)J%U}I%$Q;1+3@=(x+!82fs z$Ui8+EV*!uE{=hhTxbY{4~KXDR2NhDQ&9{v^(W{J37gZY<>1oC;iklN0?3 z7wmUCI=i|gYq6d7KNvjh$0u?RSPxIV0Z3449oHULW^)bJWsh$G`|^kk^GdKFx^LzL#il zA$o8{L9;V&^8EU2ztd<@!DdA130<@?s_f-KjR9Q)&NWC1AF4-$l^>1hwfi+`#jQ)r>}@EhGi>b1`nH4O zXx!LB{PIqZ_bRI?Lw1~;#x)muZ7f+w4EyP7>TX{h0%{Nnbanxrz$89_WwOCuBM8QJRBgpm}SCoLbT3pF4&SrK?T=^^rZ4-v^%L+$q(BNIzJ?%!W9GTo98@faZ+ zeeet%ZV9-a<}9&x-^O7M{!Y-mLL{=$lL(7lDfhwg|Mk;@H(fSJvcW7%YF?SR^oRMB zmjj;HP>NK>qbwO$f;^;^V2_d-rD#dbAlyAmj*3&xe%$(JAo{`me-@Fk4|CL=R3t1F zwlYw87c}OlDL(^B@&s_Bi;_KkySwio!yDI1P7+s?zaf?rTnJ=+gW+8{Nbm;9tO6xF z98_}LpdJ}ep5;Ya@f(eP^!(N1-8Xx$ULHhLpC;(++k@R_PlFl1*FZ_v4}jDf&Lyl0 zF!WiC*e(HCR#7KDHV!48C1sxG<0iP8L7CR+Aj!gcOyyYsFlK>3-d6O&rA6{~Q92ii z<84v2oIu_I{hZfID7bf^tQ+ldi6~ByB{OHa%v&lJuZ_#u&-bw*f+n0vY1NmfSYMo; zeLCXS>3LwiF)NxWK18{Y-WkeA9LncXQ9itu3XU8rML26~`jkHR# zd^R!jSdU@RDN*|*DNjf<1ji2C79=x;Khu0nKg0kCY%;t;gk*J=OdVKLJXDhWVx4M+ z&KM&D9n}dDVmjtT$f=}>T*v={h69ZB&EeNm4hXpEpr)*yP!5D$)gl$DOhC@k-_3=< zx2h~A7!_$&a>KG&!5ai{Uc*aLI#k#NHY#3=n`qrHi+=U*-glJ4xk~S>wEFZG{;4he zQydx1m;VOk);Q}6I}010PQmJI-CK}1^5owU1(EBxx*!h!vT=H>OU~~*Uix!fGR4lzc~7Lwjt~DW@~JC=99-KIvdk38T}8Uqrr7Wc>u=0d8!HVp{c%XGcBstiGfg z_7PaKR%}?D$#_$*raa%>W6*&Ld?$?_bnz<#y(llctmestbfY{!P0J!jBZ)d0lgsyL zmJ!(a9)ob$_ztX&i!*T2?xIk9%;|4rQu4HBa848x@Z?6H?kcS|7|9qPN{4S4l#{e( zZ+J4X`jynlQBq-_f1MqfNfapxmO8KDR4(f$Ne!=+Z@y8#zWL^-!yM9iK2)jVZ%lg( z;{oqh=`QdXJFw5ov=|;hHSFgdqju<%pXD#IeqGOb|KMcy0uG;p*%1UI8$&qh;{-e% zXfEJQ{~wHumf5bJ4z|OT-T#|pT)nd-sf7HY$^re4apFJ%oK#%gc4?ItHJ?oDi*>g$ zT*EZkP+6zT=H%$ktx{7FsnO0LDn#{)(U+&ja`VT)Sd7jXz?umZfORZ$iYpe(xS{1Y zAjEzQ+^T>;d0gbxY{G|soh5iNNfMuqM&J;0%Ao@yuk}r4e3WJx9~!yz2XTKNU0|j( zA3sK>b#T!&XT57oWf!~DH3y`t0-C)<|C8YIa@NH@FSmcgu7Zd)9gWt_e($iYF1+}< zPA50b(ZL57yovsU6(vMKIJ$7M!@+asDtE5jT35QLXd8mRlK`rP%LfN%#B+V{* zb;LNjaiSrTx!f{%(?+k+BrhgOcEN_cCO5n;WZ{DZAvfqk z#Zl2q;r1ex7pZf^KY_VXhhNhfk2#~~yE?p|B;bg4l;-Om*@~>h*3$IRxA3#0aaU4f~_W= zxTi%n1HQ;UX({Bh_!CYX3=a;BjkW`YZG_!+k7fKwPa{4WrGu0eBe~bgMvIDpmbMkEZp^9kiCEnGw6;Z^ zdJuGt`eV-~yTdkhbJ)Ty@4wP_&KJk~<8e+N4L$V91{u~W%h=|y|0sf!R}2$_D55t{ zXZ0opzG1_(6v!Lwv36b1w;9UO@GhDnA|EsZm8ehKztPuQ(b^(ckUBZV=-WaxDk%)5 zp!PkOGP1*!e@1e?!fBTfCbdIh1ch3xCIN~W%MPj>aV8Dsf2PqFkqFR?S1yfa-P zr+ry^jnHj)dsp4wRiEsx%A|s;mkb88G8tU-(tOCzSMstlE)|#}AlLB>m8GX^FEA*UNx_08LCqnj4IKr z(yM~hH1mojWtm*`GoFv@#kwhweFf>4Y1Z-o0i3JHmKL$ z-)LrvG+#ZX`Raja_2zL>nun^u22SxzX!wWG2B@EaIxyx#0mAWUmS#h#PDECzBCrE^ z*vo(p>Y)qw>Jc4!!u}Oby&4ejab*Bu>4f)09iCEAa#`a06ZxIJhK;G1E8>pu*eymX z_rWwh;hK3mz+UdCWX%50E5bI(kOSa)iKX>#UH*KUz=}nv?V6Y5NGRU_ig$t^%i^ER zx|YjBQO$}~@D!WsLJwZ%@bBoNQNejYOHsBN(0CFFljKA#KWO5B{v;|CRUIY{z8&;C zkTeu|VEoXARu6JrsEMy?K4sfOs}F7Il$;7J-d_+21mcSUwf!N0$4rZg_h|>Eyjs_t z0aO9Cn$*}&PJ6VV%x>2OBF_|~bsGLo*KSd#rzrO5h^0B@rCt@%Tb5R42qz6cZT<&J?TqxlDhGfQ(?<31}6-1pIJaKgz#z7^vw zm}%mM-x?(TE=ep#f=hNdYnRrlDh4S&6DeF#mMOaVDTX|w<;#aGTRTAAs-Vb~8%hDJs|Z#;V9TsjqL2OI{rp88GDEeB*v}b3YQZwev;t>yBkc z3&ytFz`kFBIlm-NehF55JsI|4Lv~p*>{o-L6xKAZYRnDI9NsP z+|*Fy*hTE%{AU9+%XZi`SUHH>2(1Pm7bTb1De+>;FhN)q)=8RG8^1r^e_ILXO!@5; z3ReQ*$f#Bt_CfNmI5ng#w~P(UwmV&ym~WYD9oUuZ+}fHFgwhh&p`kM08~6_05e4AB z4iJU4KuOCALCWp?9?Yu^*0}#FLd;0h-Y=9vjZf@t1(`Zswx$;F8gRgws1+hdN!r{%#xTJ3YF!d<^yK z*79+wm+x6pt*XABFd0MI`p{*I9nrU>k%ew&@QKUEY?jXe_c)ord;`p~ZKwnfdvWus z@>Y%wwkN~fClIJHACfc{!r!6V-*f1s=;$C8)OBLa1bg9~rTMTp6Jp7ItGoJeQm#Vm zZ`fTWn#7lREU)PErs`T%hw^pU`3l)ij?%2=CE0*|IzeHh3~)~iqn0mL6y4Tqgl1TD z+!~DrIl^0I`(TDH;3PlmVHL$n1vtG*6qY z`)TBKhEZiUzsu!`Cmz;PeJM-RUR2Gq2|E0>xl;UNEpJq9_p!9`z>Lx^#QXK^$(4Ll!ylBa_C zN-!HuCaAz*(*ojeq)A3l7dVRI9bjK=Be`Bs4w*D5leJk=3-w?vF)dfJ!yD9D5>Cn2t?K)a>iZPj60`5Ru0i`1&hb*}lTr;ScpJp&CA<&g&y9qjSX;J&8WN^hJu zg9D{lW}~cOTDFpd%(S?kpIbe>;-mIymlcuG`Q%Rn$JC{)jCIs!l+}Qe1T>{T zG0>Gt-$VSm{}xm9%Z73Yz!*#lNcSitsMV#iIIBSV6;WqLOQ?DU<#x-yLw&TO?*e3s zM@oeM+}V-xPPY52#i2Y6b=H+=9mJH84WfpmZ;3UPGAkP!bGZ z=GfW98h2;aGrtk9w7FI|I;*6{Vamn8W2;TD8!-qEL9pV`r3hBeW2>s#=u8$^=;Un^ zURO5Ih;1+AJRCiXp%zdhq2t|hdrT{|U$Tkf{oZ&ywpvrCD64V zC+xf6Qs_hojyi2d8|Vh>?>e=2{Tb;t4a*l{_Ixv#_ejUO6t1cQZtF|u;L%mikhJ#( z=*K)>b#C4?>y`W%x&2`W_%Nb=5IlUsDxQ)5ps#~?TUltM_!oJ8Vsi=vtV&p`c(Q&te=-+ZT(?Q3!@ZuEa3>f|=TivA`vnjOU;!1lu+* zY-v&4JTU5x4%9dQzK&PiZK${FcJcNqzP*Y+#Z_F@JrDD1CGX$YGjQ2CR)_+wpOq;? zOX?&m#v(Z4W$qJ-bNp)bg1mcn*!EqCWrceoV6x&A5uSJY{$V@h!zR8U1m!9DISkv~ zL=t0RooLwDfNJemZ41}+h-12>2kUF=nm)%JUAUr?8@g=3IMtQIcw29B+r`80gztBr zakY^^Q|sCgtGxVznLTj=^Jo%3g{nmV`nK zUq`bnW2!q$b?2eHD#6%clxCd$*Z=sRY%f180NCR|Y+?9@F$Cd{eS%ZOzs;bG@Y{&T zXV~uxp90g{PI1q9&ClzYAKhh6h?mGqz7#HV2k71f)`4*Di{pa`nToi*m2rM7*YysS zsnTgm`9xj2U5!3;2-7ZL>miINuG1+n7;}<Yi}p62c`o0q zSE6}PUn7y8DY;GRoG=8COy`)Jd=>8d<&{{|m!YEr&K3~_TyvuLm&{n-x);X!^wqi- z5_>|?#&19v&|vt4qYD`>9l^%f02-Rme3nT*=2o~l$|`vW759ju%zdT+bCSUjJ0H-i zbIuV$^ApRqn(r$At??R16HfNqfH1e`)+ar;jCj2iO!Ec^H4K_Xn6jk`HOv#nU&BA# z2XTe}2-&_XFizalCa`FvtFPz>og?tNf3S6VvBz~EQi}>itQsuIh*S4v!1@AG5;>Y7 zA&E@0o0cLFXCCHBPa5ku%r`gLN()lV+xg}MfWoEu${<|?PO?A_1R?5!8%6FcIA zWL9yk0nVnszqZJ!);oV^6l!5u@CuY+Y>y zs$|6Ns8^r?#UKu#{2ZjCbl{pS#zuAh@vFU;M&K&=sr;(mZL|OS@Ba@YZ4x^WguF6_ zR6AN#b>}@5Q(mw?-?L-qxbvFGhoAf~|554_mj*2t~4Vx^o@R zbq_xOL*>?OdbJ)J;DRtd>Qx}A9o`7wrL-9K5@E>?WJ{j`wAs@YkEE zXOFN=K3su|`r2-`kYSJ*lC}A^=+|m%f8KwoX8+kE+h1B*8AB9d=v0M>`)h9=q4Ti9 zsCJCH@rt>7Z)2<5Sj&EkTJHUL|Ia_ntLVj?iZ*R>;yDFava)H?tr4Jf`@vaz^XR|+ z$Nzlxh^_zc{{@XJC(5R=Slc%XVb|xC!>+HrQ04wVtFbls2F^*n`nW7+bDCD^QJSSS7>H%b#p<&- zNT#xuI)iwO$caEl0alWYdCnoMC7DfQh7?2%18`5r{$^YPI%)~*2HPEvOFl-?&4drr zB=556gDv>a1M;h!B^Sg3sWId~sPxB#i8pomg^>uL;4l=QSe=FRYu$4+P zzOFNL*?k>BZ~wt!MIV?&A1qe%fhzhUIS&_|BDqd$)`|DxypbPePA`6!@9L(Y04hXq|)>Kxk$|Q|8nM z9SMwKV2A=EusVFsEuh2~4Jc97RgdRoIymOT9^Q1T$m6^@PAk&>3R^JH&w#=01(U=B z7m{QbbvmeeB~OMI>@?+PaO)FXwGhV$8IAy%K#io$>PWLuQsSVXhr&{Tm?z6%0p!D^ z6n2o%n3|m>(i2t(sLP9@4VmXvg3=RG99ubp7T*kl!ZY1vSOSL zx`twi^k<-fAg-(A6{;+loaYUOW0eZkdXg7;I!H1Kyg(xet9&0WdG=_p%Z5pHd{iXm zP}C@Fgw$Yed=_?Sa}$-WVEuTZZhWEd<27u}YMDG!Qn}E-rt?0QU7XiB@2l%4WHt~g z3*ELc3x0pGUlvnd)-ukTFsZdM35-k*@IW$625Eg^XtD&G7p^Cm-zCg}koe@l5necy zPXXa@a5BTH1;kc(096jJ?A}C|4U!wGP8EWPB0io4R)_x^XY&+Z^R0sU^xvU~MhFvpDo36+; zXm>|O1qv)_aio}(>b3os9rk0F{TNRC8Pe=;O4u%Hjnj!D?QlpZrzbF=toc`w zukrYeU$oxe;lrn@%Ry2{b99Xv-5Umuz{|kYE(THiDd1_B15LXGSX$M2cRj5FAgy!r z@pAG!IpS(^t*r;Ccxb6#u*J4u0d>u9Z2PXg2;p;=t&xCot&3gK`TuE$ZFkw4*dfmP z#T=Vh;~Kl*Nf|7D*C_AqF%V%W(15a-&ZyX==&aVL7^Jw3*<(^ov((H3`nI*rwa&Zm-z&PDUH?nT`D>n3 zxOt6Nh{5aqld`t4nK}B7t4O{@@N#znun2QW_hIdAev%hwISVchUK; zToPr1bb9R863PB4EE491(sg2th}WW04;a#dHxO3^EyU=LR)zLU4vGS_5tD!Ff@`np zV_pht|M)olEaxydN|@?(#O38guC?dI8557bcxGv$zV@>4Gpi-=5-c{r8(5ZeIwCVV zk`A~5+{?y$f{6!vOcZLWXnV<7a$yO@91L0dX&=s?Ujs^d0uLdJoP}Zf^u+gW2Kg+i?w&A@Ci;9^!;8J1(DC@PyY$`)T*QGaZpN#Z~mGZ}9$7;CSXwyY)3sWu;`V?j$2v7bz zscNwTAZXgTN2`P#$2?&Zuoq~lxF>qjWRhj~)-?vZObv!j*o)*mS_AaVF4|z<6|kf> zR+k>Jt~n~*&@gnpZgo8}SHr(~k_-kt!(*m*S{b;>tM2BEw+;0wCid^Q2gSb&N_ zF7JgP&1ep*cvB{Ml^}AJRg<<~;dwDhbErxg^?DsQYBh{|o3ib&T^dF+8?f167pR^> z;>+i^?S-@{!G4(pf2#2B%k^oZnlE)NT16MP9j4;?X59}AX`@R`Fs@(da<-w`d~;ec zr(%zp3sX4lSo`AoX7;>qw1i?Vw6=kh09}^6ZHr%9ohP7SmAil(fE1JDSNqwQ#pWja zefRm^lifE@0dXW@Fa$jqms7-Tcqrlt1xSY%5P(Vms5@bL0=NN`XT?#L!n;|(W|}gY7c+p*7ow3+foLDhBLHak&xXqpewZVK%_Yi(`{o}Rm#tmw zm&RFCR&QP|9|%E=*Z~H0ASORFx+Wq*-~iqXOo^`no?7+-elts~}*_bHaNPZ6@PY9?7iJ?th!Ally zZQ&~EKx<++8>j|>;$8}zI75uO{e8zm*Gz{XC>Wt*BGyn%(-S}$8AgUI6uJ@H45dn0mqq(LVq8lZ ziynJuG)d0n`cyg3zZ;IP`e22XNnatrs&(nz6j%$+o!zysv(vPifeHfV z`>3do8`==J8r_)bgnzCJEsExP?RVMbUCEYv3t9wN_nS>xa^q2{5z+Vd)LfNQQ$GuO zvpmVN0^D;T{$*8HHz?wz69XN*dGmsa{(u~WgSQCC^U_=?S|~zL!jAc@1U>uUArvBq zWL>hHWxT5rV6b>ekAl2l#aYhF>NuUUIvKMQe!(V5Jvg?5S%UA4z&NScZdDZnwAv*y z-|A6kj}P_*a-6idF*NuB0anMozg&G!$m$>g;$T%5BU17!6j@b<>W}1Kg#hm;@>dh} zRLt<3Wc(XPq>698iKgDHIGcv;ug;fM!=uW5NbqX<0Y z|7hoWj9ZRUq_bnJBO!YQgMy}5qlmZW(d@3w;2&GR;NIQ^Fo2Uefa#G%hw(~ba}>vEqWC_DX!K}I^BMf7cMXY2|#)v znpqXP^S==8tWL(`)n?7?AOf0rpF@+l`3T2f7sz!;ua-*jZ*?-R0Q;Z9jRC7S21f*n z0`447^uC4IxI@e0Me1%bTv>8jq(er>Xb+bR@-_-17{_)Y=8Yz0Nt|0lWo_6tyMZ|8 zcD^DJ0&W`rl~!tsb`%0D@LZt&xA-TUB|}t>tsrMY)h!wVU6#9M9)udXGy@Xq+m*PF zK!q{Z!yNoM=x4uD|1nF-nwL^gjFAL|Hzi&!Hz>w20^YNAj3p?*#;^-rR?Uu- z-8VwO!qjyf)ux8c>yE?VZ+>zVG<}R1QNAaSTVySdK^G& zv`H>5R9G>try#n7eT(;Si_x)h*9^og zursA~*1gi`;f?PABf+kHddhPZ@g%f}*tf<=Z-&=jxLO;4b(ma;Q=EOrwukIHHEAv# z-?HzwHtv1@XS6di{qH2cxW7l$UQ`(5p?zqBb*Q~(46#vAy}@ zoutde(Ee0w3cF*m#bk73?gF{$9;H>*sy%5Kex>%Xl6LLk8Dup#_poWG*A$)L#6rZv zZyV3<$lf6tNmE-UF3jZy%);DhXh~l)YPm);wW#Mwl4cjL<(`>WA=_jIav$7i?pA>u z-~VubV{3E!E(n#HC~)sK578uA29O)^L5mQjvm?a~+2AIT@&fEb(-t^UjnVK^BPGRR zi4~<}UG{lVoIu!GdO}LrMl~8GpJvGbAgIRte0}bUvTJ)XqfjmYx3s_hZmaj;{db)w zYhCs)Ylny17*+}nhc0eS8bR$-DDxuWi#)6$K$5s~Rx0 z1B7SC@C;HYm`4ZF~aj5XKd!hoC@jXDQbdF zp(zdAvW9w7Qc_G|<<9aH!u)(zuh7rKq==)p%>|LB-py^9jkJR;Z+EvrTh@v1wi4$= zqSw@#q5KXduqhVXJXAsfd?? z#p3Hn66U0sjXBd#CCrbFl+jE?h}$1H!xmgW5gMJs{`C8liXylCy4$N;e*N%Y ze_yA(>;W7v+O0#Yt1I?P|KJr9gp0VUM}TxW;8lekVMnvU33$)tLslJw6`|!#iRdQ6 z-%3fnpFJYmJ(R==2;sWR_HqHe@{DNp=&tD%vW$@>} z=|7**pCM{ZVjC%MXn66iteIO)!b7Tgc=pJ!Dv<-B6cxI5jlFKeE2eo4hUV_j`pAl& z*^b+U;QdrPAu+hq5ycHxb;NZ={qQHRW4||D=at5i%8f-4)Z{v&$K7mDeHD%}>bI)= z^E0=%&MYg#oPwKEnvZ+aB1;G0(K4B4X#y^jv9N6ecFY1NeLZcO34c)_ScICZAAx+MdiSgll(|mMNQGkkC#^hMP!T9b`x5(&~ z??U*2D=LL^g1-*%*bKyyQjAeD?(6d;IFK;HJ_NLkQI(uX5hJA8fTL9I>Sw!TrYZZ2L$kr#Py<|GgF4zf(q@49x7Yt6>VgzQnX+B2mYJ&sU zqlVPy7r(dT3AqAQg@$9V(x=5vXn;&e6{~e`-Px1Zb*ra! zLkl7dwC${?BKOvV$IYtR7xRyHNV`@iX?;1_u~#GB(F(*m*s(_E=tke@aD`##XpiL8 z;V6G%tpukx8Jwks6!jBAv^eM0a)4QO;n+mCN&$&R#RYFPnGw7iI|9ABc?=0|>jrb< z#ncFZ)T@o4BdhJS2PU|NA%;o#@_hBAd-nELz&AU*liM0N1UAa@4IP993Pnv(SFz3K zbvkH5i6ZwFY#w@Ah zV_mUo*OJ}JCx;Bm3+r<)e_NsBqOB`8K8H{NWs2BlDS-2z_aB#hnAY@XQHjXh=Y7c) zJuY%_=z{?$rBrn>k*<^Smux^TQ~3MoIb6!{{-sEdr$q|u&-_tUGg*@~5m3E&F6f89 zUrix$oA|Mxly%NaqI`Ec%~C)ZbiPY+_i3mFA_LDd*`EB>h}U4p2|w>k1y3ngTr9!@cZ@N=D~hP;hfpGH~Lf<;x@R(#l6T7d~JihftXl$OS80+t`{H-D_D_d z7c9*srdl?e%IJ%L zf?3tK^H*wj1ecYKOjZF{87Mby2t=8SsD!5#C?T9E6qcPn&R%nPrUArd1nv=U8H6`W z{v84^g4Gh(86~xZqA@YcGJeXlRlyqjJa+om01Xxg_CnmRRXNbVPIRx^BYky`bmWd# z`$RXzgK7gI-LTp5EWVWv29H;HOg(M&?C)x7Pm<^!|3wkvsec$!v4c`%!Tatft~ z{50ifZC3N#I^ydRt^6_o@`a4RwTM{hqAnLpvC?&uU42z283!D4em+H8rXe4sm~3sS zvdH`VTo#3vx7Y)=&Aw&dn)wnq0QwWLr;=G+KC^-iec^7nSe{1ilU z#36OjiMV1DUXef$2zWKCv!Xa*e3GP@Ou{D=OY2HUzRCa>sOmDhTQ-NhOeIj~ECZ1` zKL<>f3IVQA{FF{GZZI%pRh`rvN4P7G$w4wrj?xU!mcXEfMx;!u6ILIWygDwjVTI1( zBO+jPkeu?QX8(VC@3I`nm2C;m?^hgCUS$Hz@BqPw9>}XqgFuRj%NGQY(#(C7AyH*D>Ol>v&FYr*HS0-QxAmZBRfGP6`zQ4U`3Y@n?|mNb;eiN%6vY%h z2Pq=_b)Ng|$J%QrI-OLm_27R=bUZUy^U)rA zE}hU&r7q6Mg?W*3g^1IZm3i7z7t?q+1@c}!{4ydJ=ZVqzaQfKH0M)XUy{z9}Cxmt@ zctpXhjRmcyIvr)>G4DPsLENM+viyt_(sjWH&A7rfG>rzf=jTHwSiU%VlEfeq(!)nn z965!ICil9a4b5u?Njh`G$Uw@ak#=zFXmQyCDx%})lo}YEY;@LQUf}VQ%=TVGzSyG2 z-kHk|;$R?7N&H4w1jD#oL^GZ0iOKnM_Sc^JuF6W?b3fGhVTG*x97N-+_gQn4l21XOqPoy7s z9JbolNpIzp_HeE=hjY7DY}ET=NI>mandG*tCQdur5HYrt+XZtyJOh?CCdjUt4HARG z+9XAE>0b~uzs%HdYKCWa)g-2+9qvI|5-i&iZVG zrqJ-}MQrYrLn{o7>8pDg@OdECLL8`!$FYqplC&rB%1UxiIdWrOx;=F&kR15z&(Mur zU#JT+m}c1-&8d4>?H?T$>Mwxi0I~?W{%}X~da92x59>J2#e+9QFAI!f>gT1$f~u{X z^!bsA2#`6?;TPg}sEJ8sEAUcBQ71LlNdj`gKI7L+X#&TA8n9wu=e)1JrDn)!>AJat z0`jRzu-NEanp8Q&E~GQwwqmi(^cet)cIhrJ5Yi}Sa~`~@3Epj6z~8m)O5K_5o0gkl zJdbg*yjkOxR;p_pO$Ft7g7KDbm+`||L>ih5Jt`s5R6x%f>mf+j4#!G|9dpf@YZNKw zkTB>|*u2uk*$%cCE|`&u)1ri~2EsQp$u$$fWeSo0#2#%~j=O#D(lpE6D7v=PhK{Q8_?3uS$0C9Vhl)HZ+ka6S(O_u{Yj*P_9>x$Gr2dHJQ0sZ2 zE?{mIXYqV)Mtx|hFVaVu9;roEL8VE|Iiddf;0aX`Jd`B$J=#hii#}PU_m+c2DZ$|jf*H@q<2vtfAuSM5-vl0 zihQc1yx@+d%N5kwsfqJ&igZ;@p^Hn!Hqtt#MsXX8MNyiW97C3Qr(B4IYyE!Io@nWO z+Ed3>s!oFtik?rcO2ksho_mOSlb&~41VpYc<56*nPK{&ij*ZQ+UhP=7)@Dyi#X`%T z$0FX~0~IZg4hC9~lFDI+dAG0b7YNnI#kBTjr=q4<=;w7+k$)O5=cmi50Pt z5Dr(-R|k4ds#MrYtfOA-M(jjxPgCoJ(?uf4G+4pl4Rhm%Y-tR62yuM515y@=+y8br zZ}rsyC(SNu?ZgJJ3f$Co8M=ubD13?&*Gp*#q%_;#SXWt92JP#qSzJ(^Vd|3qv({SL zxGBV8Ix)FQ;`EFW7&^6|Z44F76c3~A+HI7|BMWrN84z{_cYl@WNxgrZ6gADN1S&Rt zEiDkGhbd)-T6XV()Dze1EMbwVSx$Jn+1kPvaXQK_R`%L8A)Qd2polW98hvH4rpr>p z)MGJI%jLr93ISm=RFZ`qk~pAT+g`Bn!d*g;p`Oy0t}uI-opZa3N!&1@ z3`;ymk}TU@CdhW=2(G@Ogq46_ZrtF5KXiF)8i#^h~(u%2er3x zLeu5#C`1$h-B2OowSoaN5bBo5R}`OyQpD(kPgGTZUc?(h0R8b{IJUO{3!D7ss zp$YWD`UiivQuUR_z z2*$;Z9v;J@CuTWZjywqD4ufq)#D$c0Ru>|zen<(qHi8U{*v4{~xf=FY?*ICx^MqFxK z+s&1&v|3q4U?9cY(r%&7bU9D5GKmK}h0%j7Pt|#>Wy_3=3XRwLu5SA*j?O9#HZ&Y% zDOQiTq z)i)-G=0nn_X$t~t%DqY!*5Jm*7?CZ95E^_kRxXIt7{>|Jg}A_KhRYRi`QGH2DyRer z9GRagGtOIwj1f-zk(skae8pD#NxXQAeXhr#Oi)LB#UMm}yCj$VFe> z$H2)W)HrC>Nt~h+^xc}DpJ$a6AUbpD;c{wb_U?KJKtqj$^2YMeynYr#e{_@kSWzHE&oSTiZV*s~1m-7?x+5S0Fnxse;;@&Eg?^8QI7X zRxKXJjD{u6pC0rz#v#JkDt|gR>Hgu`Xxr}1cOGs#RCdI;Fti=Bt3}&rk=r4AE1@^s zm_{)&DT+v^qX^TZiPo>^&zOJ=ALS4nj&x`r;vc`jMq6Z+N{ogUV~cy|W)4#^o$%|G z$@2`DK!Q`NK@}$>Bp=UVpk!6y&Ymt@*M;l4a9tO!>%w(ixULJ=b>X@$T=xNn>qG+) zb}Jrd7P47Uih$)>6$srGef0>VL=h`%ONiar67TD)do~0I`OrM$y^IwNL$u^};qRh( z500LTU_?z)o%pj`EKj^*9vW6c{YQj|R`j;geItZo{RTuz%_3a2H?7=lPVt3!H#!+_4MHR3GaS;4D_3UQ#a)jIA!&; zL{G3KU!-!NV5RdSsYiABHD9t0Q?5tsFaP z(fKSQO_;N{r7evRGquVsI`Wa0>YK-EOeyrNNy{E#4}2LlY&L2kX30%V)Vd<1Q96!j z9dM(3S$R?@<7k9xtWgQ+Yn2`yN3?5L2x7nKJTBm7t;@QHM~4y4d}CJ{36>dSW8F$G zKo(2;fH%lK_8Im(2@F}Sq`OxIQ$-d=Zj}u5JuHGI^#oCQ@kcAXE2`57%hduGJQK60 z=d1Z}>NkaS&0mQ85HFeft?WenTT+%@d^DMt>Q1I^-rc>e4pW>?lO!AHL_Omse6)=Z zP_w)g{bGr0w%Nm)w`O;b-=^-{H{ddfz&YJOYm}$wl~gtd2BLHmczQw0qR*Nj9XfQQ(Xt`q&Z`qH*1 z070yfg{!+FThpdTe9@kw(X;6hU$i7)aHKh>QdHdi9{n>|ATbuh4r?siw2GOOlb5D! z7c;^I&(4W4bnAsS2h1UQgjc!zvis02aXV1A6tZFxzURPA!)61uVg~D4DaXJOeP=}< z#?Wx7MHV+w+dEJaC9{`?;#*SI=oXHY%x_Hj-a{uyRf8+&u^vtlTX_Um zG5OCRr|8UN?a?DjdKfZ9f7VYY?Tx{L=s!ilyKH}upi%_C81RxO0w8j^2rY_sV3 z+{pua8*K*OO@AQ4Vf1W=D3J^da(Ofh5In4IkLd3E>3N)Ibjs45b3%mBch51C=R4#> zAS)jChlE-|t7_`JcargT9py2C*R*o}z%lm&D2VecPD=#ZS!jC+@BFBM#AHLm&>j-0 z5$2PtjVLdC94>?oxLbSbvA>u8i8-&wHh}lqWyB5NePuDY;=Irk9jAV>kB$$Y9&_8( z)+NWtCzl)}K4II*QaK|qZs*W_XjW5T7(RwK_M)8n?caLE9~$;Drs~2#%OpR&6?uqt zQ$TlF-txxhlVldZQpGeLm+nOzv2Q%f0u&G0Nw~$D5FCwAh>m%s9Z0=sUgLB;Mr9`9 z7SZQuQF=%fy&6Iix#AS$61MJQ3eP}pig}hoaYR@LdYhVO6mrsu++TxN^%X(kAT#-N z;^;Uv#hzZjSGzY~Sw{o^R$q#@_tev{Vs*VJyjzO5`@1rXC)J=R% zw{?5sHjT-Z6P`^_a+49o5)$L3jg4+X6%l-j2oHXSxHIhX7x06h0zXa`hC;SBKa5om zKaj(vqC2;+aWSIz(@C5fLw@T+s_gwDJsj6Zkz_<%%=3&={WExrk_GiS2xqj<(Fx`j z4o9{E1yu;8d2BB1I>n#F!9+a`nt8h>|BmCyv@GK9iE{XG?4_UaHwjdOmbRCbTseu? zcG%<=wE-vx|6tG-oO+JF>j0ulPt1$-z)o~c#1c^wbR{?@8R&ok#ilOQ*3q-)#kRWe z@}65kV9dE*M7oF;Srtuq^Dw%Sg@|1zn9KbQTmVakY)ozedH~*hb`6j+WyxCTaAo5a z$5@%`m`c2}G3^?_L4zC%AxqUakE3Z;z|R+_cKyN~f`_e3$!)qjdxCT%JS%}6+4Vfn zvoQy0bmH6}>^LNOdcO&F6fsV!`2Hc&$bcfzi`^jf-%z!!VDt_phFYkt7BzSvLZ&A> z>5L-=!gIMKj?=x5Ue=O3Z$TeK|Kj$59D)Ze{y|6-Q9zK7OrCU z3g5U5y+fGx80QlW<{UU*fmmTf z12Kp7#7j0rFo?NY0FWe2MmL-SX$y#Qa#*NZsF|M6scF_P1Q!)83_${#l>CFZ&{t0Y z*Mpv6)`RtJe1W7qRtBbPH9G&Ng5|#l7+wITtnsp6jpB{Co-TQMJ$6^)KEM$qn3>Hq zekJ4<%`%-G>}Ga(OF^h_EiCslwfo6ChUHS@?La6RiJyW0#*QWXb0wdERCYQ{(zwjX zuIKdCX*_2TE*~h2%xz4=M9(`kZHK1q(6k+zwnNi)Xxa`<+o5SYH0_6ortQdYep%!< zHH)g(Vv0d&V~vSv)~z-mDmM8vy+vV-Ob_Z@fmq~EM9xBquuH{RWG|lUoWc+h#c^2Q zp><>-iTl#f#~#EDjF|_Pwz2K_{=N;m9TyyH8&7s+J0r^tj=KMf9f0+_gY9W;KddN< zC_&JWz8#R>d`0uvYByiMLp&qx3&EQvtUb#b;2_V+=N$8a%qsh#E@b%jkV9a zMG~;$Se%(-Bw4zdcz*=H);c*H4im`Jig6SyLH)s%pX{}MAub@VNqWbrmDGN;mJrPL z^`UxXC02hEgv)jJmODy=4b9dv>q{Jh;`4;0<0vlBs0tg)4NBc{Kz@KEyHMExwofq7 zwJ>Zf>JPRriF5W%i}oc?I2AiC!pKuAF;HN?)X9OkeKi9nSg%4BgoDRz+nOl^zK|?Q zvWuviTgsp&1yBIRVwx^+-riZKF2k^DK#NhOTe`)jKD1$E-kI#IcJwb`i%e;@CwT zyNF{KaqJ?FUBvN&iZ}*D6d`?&1P$SadAyRoXAN!7MmbV)P(}?yK@MoH7qHZhC8B#5 zr^NE8#jlzgLsiB;02-(c%n@%hcC6T6$s@Em0g#^0^XweXEk5;np^6VZ)Rx1ur=+cu z=QPmwHF$bCi_6N1Wmzjwvw*5awyE10~Otkc)7!TZc>2k|gNcIf8T=eme#@UBL) z>+~Id0;6C#p}0qG8rQ827hUM0v=@;&A5p$s6x?c^RJduThr=k~fr-wG;8uGqOJ5_2 zOhhauT7tO8*c!E5TVB6z9fq_atubAT9H;5R4K6rH3=-j0+DKstn13bPv0*n_;wKWE zvnna$Irz76zhu6;fM$=x1s|qly}Hz9bma^@3O347u#wKzRWqP_Y!?oacPWWvDe3sl zUFtD_6%90U= z=JphAgvgv5g!Va*<}9&hSsE<-zB-ZVSjv?gET|9kDDrF*Bs@U9mPJot5bLEK#|ETL zas-O;GuI1B+}v37}T9P*yyCSW}6M{ z$T5m@*9bp}{|+ljS&h{u1)0XY%7^6dvj;b{3j*?yU#I>_!+aA9{x@^sUmGFqqm&L*o#mikw%REaq z%9p+SZu4b%B!2#cSsp3!68J>f+Bjd5Dl5Ys$#8eYXS(2Z7rgF**In?s3to4@>n?cR z1+PEM;B}WS`%6lfZRE+y!5&hKYec4&lRZUiX_#rkr}IAKr`Epcd=dyZ82E5=-=|)f zb|C(~A#s({!oyA)XGxr~Vn=#Nd!j3y?DY`px-{2d&G1+j*BlcYVrtBwL@Ze&K=^ee zP-XNi2#oj~UKeBz`xYhU+$6S%ZMm<$;8esJhtLD3+IK9-+`}*l`#XcJb>TBpTXJD* z%j=5yuZ@o*^h=_#JvUW4*qZRFXM=cBp$@COQw*QwOjq8>93OHkFZN%lHS>7knGm|}BqoF31>21fqF7*jD zGeE7ULVou$3(Ka<@9Y9wA9i4?9>frc69U}HU zamdSi*2KPU-&DjD`z~W&wf@?%3W4M@WLFD^$@<1Zek+kN+?YmjQBCDxjiW4d(I|rH; zc0?Ca>q2T>NUaO0bs@Dbq}GMhx{z8IQv2XSYESdw)DYK*)vm6otn^V4j00ir1a*>A z^ahvVsJ% zPODcd#y#)z5r={q)di8$l4w#I(`##HI&0po4Y%<&sX<7&D$u1{@9_z}YE;oti$++z z%#}r_;>&Vy&GfvG_^2Cmu^8jD%eE z>VaVlb-GZ3oa*mS5mzQBsZK}DQ>U-qWjr@pDo@GLTrLV*kI~XMd}T#=G)wi(V>Q+@ zERMiOApY?(Y8X^1Qm1bC!c;tFuwD0U8$o=@;XE2QvP;OAr2#uQeju?i3^`WOH^{0C z6Q?3|3gt0!%5X%>I{f%BsfyC%FRMJ}{b^Ntr@TQ2XHQ{?`sQ$7M(PxPJe&MS!%Yx?nzwCy&@R;8d!vl6L|&~gIpa^zA*9ra0F*Qp9<`>dZA zDv4(?0>+WA3@kV5QvLq3n;+Mv0%i6wlGdH#t4Z zRbjb(yuMH(HrPRUha91FT_Va;qepp`%{CmhvSG2~O|l*O?9TE1{d!vAovOw_&x7t?yq;3@@B7XB0w^~vfm zc|~mBfiFhNk9)TL4ad*(i$|6Uet8(#(`$~C>$3N|<{Uo7nKyuUS9PK5I;gYaHDCn^baj&VF+uFr3 zw*OUX6o1HNiLG%VNzg}$PBF#TfuS^Cu|DJ4i9s;Nkfa(eh6%5Zk%5~Gg4ql;!oEQ` zmVI~gcy4fz^lH31OI+rynb@DJ-FFK{v0Zkiw;d*RfG%GHgJK=#9SWsGp>!ye4u#U8 zP&yP!heGL4C>;u=L!opiln#aRi$I}Rv&k8VZ739r5D8%@&b<0Ha=*cEOv>64=zogX%WV|4 zE~gYWe~@Pv;Izju5ECijM7VHbbV0rW>&R7GF?1UUVhEaTis$E9QA94nElXVLJgZXY zAV;89Juw&Fa~oj)_{cD$KhQTzJ)1K+0SBc;DA>T;AFhMqut(B5gbmB_BXL%eH%|km z0$D}MX~WOi4%s4;7!EVN+7TKc8{!ni4295|n~~Z=HH2VS_GCtSGKmD1IcCh49u6_e z@_PFU-0)|bI72Zrsl~E%4>y2CAwfl!8iTv!P&Okt4cTGF4k2>Q*q(tivT-PiLl?3;C!~mQkfaM`>-G)6spK(@z7g2{TJzhPKK3(7P;6E<|`XpP#;#9 zeHTe|QC?{AJFUVk0X5g;`nB*lT60HBWe4bKgf4?Z4z>gYV2SYrHYS6EZAY*j=ymr` zj#W$x3hi{)U2y_gdw2VR{vQYthOFrkR9~q!g`FM5vgUa<$@NTXX|9F)7_n;*Q;pe=W!8afvg@qrdLoy{qemIdu(~DD|5TX)dzSd#yN2+2{+{U;=Mt@ z5s|G?xZKI15YsXOF6(UfhTg z0i0TmY;-pUQO6Dh*nt2$5MT!ayfz3h4Ax!>16(KIH^2g31t8NVx@)i*C!Bu*lpy!0 z0||B@!E1m7122~%FBiNMRj!ANmId$h6_pLVEl^wNPzxMV5J5t?yhE^4ha9{ja`5X) z=cUP$#Rn*-Y_|ipR!shR*nRMX1c6$!p4Nf`YdR)r?d?M!GtvD zSyIt=HUSXs_U`mP?d{%tmpDS-d8fwPAq#BF4ocWT2|FlZ2PN#FgdLQygA#U7!VXH< zK?yr3VFxArkfDU$auRDX9$Is8kjJA5rJuF1BGZnQ!CC_KYy={-p%f_s;fz&hg?2E& z)iA&h8x!}AL6Db1@UD#~crz%&#%P4^+y>tidlztniw*r)yhUoiC`?h{<%|}=U(T0g zu{f9!wx zKe*fua#pX^{wSJeLuCYGRjAkMnE_&}%oh>kc*1KIi)8~i&;}>0fe@q`_B2c16wwiC zT8N}Zi;a*xNmOFaxIqlPzg6%S>_SaPHT0_hoWh%%&9GPiC3`=6$mrqw;cu^|a_Tzw*QA5TQPWKdn)?2pCB3 zZ{4>i-5W!%Xs1h+KCGjF&cAVM0GnBb&kB)w^{1mjZZuVgS|!}Bg5!FhC8wNHPB)^X zatYk!pXk{$5@s*AfxomG;PoP<`ET_<3GAZ{e?=gdZ%NxH9O4uqnVBw!Q|zT>%-0{( zRy;B~*={^Xw!E;!!4C*`oB4yyl|h$> zJ10l32TKZs14_$yH;_mtq`rz97w+sAEZxIdl;7f%#nE zrUG~oH&KKu+~h0tl7UVjG8tpWkZAbIUd=VZG8h2ZGM7=v%-1G_-xA7vE$nP9d)|{Q zjo`t7_DOJU;pQXhAJS9ST)%RBdw-wfu?v%6{IZZK6F$r#mtpecfd^SJ%L;YxOKTaz zNc5NG>{DM>#m;@akv@mGVKLVTq_{f)1C)kBP7dLpbErQ^zB1Qw%JnQa9R6i?&*gEf z<2sKRs~J$U-apq#Mde^&4YwT00`IJ$UM(nGvv*;JhU?g-F&wpm9fw(ps)$ldv<2=M z30|%a2E>Q8ws+9R4%&DPXruS3IA0^A-!vO#Nk)5W9H$oU)4I?-6=Ka> zRR=$I0LM23IDTu)S+Y1GQ=e_5>mVFk-m)6v$TweBt1|#PvKedZ7ckhHv*&7os%3;v zJBp`Ri+%izDtYd{JJ4f&INC~icF@NT`q)7qJLqEvee9r*9rUq-K6cQ@4*J+ZA3Nw{ z2YtkP5c^4N#+jbaeFXhIWKmp6mnhoHWl)(8O8MR}D*ohUG2a*3#^S7sLUrYIPi=y6 z+ISdjsJ>~a*j|)*EEFmOgb>HNN=i}UT_5Lp28o#OsWaGLg8R{yB~RUhadH3EJjrsC z)0g6udiHWm^nldrd2YrD+?pag>JRM*|DZ|YNh~dF*gSMFlz;~XOntvoDS0I0bZi86 zRPQG3*l-ZUJKujlIWvDI04?eB?NBgY+dQ)58FXhjtR5?mTB^*FM^Wv|alR>d4~@vp z6j8l%v7Nn2u!{1@27}v}4_ieE;Tk5BoYj+1EDRQbuv$excSw?QEF_jd?b4F?r&~8a zcD~dQ=W9p>YppPA5knjd?!>hZh^TGnz&w6H7|rNgs{XiNjpFj{RhFevj%|QKt}$yl z<@>n775V6HW2p?e|2Snv`5I)+X5+gc)> z!lH z2p1&kZM%;N;*6fIANO_rfS|;JoMN}aS`_&50J1-4wOV7fW81j>d;h`%UDULh-vLmg zOLZC-FWngJ!OK(N%z?*;#~Hh|n!{sYY?<-?I@oTbF5Nmox&fo`9qa}6J3Hn)izj$sV&BDOXLf;>(GiOHc-gEUGJa`~Z;n2U*57?@4e&~c&f?PHxsDri?^^y05S3!k9C$~N7i|( z3B%1S%Pn%1WgT_KzmAc#OJb3Pg3Ckl;_xkVinpyZpCAZMG~SB}xiMj+Qu-!;h9 z1~|g9FEkuiL$$sYAS(k@{UK$Msy)G=`Yjl29Z3Ub9*A0^EoBXpNyd>DM!k0U)DEB8 z;Zr+&YKKql@Tna>wZo@&_|y)c+Tm0GuJNgD$W&Kulj356p1d5q2zeRW=XC_6^}oLX z$aAxBQw`Wj(%~M1>j<}SkQ-_*Y^O~inbhp-P)MH2ALP9zg9>u20UYF-qSoutW`$uP z@UP$a(tecpIPuGb4Zl)Phz=F5T&l+g+ER)1u7i>`8`f;M#T`fu)H06^H%ahXHWE!Q z?g`D01XTmecy98cNlSQ$?Rwbl1Ej16NnA|Xn7EAP>XO=tWhRq0UbGIRqbwtP-3_H% z1};EKQHAq3FX2a@X~1tV;*DRpF0m?%c$B~*mBM#FchL}AFtM-hzhVdPC@vtjM?KO; z$V{V$1DTvvWt5E(E1x$zfP%~79H7Ie%{veh`H>)9cDdjdKt9OOYBT)3!(~IjM-%D&{I86xnMtTo!}M| z#&`P&r3>cKvEE1sc33dmDFP_cdJ4N?tM`r&firoGI1~(c3gcVH|H#Nqv_O2Qi~VIq zHJMNaXP#a1Pl&pRn~35}f)MbFdq4^yg(f*;;G2uWqKGUAbC8`I_1Vpj!y9|ccYJ<# z>5fr&7cB?0CW4fU@GoitDQ*s)1VT$QqR-(0S>Du>@&ZB!=Ol&f$#+xuut|G`Y`3s_ zer1J?bg9?j)R3Z2-m+CC)$CXvvyO#uw{F$})j2_7tRBWef;6yfT>wX>&Ik0l9B8BL zcYQ|&TZR_{JtL#u(qaO|v#|rT0NXWor||kAd%em{PXS9nci1(8#V1>BX^shWfScLP zuyCu_4$=|4*+psjds~BQ>tbn_meyMr%<6(wzr20xI#|)qjtQw_Lh2&TU8K2-G^YXmqB3S(A96{VSz z`vvZsBr%Cd(|J}DF$wO~d9SrFmUFx7f_y8JOd9qpbxZH5r%Ns|T*XEjmH}ysARVk? zh|FTjBcpXdUS3x$66KGi`rFkDjk$Ftvo3(1AcvX-ww3CUYnz)nq~ndVoRhp$_N7vw zoY&?E6(IN;buJZtF&eb7rU8iju*|DL5)akk5r}qRDf0EhQDW4S{b%GT#_?Nws7Up^ zm}X_6w(OY$r_9KZ%G1N9QNLHWZ>o`A6x;57GjxnzA zgfp9uWqYsV?rC`@DA{>i{-vtcS3 z)pI@IQH{S}F8ViEsB$qkd+cG35Cu`+JcjpgT9p*sk1^@=lj9(=baUj~AR9~eAT3)y zAT#LT)NIdoRA!}4)I1|sEFeZQlUCuNZ6qV*r*gO#R>ra?ykK8w2g5h~y;q8dEqA-> zVvP3+_^f1F->Bp#^DtbZMXf5jc*(rlnw@x_`T}hqq2X{O-o(3T@}`-N?0{*fGGh9oWNuC7x!OEAf<{HI@@qrLFt<|A?|4$fU-89BV>ZadJEJ9H;<-4{To4JV(02!5$^uBpwt(i! zSGo(61AXaZJsx9tLK7o+r%tn(P8N~V=(uH&YY4>J3XWV&xR}Rhh5#a?Jey1RemMq= zn-lNmk(CS6uI83-fG#J<_}l_q2X(ydDhxrZQehk8jkAs;2vlF2Jh^cStXcgtv>;eo z*Ywrfdo}t;?8n=B&yu0xv-2=?+NK3S^&n4FHdlB3F&&YT`DA3kTgJJ3T2wo@Aan<7w_Tr&md zsfPsa<4*jgfj)N0 zb34M1pa4ARs2X303!z3DT{3*6OHsj9UMJZN1xwyf{p5$awIQo#8Usr zaTD=-1Kjz0gKdq-n&au(0on1+?q(klpgADIAmfVI!aR&HpD0i>(8 zHEf+OKYh@byuvqFC^H^g=PkmnF2F9zwnY_eLUGkXbz0lot2vP^^pZFEOfT95vKkv* z2sc)*@ zzf$RikIg8qX70_$hU88KH#9FzGlBvR2q`%!sVq3a5!?2SfqongXZ`K&A4gVa3pGPJ z&T7PM^6pxFZUiVMhR5NL@nouAt8a83(+Wn*5rm%bVr42{ahVJkJvECbY+UVyK_`2w)@D*FdHbeM)+7Uw9^n{Nz6D!vbUOU?nw5I(1 zqYT&mCc2tcvl};_k#!|oF%Ar6nP$BHAAjKU>PLRWuWYqN{t>DbU%SzARs29|$&aB2 zCaSOHx>Z8Yw(|R}P!j&}&N%SC=ZGBx(HIkUIEW-~l2NTD?|3q(7?H>K}i=Hu}*E8oGVi z@3ZcSe!s6;{-1X^Egag?H*Wlp{wV*F7tvpKs~%sjOJVCh%jT^rlU0v!hT^l|JjSrf z1VWp6t)6++=CwPoUjz1x<-0S>oGh22t`F?%_CMNwrjGwWn;8Qq`W5|~^(*@4#{m~I z=*>KyvVDHE0{W8itdH%B^aqQWCHxrRUxQG2KqPco1z{Je(+upsU%OT84ESBaTY-on zLmxo!u|4z>H-r?>ZP!`2EZO2>g3E1I_%;^C4<{t3aHw743~4czniqZka9dZQf#_E^d#>-fp2;U|Zjp=>&;b13xeao_SUKEOe+_>>H zon&!3;l2^Cai}U|KzW-)`T}-N4GcTnXbNPMiRB%5wK!oZMA42D7WJhSgw%MFz4xecBSi5t$xcs5Zw$h~!h9d=Y$F1;7 zTX}kV+R(1-=3@QhD@qV!=Q#(A9R1Hl)|!rXmK!keUv2te)_LpjvBokRUB; z>h|5ejv@BFPp;`0V*mbfXg&;vSTCm5rM0evvaP3xZOJ1pn>McKBmj_G!!F>8h)Z&w zq)xfIJ}oS_y34cuCFa?_15#Kt%M-#j^u!uXrBw!@$9X%ECSFpCOiF4Q46myZ!dib{ zT0v>}z!_ri4XD}xnFLqK`l~&+mJ3#s#Q`|8%~jbt`TCK%_hnDvzmE@lFiK}xK|euW zOmc%OUnS;MPd#4Pe{Z`|WtJjgXaCQ(hy>hro07)fes}qQ_iUe~{-xA+aJ9C67T#Dl z5j>t&C+)c;A|hl#l1VkQ)I>bsc%O`SP-8>loWbiOuxUMOuwIkQMRGRcD%B0omaMFmVK+tvZH}T|GFaCm+-Pe z^A%m&vuTDuS|oAp$C$l`FP$k8o1#wTdKKdv-SY-GZ#0C^t76##uQPGh$zDT-L&y9| z#r=FfUmHJZBR#NT3VNWlc-Dj5JcM>R`>v;k@MSrHMH{o8q6(#oM3z^cm?a)?aKNe?x}{@W}8MpW63Hz6ECb zCHDZjSdKJiiZGM!o!OX3)$wGn)=GiTsAtVQ4nlgCPKu5?{#QTv-c(w}2@AkS&(%oo zDP2ZnXO9z2jtn+eOgfrpF@2g*lm-I)!mz_kdNC_$`)ew z4Ur~LIyC$sfZf`iA_bP4?P{{iE-h~c*9yOEeHRqiM$kUmsb*chQBPRP)kYohY)=&x zCH^(a$5KYECEq>eA77$6{Dm349B27Ux&4bTquBXpJ3gn$+O;} zhTb#O&Slw&w>5_T3B}NFyt^1W z_fx_f4Vsv1@aXa)>{xWW=z7PZ+r`$q*m@UR?_%p+Y`u%Ecd_*@w(erlpIxU`yzcnr6fIk8~IsLgX}_ zhz{K_MlNh!FRMIuMyxek_=HBU*_Bi3#NaKC&A64Xm)W7tV@tUbjZC7YmMb@>nj>c) zt@^G)mS&S_EF^}a2V&5J)TyCF8)@$!C>=OXj!&3$GQ;kFV9F4$XnZ^bxJIoRzOY{R!w!^rQ$Dq}4fbWfd5%W_`q?d;_G zqCbhtX*B?uu6(3F%w{_?t0U})z`-&)i_4wdjEfzV#42`XI!NQp zGKjEZXZ#B3rROH^m#@mx{u}ga1O~HgP7sx!xN9SGeyyGzj+Gof&yOF83yok7BIk%$ zR2t)A9C11pStK2m&h;G`4Eyk?!#KyPIdq-S)y#F3(lSn~fW<3^?niYYMWBe&kRrW7 zb};#U%}hfS*bm{UtrIi*#^j{IBSV@Ld1;4B#No3pF4XBv{{>{8ahkyt2>Pf z@P&*&Xi*Iz$Dz=K`mx+(XHgfZ9Zq|4t~qa=%Ti=|JEdFlzTuxriA0OWhlTTK zX?TUC2@`A5>vonhLpc%jvR2QqCYcLy`JvY7UNb~GmA9<=q6`st-gd11C7E<0Xlz-@ z>alfV(plcvD)s=czmgT6nVM!*E=Was8Fzr3CDFsLAJO5~(q){>(0?iJ z2jx47hhk&5&#AMH5#DBj621Z_Ni{clVW@sIBEl)cz@c1}vGIdy2WZCS$8{PE6*qhw z+|4mgiu3j?sc9heC5A%-<}}Yt|w_$K*?ewamAK) zQC1r2&=DRw+MUTB*Hu9PUipk_4)tm9s^CqpX={9^zSx)mHq z4Xn(b8dN24l5iedpc&y5X?4it@hqP*=`G#@ZMDHs#0!T(XBsgb;1#24E}%z?z{zLM zP0ah)E_2x#gV6WqythFG5~wt+GbTnASpsmQ6;{wQEH2m$C%9(O{(f+bv`}s5*R-9z zTfXM{@#9R3*J6{=VM_@x^Rag+o4YJ(N61GEvcNZf(broKKGnjfIoH8r^pDInZG)ZБ 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

+ZuQjJYIib-ITNHdWMXC_ENmM45O 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 z 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

9L{$WKm$<&9PR3j%+v7BFLZXXn2+_x4}y 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 z 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�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Б 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 Date: Wed, 17 Jun 2026 13:32:31 -0700 Subject: [PATCH 19/19] test(sre-agent): expect review-mode default for portal actionMode Align Pester assertions with the safer portal default (actionMode = review) while keeping CLI, recipe, and expected-config defaults at autonomous. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 index 736b363c4..4122e4d98 100644 --- a/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 +++ b/src/powershell/Tests/Unit/Templates.SreAgent.Deploy.Tests.ps1 @@ -959,7 +959,7 @@ exit 0 $resourcesBicep | Should -Not -Match 'resourceGroup\(\)\.id|deployment\(\)\.name' } - It 'defaults to read-only identity with autonomous reporting' { + It 'defaults to read-only identity with review-mode portal and autonomous recipe reporting' { $portalMainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/main.bicep') -Raw $cliMainBicep = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/infra/main.bicep') -Raw $createUiDef = Get-Content -Path (Join-Path $script:RepoRoot 'src/templates/sre-agent/createUiDefinition.json') -Raw | ConvertFrom-Json -Depth 100 @@ -969,7 +969,7 @@ exit 0 $portalMainBicep | Should -Match "param accessLevel string = 'Low'" $portalMainBicep | Should -Match 'param enableSubscriptionReaderRole bool = false' - $portalMainBicep | Should -Match "param actionMode string = 'autonomous'" + $portalMainBicep | Should -Match "param actionMode string = 'review'" $cliMainBicep | Should -Match "param accessLevel string = 'Low'" $cliMainBicep | Should -Match 'param enableSubscriptionReaderRole bool = false' @@ -991,7 +991,7 @@ exit 0 Where-Object { $_.name -eq 'configuration' } | Select-Object -First 1 -ExpandProperty elements | Where-Object { $_.name -eq 'actionMode' } - $actionModeControl.defaultValue | Should -Be 'autonomous' + $actionModeControl.defaultValue | Should -Be 'review' $deployScript | Should -Match 'ENABLE_SUBSCRIPTION_READER="false"'

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 z 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 aZcs}F1^@s6009620672v0KG{C0002qu>Iu# literal 0 HcmV?d00001 diff --git a/docs/deploy/sre-agent/latest/azuredeploy.json b/docs/deploy/sre-agent/latest/azuredeploy.json new file mode 100644 index 000000000..4b6a6d0eb --- /dev/null +++ b/docs/deploy/sre-agent/latest/azuredeploy.json @@ -0,0 +1,1119 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "2403415415579441400" + } + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "Resource group that holds the SRE Agent resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "defaultValue": "eastus2", + "allowedValues": [ + "australiaeast", + "canadacentral", + "eastus2", + "francecentral", + "koreacentral", + "swedencentral", + "uksouth" + ], + "metadata": { + "description": "Primary location for all resources." + } + }, + "targetResourceGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Resource groups the agent can observe or act on. The agent resource group is always included." + } + }, + "targetResourceGroupNames": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Comma-separated resource groups the agent can observe or act on. Used by the Azure portal form." + } + }, + "finopsHubKustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified FinOps Hub Kusto connector URI. Example: https://..kusto.windows.net/Hub" + } + }, + "finopsHubKustoClusterResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. FinOps Hub Azure Data Explorer cluster resource ID for Kusto viewer assignment." + } + }, + "accessLevel": { + "type": "string", + "defaultValue": "High", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "defaultValue": "autonomous", + "allowedValues": [ + "review", + "autonomous", + "readOnly" + ], + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "defaultValue": "Preview", + "allowedValues": [ + "Stable", + "Preview" + ], + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "defaultValue": "MicrosoftFoundry", + "allowedValues": [ + "MicrosoftFoundry", + "Anthropic" + ], + "metadata": { + "description": "Default SRE Agent model provider. MicrosoftFoundry maps to the Azure OpenAI provider in the SRE Agent portal." + } + }, + "defaultModelName": { + "type": "string", + "defaultValue": "Automatic", + "metadata": { + "description": "Default SRE Agent model name. Automatic lets SRE Agent route to the appropriate model within the selected provider." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "defaultValue": 10000, + "minValue": 1, + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "defaultValue": { + "EnableSandboxGroup": true, + "EnableWorkspaceTools": true + }, + "metadata": { + "description": "Agent experimental settings." + } + }, + "enableSubscriptionReaderRole": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Assign Reader on the deployment subscription to the agent managed identity." + } + }, + "recipePackageUri": { + "type": "string", + "defaultValue": "[uri(deployment().properties.templateLink.uri, 'sre-agent-recipe.zip')]", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package. Deploy-to-Azure links derive this from the template URI." + } + }, + "forceUpdateTag": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "Forces the recipe deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": { + "finops-toolkit": "sre-agent", + "source": "microsoft-finops-toolkit" + }, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "copy": [ + { + "name": "targetRgIds", + "count": "[length(variables('targetRgs'))]", + "input": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex('targetRgIds')])]" + } + ], + "rawTargetResourceGroups": "[split(replace(parameters('targetResourceGroupNames'), ' ', ''), ',')]", + "parsedTargetResourceGroups": "[filter(variables('rawTargetResourceGroups'), lambda('rgName', not(empty(lambdaVariables('rgName')))))]", + "targetRgs": "[union(createArray(parameters('resourceGroupName')), parameters('targetResourceGroups'), variables('parsedTargetResourceGroups'))]", + "agentResourceGroupId": "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "namingSeed": "[toLower(format('{0}|{1}|{2}', subscription().subscriptionId, variables('agentResourceGroupId'), parameters('agentName')))]", + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "hasKustoCluster": "[not(empty(parameters('finopsHubKustoClusterResourceId')))]", + "kustoClusterSubscriptionId": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[2], '')]", + "kustoClusterResourceGroupName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[4], '')]", + "kustoClusterName": "[if(variables('hasKustoCluster'), split(parameters('finopsHubKustoClusterResourceId'), '/')[8], '')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2024-03-01", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "condition": "[parameters('enableSubscriptionReaderRole')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(subscription().id, variables('namingSeed'), variables('readerRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('readerRoleId'))]", + "principalId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "resources-deployment", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "agentName": { + "value": "[parameters('agentName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "namingSeed": { + "value": "[variables('namingSeed')]" + }, + "targetResourceGroupIds": { + "value": "[variables('targetRgIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "11748842726639098374" + } + }, + "parameters": { + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "Location for all resources." + } + }, + "namingSeed": { + "type": "string", + "metadata": { + "description": "Deterministic naming seed built from subscription ID, agent resource group ID, and agent name." + } + }, + "targetResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs shown as managed resources in the SRE Agent." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "uniqueSuffix": "[uniqueString(parameters('namingSeed'))]", + "logAnalyticsName": "[format('law-{0}', variables('uniqueSuffix'))]", + "appInsightsName": "[format('appi-{0}', variables('uniqueSuffix'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "monitoring", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsName": { + "value": "[variables('logAnalyticsName')]" + }, + "appInsightsName": { + "value": "[variables('appInsightsName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "9164683275614055037" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources" + } + }, + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Log Analytics Workspace name" + } + }, + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Application Insights name" + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2023-09-01", + "name": "[parameters('logAnalyticsName')]", + "location": "[parameters('location')]", + "properties": { + "sku": { + "name": "PerGB2018" + }, + "retentionInDays": 30 + } + }, + { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('appInsightsName')]", + "location": "[parameters('location')]", + "kind": "web", + "properties": { + "Application_Type": "web", + "Request_Source": "IbizaAIExtension", + "WorkspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + ] + } + ], + "outputs": { + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "value": "[parameters('logAnalyticsName')]" + }, + "appInsightsId": { + "type": "string", + "value": "[resourceId('Microsoft.Insights/components', parameters('appInsightsName'))]" + }, + "appInsightsAppId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').AppId]" + }, + "appInsightsConnectionString": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Insights/components', parameters('appInsightsName')), '2020-02-02').ConnectionString]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "sre-agent", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "appInsightsAppId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsAppId.value]" + }, + "appInsightsConnectionString": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsConnectionString.value]" + }, + "appInsightsId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.appInsightsId.value]" + }, + "managedResourceGroupIds": { + "value": "[parameters('targetResourceGroupIds')]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + }, + "actionMode": { + "value": "[parameters('actionMode')]" + }, + "upgradeChannel": { + "value": "[parameters('upgradeChannel')]" + }, + "defaultModelProvider": { + "value": "[parameters('defaultModelProvider')]" + }, + "defaultModelName": { + "value": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": { + "value": "[parameters('monthlyAgentUnitLimit')]" + }, + "experimentalSettings": { + "value": "[parameters('experimentalSettings')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6562535881153200016" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "appInsightsAppId": { + "type": "string", + "metadata": { + "description": "Application Insights App ID." + } + }, + "appInsightsConnectionString": { + "type": "securestring", + "metadata": { + "description": "Application Insights connection string." + } + }, + "appInsightsId": { + "type": "string", + "metadata": { + "description": "Application Insights resource ID." + } + }, + "managedResourceGroupIds": { + "type": "array", + "metadata": { + "description": "Resource group IDs to add as managed resources." + } + }, + "accessLevel": { + "type": "string", + "metadata": { + "description": "Agent access level." + } + }, + "actionMode": { + "type": "string", + "metadata": { + "description": "Agent action mode." + } + }, + "upgradeChannel": { + "type": "string", + "metadata": { + "description": "Agent upgrade channel." + } + }, + "defaultModelProvider": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model provider." + } + }, + "defaultModelName": { + "type": "string", + "metadata": { + "description": "Default SRE Agent model name." + } + }, + "monthlyAgentUnitLimit": { + "type": "int", + "metadata": { + "description": "Monthly agent unit limit." + } + }, + "experimentalSettings": { + "type": "object", + "metadata": { + "description": "Agent experimental settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.App/agents", + "apiVersion": "2026-01-01", + "name": "[parameters('agentName')]", + "location": "[parameters('location')]", + "tags": "[union(parameters('tags'), createObject('hidden-link: /app-insights-resource-id', parameters('appInsightsId'), 'source', 'microsoft-sre-agent-starter-lab', 'finops-toolkit', 'sre-agent'))]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "knowledgeGraphConfiguration": { + "managedResources": "[parameters('managedResourceGroupIds')]", + "identity": "system" + }, + "actionConfiguration": { + "mode": "[parameters('actionMode')]", + "identity": "system", + "accessLevel": "[parameters('accessLevel')]" + }, + "upgradeChannel": "[parameters('upgradeChannel')]", + "defaultModel": { + "provider": "[parameters('defaultModelProvider')]", + "name": "[parameters('defaultModelName')]" + }, + "monthlyAgentUnitLimit": "[parameters('monthlyAgentUnitLimit')]", + "experimentalSettings": "[parameters('experimentalSettings')]", + "mcpServers": [], + "logConfiguration": { + "applicationInsightsConfiguration": { + "appId": "[parameters('appInsightsAppId')]", + "connectionString": "[parameters('appInsightsConnectionString')]" + } + } + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), deployer().objectId, variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[deployer().objectId]", + "principalType": "User" + }, + "dependsOn": [ + "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[parameters('agentName')]" + }, + "agentId": { + "type": "string", + "value": "[resourceId('Microsoft.App/agents', parameters('agentName'))]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01').agentEndpoint]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[format('https://sre.azure.com/#/agent/{0}/{1}/{2}', subscription().subscriptionId, resourceGroup().name, parameters('agentName'))]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.principalId]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.App/agents', parameters('agentName')), '2026-01-01', 'full').identity.tenantId]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'monitoring')]" + ] + } + ], + "outputs": { + "agentName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentName.value]" + }, + "agentEndpoint": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "agentPortalUrl": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "agentPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "agentTenantId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'sre-agent'), '2025-04-01').outputs.agentTenantId.value]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'monitoring'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]" + ] + }, + { + "copy": { + "name": "targetRbac", + "count": "[length(variables('targetRgs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('target-rbac-{0}', uniqueString(toLower(subscriptionResourceId('Microsoft.Resources/resourceGroups', variables('targetRgs')[copyIndex()])), variables('namingSeed')))]", + "resourceGroup": "[variables('targetRgs')[copyIndex()]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "accessLevel": { + "value": "[parameters('accessLevel')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "6305641259472431615" + } + }, + "parameters": { + "principalId": { + "type": "string", + "metadata": { + "description": "Principal ID of the managed identity to assign roles to." + } + }, + "accessLevel": { + "type": "string", + "allowedValues": [ + "Low", + "High" + ], + "metadata": { + "description": "Agent access level." + } + } + }, + "variables": { + "readerRoleId": "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "monitoringReaderRoleId": "43d0d8ad-25c7-4714-9337-8ba259a9fe05", + "logAnalyticsReaderRoleId": "73c42c96-874c-492b-b04d-ab87d138a893", + "contributorRoleId": "b24988ac-6180-42a0-ab88-20f7382dd24c", + "roleIds": "[if(equals(parameters('accessLevel'), 'High'), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId'), variables('contributorRoleId')), createArray(variables('readerRoleId'), variables('monitoringReaderRoleId'), variables('logAnalyticsReaderRoleId')))]" + }, + "resources": [ + { + "copy": { + "name": "roleAssignments", + "count": "[length(variables('roleIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(resourceGroup().id, parameters('principalId'), variables('roleIds')[copyIndex()])]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleIds')[copyIndex()])]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "condition": "[variables('hasKustoCluster')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('kusto-rbac-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed')))]", + "subscriptionId": "[variables('kustoClusterSubscriptionId')]", + "resourceGroup": "[variables('kustoClusterResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "clusterName": { + "value": "[variables('kustoClusterName')]" + }, + "principalApplicationId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "principalTenantId": { + "value": "[tenant().tenantId]" + }, + "principalAssignmentName": { + "value": "[format('sre-agent-{0}', uniqueString(parameters('finopsHubKustoClusterResourceId'), variables('namingSeed'), 'all-db-viewer'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "15341408879505554256" + } + }, + "parameters": { + "clusterName": { + "type": "string", + "metadata": { + "description": "Kusto cluster name." + } + }, + "principalApplicationId": { + "type": "string", + "metadata": { + "description": "Microsoft Entra application/client ID to assign to the Kusto cluster." + } + }, + "principalTenantId": { + "type": "string", + "metadata": { + "description": "Principal tenant ID." + } + }, + "principalAssignmentName": { + "type": "string", + "metadata": { + "description": "Stable principal assignment name." + } + } + }, + "resources": [ + { + "type": "Microsoft.Kusto/clusters/principalAssignments", + "apiVersion": "2024-04-13", + "name": "[format('{0}/{1}', parameters('clusterName'), parameters('principalAssignmentName'))]", + "properties": { + "principalId": "[parameters('principalApplicationId')]", + "principalType": "App", + "role": "AllDatabasesViewer", + "tenantId": "[parameters('principalTenantId')]" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "apply-extras", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "agentName": { + "value": "[parameters('agentName')]" + }, + "agentEndpoint": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "subscriptionId": { + "value": "[subscription().subscriptionId]" + }, + "recipePackageUri": { + "value": "[parameters('recipePackageUri')]" + }, + "kustoConnectorUri": { + "value": "[parameters('finopsHubKustoConnectorUri')]" + }, + "forceUpdateTag": { + "value": "[parameters('forceUpdateTag')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.40.2.10011", + "templateHash": "5168893811325309322" + } + }, + "parameters": { + "location": { + "type": "string", + "metadata": { + "description": "Location for the deployment script resources." + } + }, + "agentName": { + "type": "string", + "metadata": { + "description": "SRE Agent name." + } + }, + "agentEndpoint": { + "type": "string", + "metadata": { + "description": "SRE Agent data-plane endpoint." + } + }, + "subscriptionId": { + "type": "string", + "metadata": { + "description": "Subscription that contains the SRE Agent." + } + }, + "recipePackageUri": { + "type": "string", + "metadata": { + "description": "Public URI for the generated SRE Agent recipe package." + } + }, + "kustoConnectorUri": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional database-qualified Kusto connector URI." + } + }, + "forceUpdateTag": { + "type": "string", + "metadata": { + "description": "Forces the deployment script to run when the template is redeployed." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Azure resource tags." + } + } + }, + "variables": { + "$fxv#0": "# Copyright (c) Microsoft Corporation.\n# Licensed under the MIT License.\n\n$ErrorActionPreference = 'Stop'\n\nfunction Get-RequiredEnv($Name) {\n $value = [Environment]::GetEnvironmentVariable($Name)\n if ([string]::IsNullOrWhiteSpace($value)) {\n throw \"Missing required environment variable: $Name\"\n }\n return $value\n}\n\nfunction Get-OptionalEnv($Name) {\n return [Environment]::GetEnvironmentVariable($Name)\n}\n\nfunction ConvertTo-BodyJson($Value) {\n return ($Value | ConvertTo-Json -Depth 100 -Compress)\n}\n\nfunction Get-PropertyValue($Object, [string[]]$Names, $Default = '') {\n foreach ($name in $Names) {\n if ($null -ne $Object -and $Object.PSObject.Properties[$name] -and $null -ne $Object.$name) {\n return $Object.$name\n }\n }\n return $Default\n}\n\nfunction Get-HttpStatusCode($Exception) {\n if ($Exception.Response -and $Exception.Response.StatusCode) {\n return [int]$Exception.Response.StatusCode\n }\n return $null\n}\n\nfunction Invoke-WithRetry([scriptblock]$Action, [string]$Label, [int]$MaxAttempts = 5, [int]$DelaySeconds = 15) {\n for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {\n try {\n return & $Action\n }\n catch {\n $statusCode = Get-HttpStatusCode $_.Exception\n if ($statusCode -and $statusCode -notin @(401, 403, 408, 429, 500, 502, 503, 504)) {\n throw\n }\n if ($attempt -eq $MaxAttempts) {\n throw\n }\n Write-Output \"$Label attempt $attempt/$MaxAttempts failed: $($_.Exception.Message)\"\n Start-Sleep -Seconds $DelaySeconds\n }\n }\n}\n\nfunction Invoke-JsonRest([string]$Method, [string]$Uri, [string]$Token, $Body = $null) {\n $headers = @{\n Authorization = \"Bearer $Token\"\n 'Content-Type' = 'application/json'\n }\n $parameters = @{\n Method = $Method\n Uri = $Uri\n Headers = $headers\n }\n if ($null -ne $Body) {\n $parameters.Body = ConvertTo-BodyJson $Body\n }\n return Invoke-RestMethod @parameters\n}\n\nfunction Get-KnowledgeSourceName([string]$FileName) {\n $name = [IO.Path]::GetFileName($FileName).ToLowerInvariant() -replace '[^a-z0-9-]+', '-'\n $name = $name -replace '-+', '-'\n return $name.Trim('-')\n}\n\nfunction Get-Collection($Value) {\n if ($null -eq $Value) {\n return @()\n }\n return @($Value)\n}\n\nfunction Convert-TokenToString($Token) {\n if ($Token -is [Security.SecureString]) {\n $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token)\n try {\n return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)\n }\n finally {\n [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)\n }\n }\n return [string]$Token\n}\n\nfunction Get-ArmAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://management.azure.com/').Token\n}\n\nfunction Get-SreAccessTokenString() {\n return Convert-TokenToString (Get-AzAccessToken -ResourceUrl 'https://azuresre.dev').Token\n}\n\n$subscriptionId = Get-RequiredEnv 'subscriptionId'\n$resourceGroupName = Get-RequiredEnv 'resourceGroupName'\n$agentName = Get-RequiredEnv 'agentName'\n$agentEndpoint = (Get-RequiredEnv 'agentEndpoint').TrimEnd('/')\n$recipePackageUri = Get-RequiredEnv 'recipePackageUri'\n$kustoConnectorUri = Get-OptionalEnv 'kustoConnectorUri'\n$armApiVersion = '2025-05-01-preview'\n$armBase = \"https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.App/agents/$agentName\"\n\nWrite-Output 'Connecting with deployment script managed identity...'\nConnect-AzAccount -Identity | Out-Null\nSet-AzContext -Subscription $subscriptionId | Out-Null\n\n$workRoot = Join-Path $env:TEMP 'sre-agent-recipe'\n$zipPath = Join-Path $env:TEMP 'sre-agent-recipe.zip'\nRemove-Item $workRoot -Recurse -Force -ErrorAction SilentlyContinue\nNew-Item -Path $workRoot -ItemType Directory -Force | Out-Null\n\nWrite-Output \"Downloading SRE Agent recipe package: $recipePackageUri\"\nInvoke-WithRetry -Label 'download recipe package' -Action {\n Invoke-WebRequest -Uri $recipePackageUri -OutFile $zipPath\n} | Out-Null\nExpand-Archive -Path $zipPath -DestinationPath $workRoot -Force\n\n$extrasPath = Join-Path $workRoot 'extras.json'\nif (-not (Test-Path $extrasPath)) {\n throw \"Recipe package did not contain extras.json\"\n}\n\n$extras = Get-Content $extrasPath -Raw | ConvertFrom-Json -Depth 100\nWrite-Output \"Loaded recipe package from $extrasPath\"\n\nif ([string]::IsNullOrWhiteSpace($kustoConnectorUri)) {\n $extras.connectors = @(\n Get-Collection $extras.connectors | Where-Object {\n $type = Get-PropertyValue $_.properties @('dataConnectorType', 'type')\n $type -ine 'Kusto'\n }\n )\n}\nelse {\n foreach ($connector in Get-Collection $extras.connectors) {\n $type = Get-PropertyValue $connector.properties @('dataConnectorType', 'type')\n if ($type -ieq 'Kusto') {\n $connector.properties.dataSource = $kustoConnectorUri\n if (-not $connector.properties.PSObject.Properties['identity']) {\n $connector.properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n }\n }\n}\n\nfunction Invoke-ArmPutConnector([string]$Name, $Body) {\n $uri = \"$armBase/connectors/$Name`?api-version=$armApiVersion\"\n Invoke-WithRetry -Label \"ARM PUT connector $Name\" -Action {\n Invoke-JsonRest -Method PUT -Uri $uri -Token (Get-ArmAccessTokenString) -Body $Body\n } | Out-Null\n Write-Output \" ARM PUT connectors/${Name}: ok\"\n}\n\nfunction Invoke-SreApi([string]$Method, [string]$Path, $Body = $null) {\n $uri = \"$agentEndpoint$Path\"\n return Invoke-WithRetry -Label \"$Method $Path\" -MaxAttempts 21 -DelaySeconds 30 -Action {\n Invoke-JsonRest -Method $Method -Uri $uri -Token (Get-SreAccessTokenString) -Body $Body\n }\n}\n\nfunction Invoke-ExtendedPut([string]$Kind, [string]$Name, [string]$Type, $Properties) {\n $encodedName = [Uri]::EscapeDataString($Name)\n $body = @{\n name = $Name\n type = $Type\n tags = @()\n properties = $Properties\n }\n Invoke-SreApi -Method PUT -Path \"/api/v2/extendedAgent/$Kind/$encodedName\" -Body $body | Out-Null\n Write-Output \" PUT $Kind/${Name}: ok\"\n}\n\nWrite-Output 'Step 1/7: Applying connectors...'\nforeach ($connector in Get-Collection $extras.connectors) {\n $name = [string]$connector.name\n $properties = $connector.properties\n if (-not $properties.PSObject.Properties['identity']) {\n $properties | Add-Member -MemberType NoteProperty -Name identity -Value 'system'\n }\n Invoke-ArmPutConnector -Name $name -Body @{ properties = $properties }\n}\n\nWrite-Output 'Step 2/7: Configuring built-in tools...'\n$overrides = Get-Collection $extras.builtInTools.overrides\nif ($overrides.Count -gt 0) {\n $body = @{\n overrides = @($overrides | ForEach-Object {\n @{\n name = $_.name\n enabled = [bool]$_.enabled\n }\n })\n }\n Invoke-SreApi -Method POST -Path '/api/v2/agent/tools/configure' -Body $body | Out-Null\n Write-Output \" built-in tools configured: $($overrides.Count) overrides\"\n}\n\nWrite-Output 'Step 3/7: Uploading knowledge sources...'\nforeach ($item in Get-Collection $extras.knowledgeItems) {\n $sourceName = Get-KnowledgeSourceName ([string]$item.name)\n $bytes = [Text.Encoding]::UTF8.GetBytes([string]$item.content)\n $body = @{\n properties = @{\n dataConnectorType = 'KnowledgeFile'\n dataSource = $sourceName\n extendedProperties = @{\n displayName = [string]$item.name\n fileName = [string]$item.name\n fileContent = [Convert]::ToBase64String($bytes)\n contentType = [string](Get-PropertyValue $item @('contentType') 'application/octet-stream')\n }\n }\n }\n Invoke-ArmPutConnector -Name $sourceName -Body $body\n Start-Sleep -Seconds 5\n}\n\nWrite-Output 'Step 4/7: Applying tools...'\nforeach ($tool in Get-Collection $extras.tools) {\n $name = [string]$tool.metadata.name\n $properties = $tool.spec\n if ($properties.type -eq 'PythonTool') {\n $properties.type = 'PythonFunctionTool'\n }\n Invoke-ExtendedPut -Kind 'tools' -Name $name -Type 'ExtendedAgentTool' -Properties $properties\n}\n\nWrite-Output 'Step 5/7: Applying skills...'\nforeach ($skill in Get-Collection $extras.skills) {\n $name = [string]$skill.metadata.name\n $tools = @()\n if ($skill.metadata.spec -and $skill.metadata.spec.tools) {\n $tools = Get-Collection $skill.metadata.spec.tools\n }\n $properties = @{\n name = $name\n description = [string](Get-PropertyValue $skill.metadata @('description'))\n tools = $tools\n skillContent = [string](Get-PropertyValue $skill @('skillContent'))\n additionalFiles = @()\n }\n Invoke-ExtendedPut -Kind 'skills' -Name $name -Type 'Skill' -Properties $properties\n}\n\nWrite-Output 'Step 6/7: Applying subagents...'\nforeach ($subagent in Get-Collection $extras.subagents) {\n $name = [string]$subagent.metadata.name\n Invoke-ExtendedPut -Kind 'agents' -Name $name -Type 'ExtendedAgent' -Properties $subagent.spec\n}\n\nWrite-Output 'Step 7/7: Applying scheduled tasks...'\n$scheduledTasks = Get-Collection $extras.scheduledTasks\nif ($scheduledTasks.Count -gt 0) {\n $existing = Invoke-SreApi -Method GET -Path '/api/v1/scheduledtasks'\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n foreach ($match in (Get-Collection $existing | Where-Object { $_.name -eq $name })) {\n if ($match.id) {\n Invoke-SreApi -Method DELETE -Path \"/api/v1/scheduledtasks/$($match.id)\" | Out-Null\n Write-Output \" deleted existing scheduledtasks/$name\"\n }\n }\n }\n\n foreach ($task in $scheduledTasks) {\n $name = [string]$task.metadata.name\n $spec = $task.spec\n $properties = @{\n name = [string](Get-PropertyValue $spec @('name') $name)\n description = [string](Get-PropertyValue $spec @('description'))\n cronExpression = [string](Get-PropertyValue $spec @('schedule', 'cronExpression', 'cron_expression'))\n agentPrompt = [string](Get-PropertyValue $spec @('prompt', 'agentPrompt', 'agent_prompt'))\n agentMode = [string](Get-PropertyValue $spec @('mode', 'agentMode', 'agent_mode') 'Review')\n isEnabled = [bool](Get-PropertyValue $spec @('enabled') $true)\n agent = [string](Get-PropertyValue $spec @('agent'))\n }\n Invoke-ExtendedPut -Kind 'scheduledtasks' -Name $name -Type 'ScheduledTask' -Properties $properties\n }\n}\n\nWrite-Output 'SRE Agent extras complete.'\n", + "identityName": "[format('id-sre-apply-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "scriptName": "[format('apply-sre-{0}', uniqueString(resourceGroup().id, parameters('agentName')))]", + "sreAgentAdminRoleId": "e79298df-d852-4c6d-84f9-5d13249d1e55" + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[variables('identityName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[resourceId('Microsoft.App/agents', parameters('agentName'))]", + "name": "[guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId'))]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('sreAgentAdminRoleId'))]", + "principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), '2023-01-31').principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]" + ] + }, + { + "type": "Microsoft.Resources/deploymentScripts", + "apiVersion": "2023-08-01", + "name": "[variables('scriptName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "AzurePowerShell", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')))]": {} + } + }, + "properties": { + "azPowerShellVersion": "11.0", + "retentionInterval": "PT1H", + "cleanupPreference": "OnSuccess", + "timeout": "PT2H", + "forceUpdateTag": "[parameters('forceUpdateTag')]", + "scriptContent": "[variables('$fxv#0')]", + "environmentVariables": [ + { + "name": "subscriptionId", + "value": "[parameters('subscriptionId')]" + }, + { + "name": "resourceGroupName", + "value": "[resourceGroup().name]" + }, + { + "name": "agentName", + "value": "[parameters('agentName')]" + }, + { + "name": "agentEndpoint", + "value": "[parameters('agentEndpoint')]" + }, + { + "name": "recipePackageUri", + "value": "[parameters('recipePackageUri')]" + }, + { + "name": "kustoConnectorUri", + "value": "[parameters('kustoConnectorUri')]" + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]", + "[extensionResourceId(resourceId('Microsoft.App/agents', parameters('agentName')), 'Microsoft.Authorization/roleAssignments', guid(resourceId('Microsoft.App/agents', parameters('agentName')), resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), variables('sreAgentAdminRoleId')))]" + ] + } + ], + "outputs": { + "identityName": { + "type": "string", + "value": "[variables('identityName')]" + }, + "scriptName": { + "type": "string", + "value": "[variables('scriptName')]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment')]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "targetRbac" + ] + } + ], + "outputs": { + "AZURE_RESOURCE_GROUP": { + "type": "string", + "value": "[parameters('resourceGroupName')]" + }, + "AZURE_LOCATION": { + "type": "string", + "value": "[parameters('location')]" + }, + "SRE_AGENT_NAME": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentName.value]" + }, + "SRE_AGENT_ENDPOINT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentEndpoint.value]" + }, + "AGENT_PORTAL_URL": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPortalUrl.value]" + }, + "SYSTEM_MANAGED_IDENTITY_PRINCIPAL_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentPrincipalId.value]" + }, + "SYSTEM_MANAGED_IDENTITY_TENANT_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.agentTenantId.value]" + }, + "LOG_ANALYTICS_WORKSPACE_ID": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'resources-deployment'), '2025-04-01').outputs.logAnalyticsWorkspaceId.value]" + }, + "APPLY_EXTRAS_SCRIPT": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('resourceGroupName')), 'Microsoft.Resources/deployments', 'apply-extras'), '2025-04-01').outputs.scriptName.value]" + } + } +} \ No newline at end of file diff --git a/docs/deploy/sre-agent/latest/createUiDefinition.json b/docs/deploy/sre-agent/latest/createUiDefinition.json new file mode 100644 index 000000000..87e82bcaa --- /dev/null +++ b/docs/deploy/sre-agent/latest/createUiDefinition.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#", + "handler": "Microsoft.Azure.CreateUIDef", + "version": "0.1.2-preview", + "parameters": { + "config": { + "basics": { + "description": "Deploy Azure SRE Agent with the FinOps toolkit recipe for FinOps hub analysis, capacity monitoring, scheduled tasks, and specialist agents.", + "location": { + "label": "Location", + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ] + } + } + }, + "resourceTypes": [ + "Microsoft.App/agents", + "Microsoft.Insights/components", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.OperationalInsights/workspaces", + "Microsoft.Resources/deploymentScripts" + ], + "basics": [ + { + "name": "resourceGroupName", + "type": "Microsoft.Common.TextBox", + "label": "Agent resource group", + "defaultValue": "finops-hub-sre", + "toolTip": "Resource group that will contain the Azure SRE Agent, monitoring resources, and deployment script identity.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9._()\\-]{1,90}$", + "validationMessage": "Enter a valid Azure resource group name." + }, + "visible": true + }, + { + "name": "agentName", + "type": "Microsoft.Common.TextBox", + "label": "Agent name", + "defaultValue": "finops-hub-sre", + "toolTip": "Name of the Azure SRE Agent resource.", + "constraints": { + "required": true, + "regex": "^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,61}[a-zA-Z0-9]$", + "validationMessage": "Name must be 3-63 characters and can contain letters, numbers, and hyphens. The first and last characters must be alphanumeric." + }, + "visible": true + } + ], + "steps": [ + { + "name": "configuration", + "label": "Configuration", + "elements": [ + { + "name": "finopsHubKustoConnectorUri", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto URI", + "defaultValue": "", + "toolTip": "Optional database-qualified Azure Data Explorer URI for the FinOps hub. Example: https://cluster.region.kusto.windows.net/Hub", + "constraints": { + "required": false, + "regex": "^$|^https://.+\\.kusto\\.windows\\.net/.+", + "validationMessage": "Enter a database-qualified Kusto URI such as https://cluster.region.kusto.windows.net/Hub, or leave blank." + }, + "visible": true + }, + { + "name": "finopsHubKustoClusterResourceId", + "type": "Microsoft.Common.TextBox", + "label": "FinOps hub Kusto cluster resource ID", + "defaultValue": "", + "toolTip": "Optional Azure Data Explorer cluster resource ID. Provide this to assign the agent managed identity AllDatabasesViewer on the cluster.", + "constraints": { + "required": false, + "regex": "^$|^/subscriptions/.+/resourceGroups/.+/providers/Microsoft\\.Kusto/clusters/.+", + "validationMessage": "Enter a valid Microsoft.Kusto/clusters resource ID, or leave blank." + }, + "visible": true + }, + { + "name": "targetResourceGroups", + "type": "Microsoft.Common.TextBox", + "label": "Additional target resource groups", + "defaultValue": "", + "toolTip": "Optional comma-separated resource group names the agent can observe or act on. The agent resource group is always included.", + "constraints": { + "required": false, + "regex": "^$|^[A-Za-z0-9_.()\\-]+(\\s*,\\s*[A-Za-z0-9_.()\\-]+)*$", + "validationMessage": "Enter a comma-separated list of resource group names without blank entries or trailing commas." + }, + "visible": true + }, + { + "name": "accessLevel", + "type": "Microsoft.Common.OptionsGroup", + "label": "Access level", + "defaultValue": "High", + "toolTip": "High adds Contributor on target resource groups for autonomous remediation workflows. Low grants read-only monitoring roles.", + "constraints": { + "allowedValues": [ + { + "label": "High", + "value": "High" + }, + { + "label": "Low", + "value": "Low" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "actionMode", + "type": "Microsoft.Common.OptionsGroup", + "label": "Action mode", + "defaultValue": "autonomous", + "toolTip": "Review requires approval before write actions. Autonomous lets the agent run enabled actions within its assigned access.", + "constraints": { + "allowedValues": [ + { + "label": "Autonomous", + "value": "autonomous" + }, + { + "label": "Review", + "value": "review" + }, + { + "label": "Read only", + "value": "readOnly" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "enableSubscriptionReaderRole", + "type": "Microsoft.Common.CheckBox", + "label": "Grant subscription Reader to the agent", + "toolTip": "Recommended. Grants the agent managed identity Reader on the deployment subscription for inventory, Resource Graph, capacity, quota, and monitoring coverage workflows.", + "defaultValue": true, + "visible": true + } + ] + } + ], + "outputs": { + "resourceGroupName": "[basics('resourceGroupName')]", + "agentName": "[basics('agentName')]", + "location": "[location()]", + "targetResourceGroupNames": "[steps('configuration').targetResourceGroups]", + "finopsHubKustoConnectorUri": "[steps('configuration').finopsHubKustoConnectorUri]", + "finopsHubKustoClusterResourceId": "[steps('configuration').finopsHubKustoClusterResourceId]", + "accessLevel": "[steps('configuration').accessLevel]", + "actionMode": "[steps('configuration').actionMode]", + "enableSubscriptionReaderRole": "[steps('configuration').enableSubscriptionReaderRole]" + } + } +} diff --git a/docs/deploy/sre-agent/latest/sre-agent-recipe.zip b/docs/deploy/sre-agent/latest/sre-agent-recipe.zip new file mode 100644 index 0000000000000000000000000000000000000000..159ae7454137f5096b46f48672aeefb4b3f4c11f GIT binary patch literal 346636 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%0A)e)d3rs&)|sg|KHplPj~#pU_9+m5qE zD0{If8mI8fX%n%!5P*@HX>3PzG#JFaI7&;n-%9%ioqT0ew$S?kC-^>`dieeXZ<63r zIXpvfW;7Me*D*Oj&|N`zB$7EEE`d` z-yQmuZw_9WGT@v2gSS8IZtom?yZFt~Py0LHE`IZ7b8qKc1>SD#W@IZ6y(BCOb!4jQKQtSP_ouh-@t;0!0u-A)T`(g9-?)K)<&bHV;*xlNF^UD8bhI=4PoWuPHVDJ#& z-aeiaZP~)Y&f(GS9+rN%`NQs;SF&A-8&3D*klkRays{(+w zctPPnZ2f6NPw_bM_Rj_k{7aFz05zy$K{PbbOE_CX=*VR3!6_s#)2Ur*f(a-@fNl?F zjVz&{65QuHvY<~_{O{$(zkcYp@h8PZhxBdZPgwt25h$8@1i>tUZVN^M@76Dfr52n5 z@!1)o?knEwuy{|?yl(f5TTU^gblUpfvvp( zGf^K+B?_2f8q2!`%vfO}#l+~4?5@!v*4*4GIs`2>e}o9%LFl_t^H!AaNxgTYiV}75 zMN4gn!EM4#4512fCz3kNjJ0@itMC&N^%B3f8j3Owlf{AZ^omkljMW6H;6(UCR8Zc! zaVmFpg39`&@7Il6DMs;oJ20W*6SlVCBoDFdnh~&33C}R%EAHhMm6d@!;NIwG?i9~a z=h0Nr3KJZYI|$8AyB7?GPRIud85i#@$7J(r`l3V@&>W6K*CN}e5D*8;=usCO{JKcgHn zw`lEl6mePtZkJxZ(_NEJ=$K6>pySBMztsm)mzt2WS$w4`imYxA)<=^~^p@6bKO;8P zjh_kuH@(o5)ydP~ZzDv3B&py~Bc3>Ac8p ze_eMcFzv~-tW)8$Z}Ylk5N~CpE4+3Pjb2kI524t~@=?a_W*QQVGX`F90Biyie{c6l zevFpXH;+4M`|zhXZ}$&(4=ITMRaDlP+>(ggH8H?usxy9#tA0A-wzqctF9j&=?ti8x_?@j$r5(k1bPUA4tln8K+otZ+R$T+VGO z%J8PbpTV8^jP?6>rEoU7Y*Qms(FU(L(}@E;199!**jIfN@EUQ$W1L)JP>R9L{$WKm$<&9PR3j%+v7BFLZd*?ql_x4}!(6_%9 zuQtMU%gtUep}MW|eS18#vyIf|LdJ%te~Sb=Tf=@5l`n|ZtI>SdNf8H2G^oH61qRsIgP^Ts*_d+S_-W~8mfOXy zcc1>{R0gW)klw|_?l1(TeOkVm7n^UkjmY0cl%n|M%FX;&r*qMVQJD74f^f66j1R&j zu^X^W1mIsex1MXk(lfgC3E7cFj&Ymq!IK?QMwN z^dfr?xAO;4QSQ<0Zg8B(0^V$Ic8e?-ml1pr@VBpajymZaT(2I;Lb$j#9~9}xcoF3Y zj~V<2GB9@1A0e|McuQ7k=Ml&y=c9x0lKIi$OQ+PC3XtPy61yj1ipA+Bw<+-42-wbj z698u_bZ`WOdp1J@Hi<&HR;*5KNZn$fC!H4E$((nO=Ti;%$uIQ08IzWe&zmVJz0SN# zG3K!Vk2~JX`m_=IM=?qqi_mwTeBK266;Qr=;~b;1jk}SS_8x=@WEw?D0^K90qCxD% zyxrt+9%MaC1J6>iu;4q>F+YTJnlnU_$`)K$0H^88C@kUdy}qzO0RXO3zv9=#6A*B{ z;i0rRAD588VtcDOLfdMC>R^I;y#ilY=B-ZdN(SSYjjDAx_T zs5w0n&dE`ZRD#$~Pr{55tN41?ca8>z65qIc47I7pYYEcs9<%l5HOFo2DY?#y&rl0p zWp*B&yla1w;RNeWQpxUc6!yyX82{5Ui9gqi^DHlo4?uc!lW2%}>d@wwDr=rz|C~+! z3l+JsG5=kBc0P}!Mn;H@w()o}NAN*GA3Vl0cioJ3QnI>OE;y_Cnp*NBWbFiRyO@ph zNzDD+-jXd2KeS_m8n?ljUu=TbMfB2j|m5&o^ zihN!p8_1Q^f;c&A+3eG*kp)l-gRSC11p8rm4un$FzQ8@1_KFK<+7EUPk0{ImFdr5c zHtn2&G%F)aU$bJ`-~yN<;bfrNd6@PS4BUgOY1IR#V(bVKB3t^~1V&5ruh_i%&R4H)HJY>TdON`W{nACMGPNU_e?(*uh<>1L+DGb)04hF%q-qUWd`n20$UhO~a zJ%74JR|NPLI`JsXfD^+oHz$f_ic7|s$7n{K?V+?2d58~Lg;KH{H}cu@C(BP(o-75+ zD{HI4+G>9}=&nUigTeE))u+9vKN$3%A(3>Mjqn}R2~egP5kVtRafx9CYu)AW$*_FPHfvqxm z5K{@ErnP5LKV18IEm&TA_9R&A_Xa`u_0zSWzw~_RNq_KU>B(A1;|+1SW;P-%epyug zu-C-3aa?VP*7pPq338+B1*?)=(=(rqAiW1k+`ED>KnSnw#{~wm)`Tv!#co=ZQP|g1 zsq#tF(g7cJQAm@yX{wDpYQey@mKa&pbO>EEUUlss3pYX>h7`1nPHK0 zIn`Za7BtHm?mQAukY^WANlg)eHv*hg!H?%*xjT@$7y@J=f>h1tuQlfFc3Zc~t3l0G z_M2)`R;CmsI=e32Kc1pXKS_CToX59Po$#jl0cc)h3Q;eszaVGurbgL9C>0)A1DKd~ z$N)%qY!?w)ZkopJq)g`OC9>>1D$9gOAy=2ym-zpg{1Y*wRCYgz9Xig#e4c{fSwGLl zd9lu%!0SZ>ApFItXbi&-#<7hS#&%qQlN9c)As`=^oS>ki4Be+8@HzqZ2R{|Mf(UjV zK;>lv`8t8OwL~@qI13O7)= zgt*_2pb`CO5T|h&C08Vj)Bm5nx9e&n+0q98N;HQmB#u%Du*)v0s8blQi!Ni+2)kY% z%d1GFMC3urRAr{XlyR@QnYo&)nTz*k=10ucdq4e8-d{57*?Y%VW=eofeVm>?t5>yA zMnp!&$BrHQ<9SlMK7r*onM7g6H}eDiS^A^GQBINJCwLX68eErgNL_jBY^7Z7>^|Q; z+Qk;T4d@y66y>jq4(zWq&M0ZZK6`Sd`lFa*IeH6Q5}?*waD0)*&_U6TOF69aGFt=n zrIJYmN2=hRwRH%no>Y5CAqv4xu9;fnyQ_w{#S|H$-%+_n=kbVFNe;y(pJt~aMGZ$6 zQNn?B=KMBv5V>NQmbMn+)gFaRAYFbNB~Cy;&x>r@FQysfkBYM_8bud~3oTMM;XC2* z<|wACxI3r6n-cF%{!F3b2y;1-N}}9!RhHtPUQAYQ7B(2n)rAhDQ-ragOqW)ht72i% zf;}C(c!1Ppkzp;$Ga@h0WfYx{t`L!gW}+M$*oNG*tx)6vA^i|)B*6*7$|bExX5QY) z_KrG;C&bc1WuL{x57QG#q0X^oxyhaA;w9U(mY1KWL!`-1CNSrbA#Iv*a8$uTrW8yi z=VG}>rVAUj>Y&8yX^G}_`9*XIGk|%d$5#dRH*r@{5`1rA|H?jb^bL9X6OE)S40rX} zl3fsBfyPEPV1(ESi>TS&8VsP5G*+9Y9GZf$FGFhFs`(kkUY_D1I+G@Y@XAwr92=JO z$$of{4IQ(AT~!Cx)yG#;Nq5H$g|PIoRxnkZ87DDvG;E9cc>T1-PZ z$l{YJKu4$!8AvMuX>Kf9ZQV3c`_ClPt`r63e!Yfn@Un{j&E^4;g>*EUX+b?cK0cr3 zMcPZ`sB*x0%6K>~H;_KqYWx#5;5f!ENUfkRTu^{5!|=ON~ZrIQPY zMbj@a%kC+4$WeuLGry89rfZ3>#;X*)FUW;-;IzZ#w#Mu`c7#3be1RDL${~hyZcAM8 zA3s@@f_ffM44=Wp`0JgKDbfMO2{!I9L`}4mPsigh1N6Q)+lz3dqpUaaROb>jWj40S z?G1F{X;L&KmZXIKx;OB+`MgHqX7aC9r3pa=0gd@%=fVt4`J2&2!%aKWLCIIjrZ*DY zkT(QY%*=A!{Ny@rFk)h!-JDT=u!$HZv>lfRs3A|vBCnA}RF)`X)P06@Tkz%2 z!aHmEFOQCT%e(d6T^rhu!W`B;X(;GU$JT5A1Nnm%j!GX(S;M$JaH|_?vEhAoyE`2> z%RZtkPP4ec+CRAx_XM4jzMyoM*Q}xQy&m6xc(J*pPtv7tb~isP{@k{%5Wvuz`L_QP z|47{|Mw{#3EbT{wcsgF%T>EC} zd3w3Dx%%;~aWTD9^I8?xjvj&;o}Z7_c?8doo_75`>iZA7eg}6pDU9i3iyxVR(ZA34 zMLC`*4f0oVLHV&36%lsiN2{~0xQC2K#G3%F9rk&x1vuJb`TuKu@kKT7_gcM(F8%O7 zpk&5{T6+*Yc&x}e!@g%P55T<-ol5A)zND19p=@YB8r15GnbvW=#wgr98mMc!Ng-?j zXda~12HDj2@=I(nwZVCw`V7~(l;pr5KqVyepb@%r)gxirkvAzOl7S|P{Q4_yhbAvL z@^X4=-=YPLN4s@-V4u<|B}bIn;Wx~>0Nmv*=x@38zlh-@PKJc%Zw+eo{V*V+V)vc@ z{)#z@On{#g{ZmfqxNQ*7{Ce|Zff(eZg!Sdc1?^D&h|WGP0~hlvwJIU;=-$l=iD)KE z3}6u>3g#gU4yo+gy*U>Lmap(ULKaSx33x&|CY3vplaB%E=ahiOx%CoV??m~Ss~lOE zVb`4*eW)z~1F=pVtHxfE!=XvzL+WR9X6%qy0>HpgJ7OraI|d@4k1a=^X!6pfJYe90 zYLXqLUCqv|L!JHd&6wFkL_%930v8NNAM-pj@EqeQl~SIKnTeC4mX`^56|NRpKQug0 zE67At{_y2xC$|Ty!jtEt=pq^k^g(rWmX|4s(S#ajQ9qslSfny;Fk{-W^9&l+XULzb zQQ`kmm(W|$q~W@RCasYcC0aTM@&`Q$_Bni-%|2Vds^Dpg1s8z%<#KzJo}9pBHKVlA zh}hInR~K$If^_j`pYI4*cP8tYd?^V|`>kJ1V6~&`b>n0>f+f_M0DnwsKEH^_k#*tk zZ4aBpIPxO5SK*56EpQ5bMuouqq z;04oLU~%Ht;KAu?r>`HGc5{c_AtJBh?UEes`oW+2T?ZLs{y+c#M}b!bZSs4YjJx;E znkyauu91r??A&lx@IUoLm@+!Vk%vT?+3r~yCv|}ddhpQt z*7Lu6<90;I9-lH|C7(LP{PVxxFrue%l1}pKX098!&t3Di>*voo1oyOsXlc31)c-$* zpt_?>{)zx?&k!D@k>T29%Ddi+xe;~lrL^kOI4*rP;(EKVd_=u+I=0G4fj;(xxZep6-hFNy(s+~~(q|S4p|2Cy{DgYrlHwHTK@F(CEzUt~%k<2u8 zy65pk<6cTgOO}o&f^eXYX(8Cs`p$R}WhcNtkuY&C%lpO@o_SF6rP?eZXY>4at4Hrf zXW7tbSrjHNSK52FctyE)X5#Kk^Ai@LT-@$H)U#*tGR$xg7RkqS?s0BqUwq6On70bOiH`m?j=t-y|8*FZ$1Be=Rc-V6ZJ2yMt^@{>pt4_oInAipCRoBy<`Le(WWD8|P%>O||59XbC01 zcT6yiB|avdOD~%``GW18DoahB`5KiD<`CPz+O*!=9s&y0wN1ItxGU@kLu)2y*dD!V z=_FfW2;mLbK)e{Az?cyNHY04Twma>$CAG;OB(_a0c^0j}?(ij)p zE-JOz=7sN;pBOE!JeZqHZ)XH%P3jM-8%V=< z^Lq?WZ{d5tw0%Z^%KB=AlQ@V^9afWS$1kPKpQYc`L>bmIYp%*1#HVk^oKHtlZ=U~p z_LUlO(WvQ=^Ok+zWvRJ2`$E%87OR4BbI#Ru(Lc5}RW}N={#mf~tJwVL>{Z{Rw6+Es zDC$c1!@s*cS|&)skEdL+m1v*C5dZ)|1z+S~31N3Nzw^*gUCppniXoy}y`;DBeZ>{c zy1`<@|JXJ~K{RKNJPi;a@qmp+m7z`ejWo3Y_Fl+y%gP!#y7TEt8~tk{BOiP!P{)$N zb~;Kk^(KNrRX{;*GCI{6o~U_$IK1NJ`*3ANxrM7&;hH7oR-pTmdl)!df;3wz)YMa; zh}U`Tt)^-t0C% zzBsz&+@h7+&hM=!=o2Psw#j;)A$9I_%`>r;<%_7Ovvtndfw3+eEeiOpe(ev6~>U1>i}et9yTcCGapeRF?AITlbU1G-smxM%^r_ z0_V}yWt!c#gTHA=kc~xGQI@5d8^_}W>#V%I1Zf9{?5NjKhByNH3vlE^y5duIf)_|c zE78y86To(us0xLeln@E?-!xIj72m4NkhX!633C)9G~rt9zK?Sz>Y=M~oTx#3O5q!Y zwvNJ-Naj&(9aR+1fW#}%eMtH;*3Bp$#|#Ooj?xq+C&XnWoEO35m{Crz-5LzQu!EFF zO86N}`#>E;W=}MVbFm!r28FEyhPrF@oa|+lpn8}kFny^nOBj?4W;!@6e$|rLcwk4skuD*RPaq7y0J~{8(7p zTSofKsxU9a#}FHOVLdb>8n2q*Rc!!`CRISjo+c`!lnF$j*MzO;0Jt`pa|v^r)ZP~D zzJSo_7}3Y&Of0oTHZ7BuQbFhm`-L_K-kqG0g!^q68i|k<$v8~LFrH$NBDKmKRuos; zf(SuhPa%r`b(%zKwWZcNtB(k`hgax6O0N9dG|Y-9TiHqy1SpYFahQ>K#n%d`t_QlQ zq26U6alJJ^1NR#SLyb0teeQi`jVP_p$ti_$AK#FMXIudSq~H!)eQo5om1t!?WJA9p z4YMawR5fNtTXA*q+i+xE0*y53-aj7mfYxPibFJ|L{TbOd8BrK1}#u zr56Lc4f)<(36V1|ZnxWWnplaso>ap)^1r<1IcQ7L12%LXn*dsq-s~!WCV!w?L=&~T z!P%PTOmZks%Lq?eGL+-AWS7iAIM&=>E}jxuV40?y!>~6(`hP7%<|M_2oM8B4(AJNT z5BChaWuwsl`e?bu(h}jR`O3BOs37y$g~Ea32u9Q6`j21}>9HE5QJyRn1{>d#HcZ!~ zTlHz#Om^XkGb`*n^V;Yo-B(Wx8u8D2JDZCQKtjoO$ibkehcO<|7v~pr;#7#=kl+2u zyl;yiO8uCH(P)NhMOMcOiMi1g5A@$=0wel#a3&+aHc=lBbb1cw>vMXJiL37|@B+a@ zIJcY!W}R?F>77>>MFarYeJ38}ko!oznVOf&A8)2R0W zGz$7yN72WfSx+e`iyGsOR@$N4LcgFpCVk!8dSmIk`g%wp)zwIM=V&2ErSB~W;;28a zXv0z^d*ip-`P~O_wR4LRbeNq#c@&+YFl)_mD1BV2O2hRHeGw9A$g;_&mj-@Jda31= z3#nHlA4M+lU)q1<2?Cf{s^Zx>wQxJ}G(pN^vnkX7`|uPSo;Ix>GJMel)StO(*fjB0 znR&6LE~AsPG(FFotfap>YxN+)9domFc=WQn$BYgS;uV z+!Umo-%?}GoafR{2{NJO9~4nIRyA9p?$CcV8I)C_nUnQt2k+K4m49~l^3?%q^%ibE zNlQwwH#p8QYcHTNd!h3c9uKMK5B@*B4$xcBN}O+i}zbzc2jQstBefM@?`Wd(HObNZRyx+kFjaWY!w6ztV0620<4Xc`uEqOMK4S$>>n>Gislso&40I^B#_89+Meok^ALJk&HGw*6?JqGS-Hr-3k`%xaKr z{IF$_P*pE&IC_Vi3j^HRXQMPoyN<;c5zo z@<7VDMm&f8N*n4>IUWKyD>c8#n0fW3W1rCiclgc?xPY@S4I)kn2TOGIQoLA=!q2#B zH>v!dPDZM*SeLB*rLmP<@tSCsROj8TiZ#$0ntU|}h+=n8b3Waccv}T%rpn_U98d5K z2Z97iGqKtx-r)$gTulUN_!h$gTFe)iUCaOzVoQXyCN(C$bQsKf$r{?)PRA#)My2zv zPn8M$8aZo8wfe@-;86ap9b&!YlQN#(&WBCSB=t04Q2UKz}>?Go^#_N^N;0&La!fDiWOUQ!QeICyrJJ zALb#NMTVqJky%~_iyXzrI2KKx=86W)-STXspXJIrg4mA{+N?puEd8mx<8xeF#IU_m z$V-B-KL!;a;_sw!c5CU)b;nHges%py=DWLKZk2Y=EPi~SS>cr{cNV@1O2Zti!^Gjj zI{Nv8#6MLZvw+I`Q4(fx+WaivoaF@#G^=bdi25=1`RyHccWR~Hi&sZ)tD8`#2&jag zxRSMBF2Hbb_7gR68J3{%TCrID|JJPFwr zWiWp9LD~!w$RZs@1QE)b&|yc zgq-6lNc5y=?L4}2`9XkK3Oy^$ytMzCWP)xyh=P-=Add%;`^NOtBkurwt4Fzpx@J^$ z_iDx>FEsBvF@cYw_agVm@IuY}z@OwW&&tn~Gq zvEb05pbMcylR9s}mIoz1PNqb2n3D}j4$?hgPNUF@D5065DK@9k>wVSz@f9V!I42Z> zIh>BsOW2pp1MV&^VSIVC_Jv+#P3Lz#_oYq7hJi+PWlp$y#ULfMA9PJEoXP- zp(p|FdOAt*fn*z{9eELEG5sN{tJEbdZeQdOz_K83yKmP~J9xR*Y0_NcG4QJ^n`zq$ z9AmD%rsxI$TlxcXZ6q?Rqw zYbgm9jWuA-Gi1o*n0B}Ap>cWr&)d$ zPfEq~wVn(SVEnV6z_h3>C4{K8zq|mbHwPRF0llq{cBhlmEJb93u|LfE`4xn;oQx6^ z!gLCX$W&aVfbC`tS(~r-G0|~k=A#kX#l%34X6MM*xzc5}Vxa>c=)@04SU6dVFlQ{~ zG4Y)_>RE1&<|osu(%Q%JT3+ToKr*bQCg26{vy8QLC{||3$%?joQOQX9(wdRXX@(_p z2|ZQsh6Yi+Gc_}AGx|pANknO<$flz!HBH=J;pb=!g6izbb`f7mT2>Y(eVm}BBMII? zo`3;=w+7VLyw7<-x8*#=uZV2CM95`t;Sw7>gm-3b%K~g zBHOl|Z~_3F-PWt zH8N$UaRQs4Zji%`1Jf*hg?C2*a-u+UaqD6w;};s-GqoQl)OpR3oSwQD z4py!ShOzOLl$g++J|oRDAoUOeKp((mL|#K)bZn`6*%xBTdyf@ZYq7kUY|^HZr>86g z**drVx{199bW6xH^otde5bvx0@Z1MMRkm% z_0;W}YTwx^DO4@0Qg_>;!P!2G`fO)FbBLNBYq6ALm(XM|<|bWCT>C*{B;92?9bw^{ z6x%b0q+Ou>47L*ZS5Zc;Mf&btn+9spf%~(@{4`6)-hk6$=p~E%8=dQv6uR1Juff#W zen|garT;#r|E@QgNog_)`(j-T$$6t2mL|th2w3!n*Yv z(S_QCb*(six3SUvB`X@`hN=+6Qu-jhY%Kn)0!3YDskJ8HhU<`qn?MRyE6QzIaygO2 zg)ZpMtZ-`>`1~@)iPl)`UzltuASkO~RAAYvkLrV;thN0bX>q!LhsexA?Uq_^HWfu= zpWtk+UE;lkZ`4T^h3DFF>%8i#JHP6+?2HYcFL?Ib1lqFlk-H19HBRl8E)jI-WhS9d(xDJaSV03@0DyvhN8>cXUOglAcl{3|DlIVgC71?G>Qr#9 zSCAY0?WyRk4ltXM{$Tx0JtO^{3FyrT#5fu%?DF*Ra~bBPkvH8`!xkd?qE$mQi>zeqy&rOA>C3OFV1F7+smrcepCzV??}Q8b-Y-qx^k9T#(Sw*0SKFD zS=o5h`JzefRQe?iRgM~nNgH1vaUQ!DJmDlmb>snJVe*-APF_|L*?hmVHlAg|va2y3> zzO$VM2ViNi?STk0&3dV$I4RukNmY1yTF$Kv2oJd;$z^;J$V)h&Oz0P%^7UgdMVNFJ zVYz#>xKKmebTM;pWnwbLnZOFLsN7`aDEDU=C3Ff7bk9&tUh9lIXzQ^MUZB} zD5ZZ=z9)vpM9vXJ^(2dg4i&Z_vOa3Z?{4={=u`0)Sz)C5*11y2yT@0!AW$i3#?u5A zTgMhg76E4>x%tOl^B8BR{UBh214b)i2L;JFf(KPulti$5vSC2xEj$4uG+MM3txzVOS{IMCY%BZ4O&X}|Iez$6jlWH8MOaP0(=AzWmbZKAs* zQ(qR6crMOhFw_9^DzskFWI86)b9b-L_Dr)Ji-CS$iC!3o6EcEh$(LJL%ICVX4Q=5b zRMYYD@&=P8{TeBqI#0{ErDC1t;e>6NrS2F>Lx2(HWurq&MrpTuxZ()fl}p|P+y_KU zj^ke=^upX=Tmft%3X1xXXz68BCS`Z+q%9Q={(BHW4`6-b@fB?D5NpSeat z!88=$TBi}MNRW#;i7vyD#AE1A<=>d368ErSI>~PYO3}zia@<;?2TauSI62=?Zwc@~ z221Q=?4q6T)+8v(d9W-tf-R``krA9dWtP>tFmI%vC1|eLuV^A?? z#FtKbq*js9(p6;!HRx_1{U&EpjmZIO6Ct!X)2CQ!_s%>E$RI z49QKRP1R*%v_L^<+2q7e5yXpC;Bk>BcfJ?%b^{=ae6)M#xC>#^tiVWVFhGOeAAvYh zOVm!)@V|TMhAV*3jmW&7;y?p0@_;&mAhSVa!V*J&XfV9+@0eQmHbyvK5f8}k4ZI<9 z-p8H%-OeN+<{(lts@gv9?aL_?)C*AM7f5{Z?EUqL;5lMRt0&%aRv^271321CfmQeR z>CVIk`fc0~6Eei{ITTSeNfF2u<@dHBw5mjuWc-qVqlHWR;zqb&HgA6x>u`X_#hov}=H-w(bBK&T(ZR ztZ@qjF58wGod_{Gd&*J4a6CChf0&*)k;O9+dTbn14O)+D@S8yyFwbDIyu7=$ybLFQ zDOcw6L394+|MkBr{~bHgB+TR{|5?qi3`|S;%7;NT(eL!%w`=O$(`T*Nzv|F@oF43N z`@^acgMLG-AZNVw+sm*)pA8tK+dts;8CRLn13&q*`qD_g@}ufx!H zC~c0!m`#4tCg=*cQ+pP+lTbg0h3PrTmHEg{M*jY@rrCK;I5{WEnRe?HZ~+aVK~AR< ziUtusI^Lu~bQ&j=dEACczXfH#nC5N~bDRLSbDGZr+dyJwS$6yp<9a*s^G`nDv*EsE zqm<#k=CA)iJ$*Km@#yO2 zDZDKx7x`ugQ>nLb5N5wjk@f2!UBTFX5oK2}vQ~hu2H-jt?w%?tla}Or1gBJiRha`Q zSUWPJ9Iha0EF4Ca4f3%bfe9$O{Qhw+qgg4KrD^e$>;VU1amJ-@UI-=Eu#XUCw?$>t z3I{!^Kg~-(Xd2FpE|w1B*-^^yWL`mNx?RjzW$=etm`q0@QUth>9ju!hyREls9gJEr zrNu)yAMr)GE3B^L+Tp!#Mwwc$Hd>DvFtIFB+iK8RJ?eBe=>Ps+MeL$QDF`g9Yr(o# z_|uTJ00%5mXKy@?1~Ek-m4uFfE$C}aHm#KlFT209U|7kf$xPu;{n`fxM~p&kpOdk) z7C3U0o{;a%T;ufC!dJ_dq*6ZimF!JM7x>_B-H)b}X^qR7jcN)YS~q@wi(P47JT1-w z`1{o;9mdH`U|ik!SMOAlTk-QK85U=A4=hKu`@u%EB4X$?MhF*=wp=%l(sXnl7cOgY z!?`{-YeT?vTWWQUlToVK?!DwibQ$nVuux?AG7WKW!7LID4j=F(_A}2y-Ih12L`V7C zi+XvtJ2w2w?)#`eMKqtY*0tiG8ZVPbF&Y4Z_z2g;N3Hm0RuWERFoJ)C$y#Ua;eTlf zzrB{A_xbOs5AdD8rp)b5)rWUERjKg$>e1Tz#>1~S9)5khQx#$h$0#LL8BzF0oR8%_ zaoYou4#Yev=)OaN6y|<@ZJu4bcaLkjFWJcFj6h`fB)~glw;v9`4nzhOX59mS^6jolUz{xXH{`s{zOk< z(n@*@uM+45X@&vlEvQ}4PQaw}G=7idx-BAzU@*9;9X^T>sH0K&ES4k|K7$3B zRXv#&a3EvpIB(QyWULiUXp$Q~c++R?nUxRJsXOhN5Bv|ZyWM)f%)vtPh6kuZyIabh zm}-SKj+inSV#wIp$du2ZQ5`F`XY(}W2_4DwtW6KSq_l^ zjR)NBXL{X`aeOC-+l&fxeQjJvH4d_9!inn5lB10a+UKf)MMy|^`)LvtNP@P3-^9y@ zElAb^lLa1rI~QYxeUAV)N2{AbSQ+uz#WwkV3FfuSfo z`DWcc`d}{++h8vQ9zGrwMC>yX$jwkwI@ODpM~V%MMS2-#1L_5L0sq2l>8y~%KsTHO zA%sk4h=^S0eLBZKy)@&tl|_O!L3eTeGo`J2K2@E>UZmCZaz>FvE*3kWVkfQ}S=^D6 zn|>nc#S9>!M~pb1W1cb&*w=%>M-e+WpeYdOh8`X>deV-}63@|on4L!j2jB`=2ZiLw z`jb>OgUqxYCTYScqWUF`S0~e?m_pIw?9{l(;`i!xoY9yAF`PupPL!V)DL}dd^*RRi zlIj-IL7bL3um$l@=v88VpMK(ZbUBod`%ch#`04%u^J#eC1MgZ}KT->~C2&k~-Fa;R_iuNL zmXH~W?N^6~yDyG@KG;3ndkK_pN+%(wmzdxP(ci-xmmRu(__y}bqg zB!B*F0LscNe0UNK;{+So9rqLcql{-u?NW@MTZTg>O#zO1j|OfL9f#ba=uPCRyN(@} zpz_3>T%Ni8?b6i!NhU}8&%X74K#`lKXOz}D(AMW|kiV6v0;l=r<`Mu|K&HPN(U;z} zKXl2k;f*W((o!$87z}MA_gN~xae^8r;sLH$WVvU=L{h~-rdOBbU{%jQXHR#y7;5+E z`i4lVU8@Nk#`!r4G2fg%HK;KhDsjRYOr=S9yDHp;YsEoJ`->+UfplNzPl6 zvYPH?nW<~(-9LVT#XcJ{JzH;K(V5QPf?9gpe)~>c3nEOTEp4lBk+}(6i+44SoCoIQ z#yVBcktQJkGI23ASY#Z7E;y<6(OZ6cBQVNpmb$DnK~1}cLQdHdC9vx4Qq`8xy}mU- zQ?4?qoBIiOO5o+uvuL0apkG>W>)GvoH=|w30>GC8e~}3rBAy$MQNs$!gyQVum zuz5K-7{{I-fo9BcWU4i$MC3A1*K-nB?8WHHQIT>aZ50K^KviFs;nmy+?(hkzM?1))7`x74fdj!EI%c1JNzRAto7DwdMCD%?OY zP`jcJU|5hw&^!8@;lO-JcHA{ahdpC-a4MR8>ewVoEoigNM^+e=9d#)oLL6O)ij-OJF(shSl{ z;1l(0x^VnHHc|OM+j=HdY1WGV(#+u|^on4AKiJv%QmCk$pMI;A?@WQWES%p}3K$5| z2&sx=ygn|yOhY+2m5l;mMIoVBXr*(Y^D8Q6ysV$9u;sdvo@q;p3EZf!?h)%AsoK1% ziL?C!pt850cvjTvr_uCkTBQTlndDV1zp= zCjx08X|Zw^|K%^pc22V*OyG?y97o;m7P5{hZDB(wYdF zuWF5#8XDGD-nEBr1D5~-FcEEDMA=$rZLRZ&`u(o}d&S=x5>_VJ3MVw9Atl_~5Bth2 z?kEEJ$tEqHI#ISz-H~gkd=^dtWYIGEPB@tW$}`NXN*m=DaP~D)dI{MOQ!p@=%qnRM@&sPzSw6$pxO?$gpufqSF1uUJdtl~>!hjaf zD6sC^Kt4SG3+{gI1MWm1ePI9J5kV=qowR+#c-=!M$Ney%G-t`ald{ zsU(g&b^y_$z8{}Lx)rFC4+&(%cZ|$H!WQ^ z9d{!J4m>5~6*KV!`IK>gwNGxlQcv7)JA?+Pcc4oP#(G&n91Eb1rB_?uT0r%qhrKHy~kO2#Ju^Wi{fk_G71}^Gb?F=;OH@?UX9{@1Z9s>Yk5fE=e2!B_XI>-FC`pHIPwaw;0a>6qP%7idjp~s zBaSFwabE8z2Tz2U1nJFo6IL_i#B59DIGL#IZgt&-2Wie>mFCWXPtl^6FTxt*%V1?} z)W*2`gDe;;|3t3Woj9M2!Ylg4&Cs$xOKkFAXaq|WL6|hWV5`@gKi;wWDaL?R9=53DcN9(}6k?xF3%yOe>!- z_raiQ)d<7}Sb?da(xr<}P-E?_8Z)S-J}IcXs7VSqtwWdw%wsC-*eu+Fp2dO+mhBZF z^a=;a{nzaj(;PqZEP?2iqYDSxO*J6ga;B-_m>Vw<(Ev?8nPv$H1|lnL1c7l73A(T1 zOMF?tV859%Y@Vah`ATPWGz8g;!mIxLyRF_-q4%3LRj?NW$H!|5WY`Z1PLtrcqqyh*TDHNBp$i9?UX{T}%XqST?92c_e=w4#j ztR-@cB!b#h-f*h__#gZ{SFZ^F+Xhbb5)Rcb*9S;CV6m*2_>cdgc%<<=3ktKGYW&#b zRlrje8m&1P(fDI<|g(OHi>7(`%6?e4py3V^%jMjx`39XgpS9Q;KgL#aR?*D!ok9 zKn@Oe_E~*+5+&h?wzs^Dz}4y6zy^^GqU!b22L5VR=>PoR{tsh%{Ht>@&gltlQ2K}M zR}r2pFVkvtek8c~loQ%v_CjDLbliX<3%Mh>GO%4vE7o=hlOewg#~2=xpgD=o5QF2P zpIM$LCpv`rE_mzTqgHm}yg$uzU)_n40ez7kMWVvx3DGu>62Q@zAj->71Y3h~ zOw3z>i4hT~J(>%vyr9HaHLMz?uJ;xmUjtd-_jy@y7h1KyD_$VX9ecI;1t6i!ImF{`FS*eHkC6- zneq)7kz=hAsC)-!u)OcY-f{chXq2+LZx5vPrtEevg5T|%pA@Cw$XYhLmhw%;_HoP|jQ7&@U*zr7{+7Io*@g zLWc;3;XX)H$g{%?)6%5rk%2EsXNh&(*Rm3njO~RrGfo_3ZlJmT! z-|%8@n`o=#9h2$F2vH#iIdG##NNEW{T1QGL6aX8wjswj39*cId#AA15_^6Ed^_0P=gM$7)3#2f-k_3bJW(%w|&n@8n>mq%ET572&&kog$;K zoH1#_It|-n0no^F+ZvT*pg*%jWpQ>@w@Aj+S(JHMeTbut-(!ChMn>F$ICl#7S}a0# z=$^SC%R~$*`6?)q;cOM7LJpwcff}Tj2_0GRK=LswsW(?9700IQ%viugsW?GDX`#1u zW@|r$|8xV?qV!%%O~jDRw8&}ju)syjYpJ~hIMR{NsIq7jk;+B2gnJV6OgPkJ*O#rp zE7#u$Y7{{OqLJD9v8(zc_)bB`8D{u!(g}{vA`m$VSmP+YjPfENKwSc6@_^kf7C!;k zNA!W1jTEbtDJ#!H!u5|Cup1z4Qwm^oSU7J4EEY%A^F7r#4u55IkYjS?>Sbr4IgYo} zB#HXqGZJ;~nC_(rtbi7>yv+Iw(LNJ^wwGIEUsu|!Ap;&aq6AEO(4Pe>wXg zV7-66-$q;>xt(l8ab9ew#ntx12mkYb`9Bv|*VfvPAFtp&xDyBA37^(@Zy*2(`T10By6xxZ(>7I?=kc%6vlG7vbpgLWkwT-Csh#CdL^A0laj&BD z0KH`*X!xG^B{)@k;G+!!27_PibUI!fyhKMNQ9*gObSF3sMT;e|fSESy#F=Q_ABnGh zy>I0qY1|M8*#GwOsD;q|&8~ENMgG6-y))Bso=iuhhBIgvoCmlcf}R)7{@WJqLTGoR zVs4d57GH!#w3`fw%d~mdRaBmPX>V`h&wM=DcJF2R+s-?eF-zAv*kVyWdlf7%BghB0 zDVlC~s-+PX$+zUHaXkA=)xT^i3U?7$uZPhaIEX1D9sa3%wONX@H@Z}C+ z_`T{7rd!Um6e+xMIEEYb$8uABtHNR0SnmM3?OH|e3q&pPd!c2iO;w~|w@!v`6Ma-? zk54F>by`CN>80sFk`@i8F{r;wwx=sgRP-NdoT&3S8EoQ64wE8Q4c>yz2;k2OPV<3d%Z=xqwRj+CVtK0;aSl}xz7|hx6z;aHz-TGEz`+Q)1FA!_?I3$dhTC? zNZ_zd0N5|Yc9N!}oKCeQRj>DRePYtJhV&&|X6|3Mps%K5bES*)R0Q?``YTMLbHq(u zrOy*RwWrK&lo{_BFWpP!C|`ZtUeog39^>jsn8*FPYS2ASvj|*A1sp#hE6)p^b%|?n zG*HutQA>8~%|Lj(RsPYOO0W0xHWEn14vnt1=!IlW=#Qo_SP0wVMVzHfOvBJWghoP6 zVPifKtIYiiL-(`r0e8^2=O0;>vcJdCrSCsE&}T6x#OKMnL-$$zCFsT8Hbr;S5j$tj z!hybDGl$Scl$}K(+bzxe!YKmdk~GeL14UB)zkV5i+uRA08hhqKHFwHtO6y7cAHe2b z&1x(I0M7rFckYJRD4S(_R+Vn(3o%Vxr`>tD^6ZJG zy3>IaXv@{K#pcYXmNaE)dEuqugh0G`I{C(w35ql@<@;v{{57Q8^|#ZOOh!4n%Kpib`eVHTM%@+#5e`z!AKq zF3J#1vM6vZ{phppsKTmdrsEP3UaeC^A3Tl)nGSyOlGI{5gK`pSJ2aWP!NvfAg;QMf z7kPhes%{i!{j*@}SGFJr9DVqww3R}%;$tl>JbfK_;py#$ll>6JeUR1DO(HmS8ztmw zD&O{A#wgGHzX0`|f)oH|Mw@ur0mDgn&~|XirC`c6|FC{OO*6Q8KYB`w^-l28(M~ne zE6uZG-uA~7u@VB)Z;+B2Lt###>x@&Uqj1<(dr4kIAx=(2y7Q^WWN5VfB$|YcxXG|K zJif+7iovA%c@a&T|9K5#6=k7B6|+OrA>J?w&(ceF$I+yoy8ch* zVTPZH76%+!(fbLeqd+cXmR{f}(Nv|_S7^Iduu&J~^UA(=&6ZShmi@EJIu$&1v`Bn> z7h_EMTbFW!)aNvlNYNDalAp4;h=L!W9|HRutb~g!gz`3Nv(56*HS*>L#zBTklh6f6 zL;-w@{;B}Jc9>Jp(?#iu+N7{5-4(r@N25xAq!WK*Wq0W+%9pTg^d~L!lK50LOuIoM zg^VoqzIp3}yytC=DV{|Ig(i~dUL>eYmc20cbZ#N3L2K?npLZj;ZV^ESAhN(i-SN173D=Jd4qla!v`w19IbAl|A|HvYpu2PFhV z^f<72ko%i3rKj--xyODzrxGm7$*22Auwc8aw8Lu8C-&)S5rpY z0C*E}Qy*xg=Yfac3E)XH^*jZz4k57?DUKis>T<#qnBtS^<4t&vSWQSR;lx}-15sQp znmr+vVR^ z9|en@_WI+MXHS}K{U$7=N+2QtdpahwLPvRIXup99ItnLC$Vi`nRn?H1I@zCZ)IC%WrN-3UE)~)kOjFG zRxaaYkY461K$s0|ivcT)Oh!Ny)c4H%PRaKb>i5qG=62b`Zy&}zx7NG>ZZ}h>6uNEG z>+9*k=djDOAS|*tx}ZHzHe?e*WFaI{Y}!zX#*^bK*>uSlprTKmGpPhS8hA2}4kRXPoZsX3hJRb(cx0jh53 zc0k9!=}hDGK7gS9?YY`{g1nb}oaXe;t;s|QOk+!RuVA*NtZ*VQVPGg)(0h6~;p0}P zqv*X(+K>#r*ZTmLB<&43n4{A`V2$MF1!FIL-r~c~k1GIAA%>fHjGPX23Dl8f_>Ib= zNWEp$M<7*<hB;~*ECK2?9D{u_3Dj!9 zpOFmII{&kXvN4C|3cQyXH1u>5`2cQ4#OxzWIxoWhxql+eS?v=04EY?*-4#0c4mKB7 zaQt2ndxoByIqcL-=x|O%8O$%hj1TyPW5k9WD^9dl6Rq*KwZ&*_TAX2Pv628YBKg>% zlOaGFNh`+~j)`#lko`P{tuYyl$ZB*Bring>SraUXn-?cs6XB)$;ppf-S z-*m#dRmWFGX?hMGLdN}7(JyN0ga6ydCAIZp$5G)|un4&%{`GO`%f;yZBuoZwyL6JY zoFBr`$nTE8r+zsDH#pf6vMVaQp`Jux7G>%K&6w2!DGd}(HE*HBxt2^C9)|Oicr8-A zrn^?fnta0wl~>3&T@eTr1LDBeGNSzD^i+|Nhwp%@L0Ne~Mp90g>2b5A@>KV=KZ+qx z@^}!{-wP%DjK6@dmRN4CNTEg6OBTJ~Hq|1O=0mE(N&k#{m_@Vme@mVUs zd^*SH5)3Dm*cA+eUgpt29m|3`7M0HI&)l$~9M4>9$1U$6mQv{_y78BP^DI5bd}6u< zJj2zo4&EbJfGa(PvBXWd-$JK)M$@2Y2C`z1LR>g=WDMn`51`$0`n|cA%WcH`?OsT5 z8{njgxlqB*zh_YJX*_I4M8M?ohAt(63+Ky8AihymQhdC-3L9Fu+0v8&)-pw6eV7-I zb{I0Al$;!VJ5*-FK5WrH*E{y#U(vs%ZJKf2;=%eGz6+T>h{qf1VD*h^@Ht2!87SA_ z!%*YH@|;RL_~N5<67Y63dzEiwn5GR6#`qX*9!pL)Qo7BG@#dWNap*_BUgzDeMg z+V~`Ps&U96RoC*9gjlfEyAnO&gBp|*v4K{57f#nQD9T4M*XedG)8l8hTY--KP==1x zul6Y=)p3<7)!Ep(l5=yUYxGUks#L3G`!=`inGdYXTOaUR2ReQh6~U9*!?ZogSC7Si zr5eyG8J#?kgC!s(s6ED^M3e%fkpw?9Nug#TUO9?5?ajLYnfPNu@2fok$_LhlUW|b5 znNv>AjhaIT6&Xy86~J;u^l}nrd8Gce`|?FES!AgJ)000#t842I9)9)cae#l6{)6AY z?yRnnR|vR3s6JN};@5nJ3Uqus9moo<+1k&+`kSRMkADl@hle9po9gW}i{EW*B++F9 z1B9RoQ7tyLv2E+uin(o?#qF&VN-B@=gEqH4+db+fj#2;>ftv$967HzhviCGg$Hum2 zl#me%A$Td%*NgGDI`l%+ef|f%7IKVm9o0kfCVlE8OyA>a+b|#Q%Ta!FU&b(`69JGP9?y_@nCS$ejM`1p-b%Fz}z)@|-jWl<` z3!TYFc+JPnc6U0azUu8T3h&rgM?d_X`s(dE#xrzxnAF`+$BQ*HfOS&SfVU^z7OLY? z>*!|KUqZa`aTz>Cjm&~@`C0=WRC9?#thilj|02~-lVWP4I3dN~U?XG$AubXakKhD& zjEsaY1|l826aT8MIAZA1HLb&iY?)yZq7ikiF1FJwk`}MU{6;R~XM~0@0t^%kKBO5v znday+h&MIZag1BB)4VZ};=*#4rPJZrWLl`k;j0x83PD3Rk)4Ho?jL2;oHejwi1HLc zp96KV2D{&QlDj{Wzmv{r_e0qz%NMyK?xO}iTwR7)be00i0LTXH8vx+7Mx3)?6I2HK zDXu0nn$mrw`%r!s8h#M2N+YrRelkj7enQB4c0QfldPH9DV-!_a0DfpM49dk7_NiQ1 zs|_7S1NB2F#IhK@^t7Nx^$&+X>^`T!V!mg+>h8`i+kL*qnFDWaH8Z%l-3D)deu;y_EJxjJHJl8wx~JX6|2N)FMmFRimQ z?4OZ2ZI|!k^fuiUiGO;%uMi2SWxap6cn66N@A!EKn2@Wg^y8YkR%_)SAE;~fp#0-w zb*&!rkZ#ouhFiZuAEh2N0nR3j<)^@0bGzff5ODETG9QzrtGGGdKU5hh)XTM0K$q0T8wi`BJ2vM$L1-&VUJ@Is-<$BE2!M9wLKnPD#?uw*zpUnp+$ z5TNU_wam)*oqX&Z!dcHBz*k;}89j+E-HB@3;pK0o;CTyJZ!zs7a)as#AU~({?kEcf z5dtF6QDUYi6SiG1Sg$8U2Y_6fn3uP2qe5s~?oLW0N!is(Z*t9{H3y`nh#O|arB2r= zQ~>X?#E|)YV)yb+G=L(9^N=zb9o47VQX~~cNN^w%{lH7#akpYW*r@~5!zI#V$v6=v zk_R6Ryw0iK!jzD3Pp28lv?PT)vE5s6z>X+hT5gN5jF*$6A+8(9T0kx$eSXmpi#k=qgC(+0& zR3|VQ>`Mpq)N@7=*0Q$`TI%vF?w@hyN|Jh_sU>@lJS=9xvl_%i6tGKpvsvh!38V?% zCX5BGLf9i9hAuGtae=^4J|}6T8MtVkjWQRl^QKaUjIGHgW~wceHM1MhvW0vjs2C21 zS%jQL7Cn}-r~(In@Ur{ac<|ez!LRgn?+>ZtWmxyMU=?uf4(>Vy8ZL>|ueT5ndJ7w> zw=n-L&WFDQ8Uwo)yr1?4AA1Xu)Z1HdjED;xHoCpHK!z!PrL)OQO%!ojK1%r*^cpFZ z+56NlAY2LYn%F27_ru(8;`jbC1xiP8g;%cX2OmwWy;2`7pLI3f#J!8t+wt7jRuD$* zE&kIKA{wi($l`uY8y4}oqW9>dl(L_emuE!A5ZrUu-*Ham91w_unVI@VdB!YH`SlJ1R z)7E74ph+Vo{kkLIzzZ;1+TvH`S`bYWSXs|bFu)nOa zxsx*u>=J6|jeE)1Zi|iF3HZ$DBD-WuA;fCYW{qh7iljE`So*>I(iE>3Q|h1ls|BxHo*f5 z`jB!_&FQTsJsg~J zqpYk86pyj#7wI6Ko{T)?E3MWaIG`G?1-_}F-;!h+j=Fbk%c~|Wy6Ko@5Rh`BqmB#q z+A%B%TUqN9rl0)7X_fYz2$20%&-j`J(&Vm`{0d_2QU)dYdXxsKtVGOWstn?W4F zj(i7zMH{YI?^kYQPG8GVXtuFO^r{m@%#RYB^OE%b zy&W>`hSo4rHOtGr|+G$b+7N@V*rzLn&oFP44J0v`d3a_8zD;(asVfuna`8mDxZf)Wy>P=x)S>D zX7*4OcSX)DPIL}d=WrV_%poN+Ke0lTE9$~hSJFssQ`0A-C`UC3^`U2YN4f}o(;bpV zw?-p1ot$PV`GOBZPNJZArb>natR7~$@#kpD9I6@94yPaJWMi^j&5DjlTKLTAOLYH* z=mGh$#vFNi3Xw`QO>r)kFMdB%Br>!2!~9Hvk`ZPpB>EdxIMBM~)+#~?r7_ubZ)NKk$M((Ky#g#guAjxG}s4H)8?m_`Cr*xgzFM=3UOay z$Tu>ePcq<#w!PltvuA*I!^~(k42pY=bISdQL4sFd3{vqa2t)uu19>?PacJp2mj;kH z46vlhG-Y)ocO~m-1OlF33d_sd;sv9i_SfP4#GkEc!%UpF@0J$JDuVd<{z#sNED~cW zaiNk@6j&b_Q;?!y<0nqQBI_cET;L4mf79sTXyWl;CR202%_GEv77LIBxwwj47U%~Uj+$Ah^`U`}kj$jca6`B{Y zwp|Le>GHB(meMv^EK?OF2!POOLh#=(aUtEOagUj4awJZhlPSxRM0bHP*5#7S?mC?s zrLCEck4nguG&z^MlQ=hmOyjbiumXBjLj({;iI<4NQphfxd++kH z*HhP^T8|O(P!9_}dOa8*MvWLXXyXs3VFn{Z;MgzaLdD_=c4{J1jfd$u{l_d7ub53wYe5PP;(jSt?HlTG)r?BRQCtDfh8h8$9Mu$QgN@NeG;bv< z(c$&c@+ufaeG1YralYnk)K8R2wJgcSqm1qq`B|F62P3%xqUuBYME|dy$bni1XX&s8 z(unPK5qAC9sXgF^$4# z6zua40m0F1{pzxzkeQJPdbFJ_(q}1%F)3xbh9!kkLM*!qbEec^0+yHIt<&HG#1`Vj zp72U;aLlx~E~Qb@>Y>VHzU|uH2{cIyHDbkQ^S1f@PKMYWvion9?3#xcBoiSt15#!D zELZA?`%$GaxVMgIjVRFChH)(hb;JI4=KlGlRDJXIi?QthS`OSuBYLqH#^Cs)Nz{=y z|M$*Brf$tS(Qi!&=XFVkRM!uG%?0<~KAWEhb#qc(k2Bq^pVJ*T`^W8Dpx;*QhdE+7 zOh(DNxaa-By)f&7-xbKaJ{RP{2fMj7%EP>B^I;xPQyoyv8*m=HvZSRpim6@e11WjVKVdj~bPBMmJITB?Z7rMr?kS z6yba6I22q~iv*Ox-1ME`OmEz@tizybFbTfQ*1}M@<3jDb@jP_}4#J@h)6)6JOje(< zz=63#1Km3pW2iB&4xfvQq?hP@S6(M1>v+}5Gh-cpk+*B0gDf!v5%dQ z%lzkyhuoa}^!%{vw0TJDW=1#lHAWr7?lGlqf$%SyV&HTuc}=%|n2y6F$f9sS8Z}?1 zj&~m9ihINVqKnx<7N-Dl*UixyVpe&lK}ah63y6V8OgVNusA$m3Ugm~4nyr7eoeuoA z_PQ@6)D7nf0?)72@vH6*+Sz?|XgfkdiIs0V@Pid=rcdp3VHX3afwV=L?vUBDrjw8;hfGHkkplfy9krZQWOUavL_Mem?0Z3*< zzfjZwqEbUJ5+@P=O&sa++pyr@hQtlSbVI#lB)^U*)q#E*M%988cZP;~$tWt-aGpUT z(=*^6h9mgZdr6up@5h&iy#xm`%twvWI2sLFYKekXmq7jtI~R{FUD0dV2uM032BZZl}|+4TDlX`!AUcJ*i)8B7nI?4#%5d1SuwS(L2RuQoGS^TyO!WH!wAb_&=G zlz@Y+H_sf<0-(UMuFV!h6O$;cvI*(WO~) zCSAJSN{?5svOirny#(75s05qxeo;$&?&;51|7ZOSIkf3J{D|hWbczfPoBIL#C$wT( zTR-qqWC7z(BdV&&z*Z7bMlkCwOA7WCJSO!dD6bCnvDtREB6{W<#LOd#*&IQO}A?7s|p{{TWIQq=zJ6XefN(l_nKFR*Y5g#v|GwjCPBg`4JPv888oUCuWs&ivn?QD#R~bm>-$4hur}Kb%%Ofpt3ceonTL~8i1@CTCL>D*z z&P9^uFJjCWR;~3DUQR5CHl^?Osf6(CiggL-6QxZ_6_?ec^-fEzHC^0&XP)88%#8Zy zzH)|c=lVBf>hmI-_F>ABg$uNpUP9m4TM*EyZMpAqPQC6 zu+1oiS=PxK7;96EW)n}|^7lF!9`1F#+zT#IzEz@Br`_>VKf`ATd8-l3tmL; zi-T|&J&%)fu5|}FyqKTIlg-sm=Sw?4_=;&#NOqAQi4RjY86U)``4s=Y6O6#Iv#nss zA#NxZU&vs!VQ7*+qag;(c0;8u1a+8~8e=an`5J6Yt*ve55iMvGK0Mff@d=X(MdmS5Dux}HuG4r&I%;1+P8%v#FzSwhf~4a4EVrbJSnNX01QVBJOYk;aU=5{^c! zo`0jEBMN@fs4H4q{lr$G_x#11AFj~UwX+j z8*Tm()=+elSI1kBjbO$X)W2Xgg1D}?px&u3zf^Bkkl4rXzEOkJkh{|~Z!R{hDUOSY z`WW@kQv9Y%RxDmZ^o{{oY|JVhWNOJjZe=l@PgRdKNby-5y~ zI~1_SJX-IRq(0w9f&A&L=|sZ(RpWGJ)LpmBK(yNPyUzT z(q1teSu_bJ97Wok9V2})4xIAUsA#t_#6)w34v4w+#H*y&>Tp&{W8Q*zh>9=~GD$i1w9X;RYKfZ^SUQtam8W zPfue@j~IsOGx~ZL#t+@&-hyfExsQV0Td)}DPAT%u_ZALT-{=pmhadVKN4!i9GQRTI zuS**6A422vjl6m-7GV^owm^PopM|7zL?bipFBp0u`!s~dMoB4M}g`2@>c@h!E;(szK%UiRv{DBOXz}Inz z6WQIEV-*3fiEqlYi53}H3jm2U8w%j2LRTr@BouX|x!}TK;Rp5Bwa5#GF+WiBy4PnmI?<0bzE9tL?2UTk0G}(5!>n+Z4*RzI>jV4x|!Enr&pA>Jvw`2hLJL!IqT3IFgT~xr9xe@C)MVTiiP2kxPW@!g)xP<25 z1JP~Oj5@!ShMl@wGvbu*ORo^HiMCPVPolH%BBqp2`9c@)#RbQ{MLZglB-KWU%>W0+ zBSLI-JQH5nm4IKCAbCgO4K>y(H9S$th22}6SD0>_RODd&P5GHQNm1g_nhjwqK^^mK zlxkzS%VWDoN@Z>erlT@xUdS$zdnCmVt#&$oe`<-CN;AOi`8or&)@eU<8l%s1wK|kp zd+5E;DPt8QE>~%*s+^(VE(a*%3Xbc2^&(lpVt1=n_^1oxRAIaZJ>60)@%1T?YTt zMiI%6HUS||ak!JoKO8v(kLo#;mYMMx6+^2f?Yk#4ScNa~6RmdZ#%f1jT8bi}n;VUu ztiu)eUMHYNy<|}z`Ict1=0vY|;m=#cDi}uU>y8sg;sloaw0Z&b8==^^G3dl|qwC2P zUD0kvqREsmt5SAW-0=r&kcb8b`O-M%opyXE;z}dhx?XyB`N&{;&l+~l)c_HXunes8 zzcA0AOT>u@P9kdVHtW}4xbmWsnRu}{%cA>g(yn1W3`IJr*@Mm{VpHja38WICAH4!ip(>h<04OLN zdOjvY;)a?lnqZB=d&CaO!3z2zq08Z&_?=@pDE8$tosM9B6G8)irH=pk?(5DMp51Iy z4b#-?{b^i$qrQFI`9f`45&pSt|OiAk4>-8}^bgZ>v!V&qf zMY_DR2HCf4WT|?tn_|`?FnrxWTkWLu^B^XMt&=OYx`xX68?{$RkDxj6M!E@yksymFTUSx~VlIfLM zVmGKEF5<933-Ae?PM`mPu4NmD$k+wq)FcCzm!(5!>~1wT95#g6JOzY4Z2*gP@}%1o z9GZS9O+w%nIzS=0T-py1jAc+8G??zq;NcQM@*v8ZEuWcy#(Ic zERq(1(V?pJr@(-tFE3jTJm!1zDe#t;g#`*3{pt*`%Q%t?u-q^{J#-P_ko4IWeEPT~ zHIa=RQiLBWbd;J7{)YYxj)883E@2@$qefxKz)PP{bTwkUvpS6b zT8e@@vJ-%ns6tBMOS&C1Tn??naS^0hFiPp4IIv@m7+3}CD@YyFY1WbvF&u+AXb&=n`%S|447&ds8>KuijduS! zylmo=&}^{c3J2){LwF&kR}YNlu44*oj-97o7{mtv;cq2ZYRcYc_hvxyKP>2L(1GRU z5&NpeZERLBC~#>v5a@lCNRQ2Ec0hS0EH9V*Vf6%it`};Or4)>w3@roTPcRFPr=ubU z2%*z|JDm}@YFo97fL|Kth7E8A*PUv3YvEl z0ZG!q&BPUdG;PH#NheAvWy5IJS-~%9bGq2Gk8>yM9U?;&L{CX z@%b9^-qHnytrXa@adIkruk~KvN7SRskP<{3mSrXucBni;UtV!6q2B*3YQb`XEH6JQ zk%9>41Ht7AJ+gZrs($#a0R}{B&Ic5Qc^k27?^DDV5?xkem4Li!z9$}!qXEtuI(3N~ zlHwB+#awQIiEzSn$?e$;TV?BGFN7H~r*sh7ya070Q8fhZxK@<3tvYn;`i1{7Le z9tgq*I7pKuBhe|yHq;Rn^)u~HFHxiHak4xKD%|LqR-nXZ!tsq7n3>K5l2YcQa$++% zj3yCs%80T%PWl-QzhjG_WTj{*$GAD5QX9 zuZ@>)gV4+|Y^Xsri4e|~kYIN#xU7^)aJ&&egD64(o@1GHj?pFp^^;^HSTc5mu>V6M#1RS*$EK60%4%GwTg{rytLEK^!aIe#EUcK8Xg{VjN3H zu|l}siR%#@^LZq4Uusd({Q?W zrI)n3Z(h7S=^qvdX(ww*)FGh8NUl{4KZ<-H!7fPH+AR_ixRS(jIps?ogny8WmL+Xvjo0>r zlMWO~+m@sp&|i?9UJu}c#JhL@+t&WU^Id*=SGVS;Pl{}GIDP2=@szx}{T=%HgxOf6 zUbEK6JF9&kpY@4pNH;_>R1%NOD6HOk6w2Gr9|$4Eb4TLE%cEV9tdbg(&!jGb;Fv)v zTEit|(+X?|B8d^iq$UG41eE%_A+R1#yg~Hqd232naPPvsV)?(PTf$Ng5-lKxez?%kz9W*X%9eee@bZ zK@vZQyOdgbOq{NmY8ttv8x@TuBN3KbUTnDh#ZqKx#w$z9Zd19<-MR}0t8ef+1f9=# z53S!#F46;COfOmVVSef(>pPzlPJev6c=`{kA7=;Be^~pt^yTqy5lO$Gg45ERt3|(i zEw#v5k&DwT-h4aF;&&SxNp#8JRc@qJjkcwNS6K`Us<^#%LX_AMehB30v)!X!vWVDT z#sqV`b=#Z)ZKE5WX6abs8?+-<@|b!H);DW@It(vWN`Gj~bf?u@HQ-$BT**ew*)F%~ z@M_OwUzZ7}KylvO0a)+niPRfAGHWq#$(zAJ?}s(+Q;6a|ml_V$S+yw3!M&ZbC{%kp z)J4yWw*eCIhU=R{HP<`WY=JzSTw?nNTQ?v?{LVyRRjvA7Na{QWF82>ZR;S;>-Pk@$ z(>$u$MeeN+eR_d=QRNr#>*3kp;=TjJ@fO@$Pb^Z6^|f#>cA`FoR7AyPg!Hj$nn~#1 z;qR|U^xi<;>%mR9Om+V}I2#oJq+0@Q+)!^G(#Gq3b!e-Wpf+I1A)h0WOUdPzZ08qI z7LdXK0Tm6@>wRrj=VlF4S*oI!e-0E;d+kWSVZ?_l1M zVT_z7x!OK>1@ez^njyI=8DLkOtG$<=0m~p?2xBqP`u0Jz%6k0C6mevdFUHaHCR zahUm8`v0-_uG?{2SGwr`eu_2ZxJ5FBBB@IpGqDruX7gB-Xi~DBE&7LdVD4-0W zNKt0?=wJH*_Wrxiqx9%^$qV!=obk;$*9}13DA{qk%jt%Sz`9@NnrmLZnGVW5439ec z^r8Bry0`PO87LKB4%Hvk{hg1Im8}P9{M(GTeXKznQjRM<@dt9RWfVKJ!+LjWqg!+6 z7P^Z+zc~!Bz(m0L_~;iieT!@0Z&Oz2mqv=Ev&*E&Gio1e7!10Y(dlk&9T?G% zoiPX;A#OGkd!EL_vKA=(n?u&>;+&_sG0WZL4W?MM;o;mmG)W3rZjV=sfu%^@fp+3Rc>iB$MUo?L71?__Yrfiug)_QvA%Z=q)%cx?+nY(qaHppt zDvQ7)4zcTq`*ZKvKlk*`n?DsTD4Cyqwj4y}_uT-upV$AM-3f=fib+{%UK|WO{~>`K zJh_P|+;*iz# z=tTyFBA$%Y2E$#45(J*z3)rQdW-_-nZaD0OuE-pVR^ew5Q8->kQg651XiT=57b-zT zr4pB!axRnyMzHM!$h68?KCt1{HFsJ!y^?%H)FlhDS^RPgRY57NLtRix&92#%bUDVb zv^HkW^7c!xkgZF0$Sf@?L+tXY869t+J8q~trnfG>Yt8v3yJ1rkm>@eHUfH*cvt3ms z>&a@R$WFje#V|A;#|oQHU`kE*PfzC4LX7Y2DRVkCnF_kzNi}y%)te@1g|Nq#e~XUI%GNch10|zuBNeJ({WrGHvOfiii2>9rfFf{}O#Xjy@i| z`uNMej}P}gKKUP;UNJfw)C*aVgTl;S#;H1bwfm*_J{}GWJ>>b38Bm8%@J`1qha9nK z@B>2SB`Njr7Z%W)@4G*}N^nWRx05O!PdaM-IXdA`;H)n6VD^EI66#pF+Rb9$RF1dzKr0-I!aO_?yGF^o?7Hb4g5frTP=_UPrn(Uum|< z7tU?nBQ~1N;qS=`#3?AaOYpI>NvL>9NAm7Wf?QC-A80%BlCaaH9#5wGmqVE!DV)Z9 zvx9FCHUu-|C*i3=vcveT%u!H;KN)}EQ5kFKxIX-Lpia*qiT2yClp5k3agz{`KYVJ; zL7m>!h8YX*M*THUG6kHK&r*F}<@iQ}pJyJib8NBOGrS_q?3?MOme6}{k=Jn}gVc|$ zKNb41sQt`ca0yuzo(uU;O}5>Iw@KW z9PpL-0K|Cqh|&f^eun!>9RQ2HS&VG%hNW{rud9kY8#>vJ6ByPq+}rv4zx|&Fl;y!x=4aN&mTeIHQ$BO+}ztgL^u_EhFIc2(LYJ-foED|qBK!y2aFdKmYwJD@Eqh}(8^eXyt6?OrJ{qQz7wt@UyHmF%Ro4eu#vJ4ynGb9mk{eypo0Iqg9v42#U2#o48 z`_rezsJtU}bZiQ;rFFN}rfi}G{=;Znnvpb+63~)ZEX~jW8)d5;BY@Y3G-Iy0gXt48Q)EuuA4OSwSEfov)HnD5WXD^OymRI8#KHzsx zCV6!ONA9B{$pK1B0hnfhF4ThHNMJQFG~H7i8%#x?t0(v9SCT0SE!qfxRGZ=mLdce& zk}8ru`k~)zA%+$eb#Go#w~XR5D~?aC11rYzskQm%4(Jnj@eDJ~4>_>TQBV&cYCFydfUq30$S2{Mi`N7#D(B@oZ1ifLN&2j7mpgsVtjdwH0tQnPpREiu5?D>>zR{i4h!5IylIF6-9= za{i4~IgZm*7j*O^@)P{i7%{r*@H1Lhq5)BXVt{ur#qM(YX*kG>hT4ky4`vw%IBjs? zVQgIG-psTtSjOT=7`e!Ba@%G#!MetjOgkjY(_La)yA;|6{!plM|yK-R2@*d|{!RL8#uF3JL zxsq$96s>kuZL6Bpjjee$_P>1nXp=71#*;lS$cf!rqU_bpH7>`v%U-D{qRX10znYtGyPD6}M|A9UC32^(%*N=i>5vTqz{o^#zfa7XO&z~gy@t04Z|M2K9FHa~I`Cne1 zP|{;PP+v+I6m@p;{OL(E&B^PNr;-3-JPFW3wShaC#AI5?{_i{zUd)51eCm@t#lMIe zYH62kIEtmN$j5guC9y}LvEXkN0a6_%RU*pGnc*NC0=*g9MNiJeqae&AK^R;aNOzLB z01ao7=GSWfaGzgEc)z395ecQ}NC>1+PEN_gZL9=XRnLC?j0SL{4&!SDJ9BlV^+oF0 z5Fl{IWRkMIIMv~4?Q60jYYafuy~uqymWaVz%m|RUQAFTskY{&^hl9B!GJ(fAhs8d{ zn^%wXyckgIbUFAY6O~_OF!HomGJGqLureI9*lBuUTOJn}#79M$3ucYCOryk}zTFQRST% z0I$t`7J+zCq>gjWHUlL|79wk=XPM>R7$-76ZJU`c$!M(Mbew130^fd+bzHObDb29edF8G7?H@RY%aql8tzB_jmS{FHk=>1+Z0fO z%F(pK!ixgi(5TLEvYEP18CG#0Ser|mF(t`({>y2PUc+RU-{4|VDkCB0cQWhY%es3~ z_|=b%JD_8ip&;>%R}=v!JbgP!^FkN$;mLQZpW-@3FX%kH4#Mn$wHIGze~h7!2H4!ZuTCdR8&Uw!>NVsn1i2(YK97^9SA z=S6J8?|5rOZl&r~TwbUmpW^O-SI+@wV*$gQP75kxeF>CInTiS-ftVL(tg%E?wnMO% z0C6b-1+G_&!JrdmE^TasH4J8dYl~36P^$ElgysTp3R$njc_;UkYnq*{ttz-zxqsQpnB<^3tL%PsGCfv^_;C0W+qQ70~F_sGsQe0;u>QK48wFO-- z3dEqsr4Bxy(d4~LKzPs*@o7U8J-IFw`l=AHG8r4zK%z>ff#vq2X_5{iS<(!_gJOd; zN7Qm1q}pUmKnUgOqG=~1oVd6Y*gfbkX(*y_T-D$I*Z&T5qJz9&M&pv0k!?SvWOlPK zKdVc}8U5+P!B94`3!T~S$5ou>L%&il71d1RDL{^_SCB;`o!r_IY;Cwe)y5=v!U+7c@7*u?M2)lViH@G!NwtYOYip6Dk2GQLZsFrn7S#% zw&vu5mc#G49Hbz2SlgY}!E=csbCN}XDb!@9Pt`#|9z#$OF_klQ8O3>ARWYujipU(D zst&%1w6GW(&V`x$0}+Jj1PEKmmE~8d9t^cQVc{*~(DX-ojPrIN00B{1U8mYYD0aDR zB3XzDE)9fn<`6_4jpWfVixpqD`D@!3v)R1?nGB0~fI)em8mC-J+o#|#cJ&&yAtbC2}v}0Vq!`K{?$sVHfY~OaheP>R?btLbv-~13>^nGO)j;0 zK{BftaW~AH=Lupg@^4%O5>^W1Pb0}Pf5Tc>X84S+KHNSwHz`LNU{s88NRY;TTN(4! z+O)p8oyfba9-N3k!K4BwPbsk#QO;8_(=Ml+t zYYo8%!kle+FC^Wx=~WSDB?24U26-557Gt<0X!~*zF);aMb7nb?^JCFqa{VV4Q;IH6 ze|QzLx`Fn|V_AulLZ2sZak<8HoxS}5LG6IpM_WzltVsGJffgX>N0CG)X3ZNd@!8uS zj_VQ6xdE-Ko}r!-!tfFgnqyzLZbJnGm_0$XY8&{GI@TZHXhx3 zw5bplC@zw`ROgWRnM(m*Ts;F|fWKepN*bK&b#;1IC# z4BtRZG+%qh33vg8G)i<47yZ%o((Rj(chlZdQtSKCySC_m z6E-k{oc%JVy8=T&byTI}amPf9VWt;`6hucy`4yr=Y;&Xz{4_m@6Fa4zHOInE%+5x3 z$uy`hCpz0dV1hyBX)a+$Xb++p6sGA!XFT4jiV@GxHggas>GhIppqU)adV*JBe@SSfE+%)I-C$p@5+$C6~8R;w&G>>2);Fm3&=lkF;i^d88K<$p}Uy zjLFU+QSw3!ihN@H+hAab@DJbyr8wn^GecOfCxX%V;sKnQjSgEKTT8YQ!GK^K?bcW+ z!5mDhBFNN-U}9*E_NM&{?T%TK$OMOsD8|OpEo^2(3%}+77KjKnftvsaB&Bwl49uR% zxamscnLP+h$O~o73r2fk{>?@5oK`eNIw)bU=j(S{TJ2?y%6?ufbGw+IS;pH8UC=s) z5>u0$^s2yzpxz)Wb7~H~)f#{IE%(?qSQNYTR>N#_qQS2lG1u7am!nS^>R{pu+C)AJ zXK-n0gZenJ*3x>3RxU09t)EEU@u;AzaM$$T675^z3JWJi`T;JbQbJCejFU0 zkl;_tU>J+|3a4)itH-!jV2~{_o2j6hPsnCwbGO@iq#vr>am_}#Mku>q9Ub`B9dAWd zo`iO(>&~3K!F9)ysag;YFZQark|ku&?Kdz-)Unmu)}GBZE6X#l{Sbf(Po;u9(vW4f zesi0(Y$3GxT!6ee`bauST|9b!_Nl}Or+?!bahN&2zjPl*I zO|0Ilc&IM)wRgJkAx5XgM8hz9Ii{jL7o98=^|f{f6aYFGyA>mdfND&}^}u-T7MjAQ z2B#lt81^E#1nDK^6^$%3lU^`Qsyu^sfa&uWkD~BQ;IvVd=mJ~_Z<=M8#JM>e&A>33 zx|N@rZun%cNF~V?CKwkdv5N*ejh7UawB@ow60$dSDHNp;UVvmBCYBUA>E)!qwu(2? zII=J2P{)yt+q|%GGjj>M;wktfjB-CF8o@-a)t?x$JX+#`?e!qYvr?mqa#O0`$$Hjm#l35|o_7i*REPm&; z530%dog&{;`7JB$tm|27?5Q*EMZ{*OFcF}#pOzH`m}IiQr~c<}cJJ+Mk8|}~^_yM# zfgSOi-9ri64W|Kffu#aqWji3_eO#+0b|(A9E@_NZcQ0Y}j~FPBNyrRcOPi`?rp;Nf z$ihz~hcS09Qp)a;A)8gic0}7EYZ51TmG|?s!@99?TouXNPT+1;OjGzS17bWL7!4b2 zplN$^kh!fb%dIRPrdjO|Q?cB}E?2$*%f+4N#ItEGJF+}GypW&8Fe19{xD|<&_YKss z?TfS7{HEqLXm|7Trj06N?Sc3x$K7|X8ky``Vw@3v0ufd?l`X`c(6NT-JbY)ZN!P{j z!B=M^RUL0&}!=Lf8tp= zdj0^cl5J6^7P_w!_-^v5B{2;vIE$F#08?aAHu)6&s?nFSLR0|zn`5xREVF%F0t+TF zptK92tBzTvYQEU+iz7up9}E4Sr{kQ9P=gZ{<*2 zcs>JGt=)o+MN%u2B_b2>g1#u8x9W2353SA?^&w16MTl zT1#ZnBtVD4VBuOIJJ)R1*;UQUg}T4MZ>)Gfp=m*4JWUJ_nn5)dkx@JGfAeZ?OU-O2 zz2}hVrXrKZtR_1h)*tYe^C4Y!;fUuo*?AVWWTW$})~Na%`3{Lo)>O;l)#88gOlZsq zeWYH)PZl%@fT%cY{*^e;TaMJ!mKO0|VZ9a!1eWWHD`9(nVJy?zxi;q_B+0QYxzazcg4%f>@sVs zoL8^6;;hQ62lXHf_ec(Z%M~XP;IAW78iyoWvJWQr_UvK;EnWL6GpevvEA{e`;>~E( zND9I?FM~#+-dOG1s%CV}144sG z05#9YNxxjRjz(@KEHD~2FTKSpIu9*=m&Smd@5i@2?xoDzl1!7|{+LBBZR6XQF|1z_ zQll?DQ?}|_ULpeCE6-Jx>q2g@?&Yc#`59@ZXa)igSD~BmdR(=1lZmKhU9~C&TZE%k z3->dkg6HOMT0kdpd}73i(-Quo#?5raY8tueY@x9aKY7cVySXC!b~enzCCAfLxGx%X0m9!ys{$A$0hI!%m>qhEwA;^CkC~?gQ$&`rtJT`b%Q{SBYHrPKO)nvcV;V|k4ap=0 zd$MXzXO_afb)S{@*}F%AG+d%gm(&$%Ub~aT6-Bn9ZI^|lE`qGwU(mi#X}d~&E{id+vs%~|zR1XP z%T=oIGnrd93593XlIaShZP9kFRTJbwJumEwnKg-`Y?W$UmWIl;?)xsjIj17s5mRk9V8f%VVvfgXK zk@jPy)kaSHGjeL5bs6aXEE<|-!5*5(k|ldN zjQPc*q^~E+d)D85 z^fiMvh7zl`Jw6Vm1{#LslLdT2t-?l5;ePqG`0J2e0{g2vuE*r`3=?iqZ;(5z+kI-( zS?F8If_dEh(Dr2=nfb(q6EWsCC(8mVfVMjeEW0lHh7ZJ{3*bX~% zOqjs|lof~4yp5DE2deXO&F-PX$W*xPvJ#USv_{ECLnQ@0dJq{i?pxH?RtQl_^Ipk& zsoafJ;O3ySVUpceD7w-b3%oG6+PcoarDgSnM#xa)(Xs5fwbffMg$9n$sN`K^Sv!ly zTUR=xuyA#|Po@b3P5|KfTi5HAK$V%lNj#pnjJdCI$OC#xRdX!CU_?AuT8 z>;h?~<#Q8Ni21|@M%e9I(JY5uw)kolm@Gl@0xxGavc-&Bp%tfT%Y&r7{pRgJuCCznnXOdIK?itDrGTi!1tD{UFlAg8qxF(T5S z8mKP=_q`R@T}$?MO=wW7QOUkX&9jP_q2UdxUs9jdsI#HZ`obx(f(qzrx11$WqmoA6 z7E_|2GOLwZtsXyHsKKg>vtgmy%kzu(WSg%{F{^RTHrw{Ray;5$zc*NDb1b_eR%}6g z3E`3Nst;^6mS5tox|XFK9P%dR?UuExXWqK@>kv^InfTvwE%Xb3K1JtLhGWx~Qu|Y$ z?S&=KbWkE#de+=!{99>wVut{vx9na!K%qWPJWtI3gp;b>=Qe-qrS0ASO83nPr>1tN> z6g26>G+<^?tc}9Q8I6E6=~91~R?IGoZBXg!jCRC>fn*ew#H2{Fell60C!N)lxy6x< z+F&3}5vbTBlOVA9GYXXV+tO7y6uimox$bDgQb^;t za&uHqO**F!Qm-kgt@0Cm^LDniKlmWK+89vWc4N=5$Ea=ZdYfmTP*Q-n9NxAybIJ=h zpft?rG3|ANBs^rA$)T@rImjeET15^|!4+z`ti&l4yGzTKFVxF(qA3Z>U_iLS-ILfJN`-klnbHUjC{IC?>xJre=(`04(W!>8Tx zzzfW$)E$I8n)6wrPa#D;P#Sxv69~qfC}cAukdgS{jmL1@%KLYrWzc3<$&m%rq!1Dy zKcDH#-)VTr2cFIy@+bE?WBs}Xc2?Og!wovgE+Y2*hwHp?J>}3T0)gw0rNkTiTMkrc zBfddH3e7wRA}NyLkg(_|p5b*qg%X7$8SeR9T&Jc6=!BglsCj{+4FVT-0>d5#Msd*x zJ0{Smdoe3ep>04dNMWZ9riB8qg^~R@IB=l}52;L~|51BvK|N3#fLQ^udUi&kN*jR* z5tAOvfnfY7*g-lSCK)H57l1Ghdg4b>%p&CnUa-1TikdbTC}RVGVa^(O2535U{4s@o zhB_WEb`hM7gM)b#7zCvrCje+B9FHKo*M)fy{3m50dw?gr9X1$fz%F?5F5f)O?swG- z3QjYeVhF?(pQ8-`SthRH)9gW4oglD07bRtTVKN?eVTwCJV0#)D#{c=F`ef(hg`swW zm9u2XoxOGRoOSe^b@ZI~iJmhnP|2*blBnDqn6NV&28#&|hbZAAcy@e~FrtUs#773G zC)mR?HZV{4jCdWG`DeBG988E@;03Dg{b>L16H^}&V!ko-&4H7kz8+2S}33nqC%1O|K3wS`@%M_GV<#}b{H9WUXmEnY$`T*5YL z^|`1;J#5B5IBSo8U@;vT;h&?{EG~RzP=mAOf*LHYVPSr33waeoRz#rv13*+Llr z<1uZ)LPP)o&s1Wg2~@gCS9Z1_H&*2id<5l4TtmK?Mb7FLr!v30+M`WdI?2Z3m##9Guw50 zNj6PwfW9_>0Idif7eu<5w94PjhHmSf095`g*sjPIlM57GIB)~D#ATV0_C?ZrxbryS zQ^$Bdr``hIwBEd$%yy6JBSDds4|Q6?!gl-{pa_V}+G}&?Up~aOagY=+((8G^ zqZAfHkRP!2eP(w8#aLN6jmv6ruj?*?OMr(G2|h1$IUpd!_vxL@?#$S|gt+C$?zK^SyQkS5t6=$CXTHwHo8%d6`Yd(M z>N!14PZUL`8QQR?+B2VK1E+i4lW1gR7>>+{%aSZ$JrJRh7F<$}aIM7Xl2b07i6BnJ zc`WEZf@{d979YXq*Z4#s#jM-BPtSbE`r0+$y(o!k5&o3K3)3LfaoL{2((T;8iI zzFz5gdo;SL}G(c2IYvI zmr-(Fg;T)8L~$V{bcRH$KuAXHjv-%<0!>zq%>@qY@Bj9H_c<(_54&z>`%i!WxBpL) z5%LhXdZ4D6emkMqEa^2mjW(o+b9Sz;D3&&QaHaKyU&51QpsqAW_CO>r8A01)M9K>) zO!_0Uvg)Yhr1lPlIxz*cqQJ#Gv!<+XwZ1@fPXqr&afP6c>_{Ltb_rEgk;FqyWyACl z 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%0D6D`-ZdASrQP9OimVrY6mqmXI2owz@k-Eo#;# zn03z$MGL%}xoN4r#kD&o?ARbJOcm6l*Yyv%Pi3QoYdGurPYU_*V2V2!Z|poUCi-Gj!oZZ=xoA zsFgY8BHDsDHvzurS7>@ysuL4AUa6NxWG!2ZnF_XbtWc@;HLt2|X+s37T&?n&Bcu;T zmYRM9=qpo``5gA^QqvC+y$v;7V#|)SAJFqJ!Bh>%eoIsVxt8gPSFLxYn#D^ysIg5p zEz}k9Z`OfFUzM7Ug}O2|{Rq+<<(p+p(@og6Le%K(bxi@a1i0l5gaWmw*`#cCQzH?p zH{dX9coH4{^fuJE+%m?rzB%uF2aNUAskyPZtqvsYt5dV9k992?PYZy$rQLCZ$kDJH zDo-mTyMu47EKp$8NA3 z+kTse`@aw30fv*az`@nJbOs>`2?}gZ_cGPc7Unt#JFanQc;L>{a^VojZ4E z@m$Q#_6ae&CBtl=>ats!%l1huyCtw}AB4PH0CM0CzaC@~WPvRpU4n74aavFM@ql}P zFcW!9=}Kies$>S}>-K@I4foX*gIc!_65TC8bo=nn-9kUN5A576sB`;}&E3K^Lsw?M z%-iS2oW#=anm1ZIPUJgXJB~=dYx!GbaBfwDvj+NODrTFmhRb|er-Fe`#(7t14~F}$ za≺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