Initial commit
This commit is contained in:
288
skills/nav-stats/SKILL.md
Normal file
288
skills/nav-stats/SKILL.md
Normal file
@@ -0,0 +1,288 @@
|
||||
---
|
||||
name: nav-stats
|
||||
description: Display session efficiency report showing token savings, cache performance, and optimization recommendations. Use when user asks "show my stats", "how efficient am I?", "show session metrics", or wants to see Navigator's impact.
|
||||
allowed-tools: Bash, Read
|
||||
version: 1.0.0
|
||||
---
|
||||
|
||||
# Navigator Session Statistics Skill
|
||||
|
||||
Show real-time efficiency reporting with baseline comparisons, making Navigator's value quantifiable and shareable.
|
||||
|
||||
## When to Invoke
|
||||
|
||||
Invoke this skill when the user:
|
||||
- Says "show my stats", "show session stats", "show metrics"
|
||||
- Asks "how efficient am I?", "how much did I save?"
|
||||
- Says "show my Navigator report", "efficiency report"
|
||||
- Wants to see token savings or session performance
|
||||
- Says "show impact", "prove Navigator works"
|
||||
|
||||
**DO NOT invoke** if:
|
||||
- User just started session (< 5 messages)
|
||||
- Navigator not initialized in project
|
||||
- User asking about specific metrics only (answer directly)
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Check Navigator Initialized
|
||||
|
||||
Verify Navigator is set up:
|
||||
|
||||
```bash
|
||||
if [ ! -f ".agent/DEVELOPMENT-README.md" ]; then
|
||||
echo "❌ Navigator not initialized in this project"
|
||||
echo "Run 'Initialize Navigator' first"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Step 2: Run Enhanced Session Stats
|
||||
|
||||
Execute the enhanced session statistics script:
|
||||
|
||||
```bash
|
||||
# Check if enhanced script exists
|
||||
if [ ! -f "scripts/session-stats.sh" ]; then
|
||||
echo "❌ Session stats script not found"
|
||||
echo "This feature requires Navigator v3.5.0+"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run stats script
|
||||
bash scripts/session-stats.sh
|
||||
```
|
||||
|
||||
This script outputs shell-parseable variables:
|
||||
- `BASELINE_TOKENS` - Total size of all .agent/ docs
|
||||
- `LOADED_TOKENS` - Actually loaded in session (estimated)
|
||||
- `TOKENS_SAVED` - Difference
|
||||
- `SAVINGS_PERCENT` - Percentage saved
|
||||
- `EFFICIENCY_SCORE` - 0-100 score
|
||||
- `CACHE_EFFICIENCY` - From OpenTelemetry
|
||||
- `CONTEXT_USAGE_PERCENT` - Estimated context fill
|
||||
- `TIME_SAVED_MINUTES` - Estimated time saved
|
||||
|
||||
### Step 3: Calculate Efficiency Score
|
||||
|
||||
Use predefined function to calculate score:
|
||||
|
||||
```bash
|
||||
# Extract metrics from session-stats.sh
|
||||
source <(bash scripts/session-stats.sh)
|
||||
|
||||
# Calculate efficiency score using predefined function
|
||||
EFFICIENCY_SCORE=$(python3 skills/nav-stats/functions/efficiency_scorer.py \
|
||||
--tokens-saved-percent ${SAVINGS_PERCENT} \
|
||||
--cache-efficiency ${CACHE_EFFICIENCY} \
|
||||
--context-usage ${CONTEXT_USAGE_PERCENT})
|
||||
```
|
||||
|
||||
### Step 4: Format and Display Report
|
||||
|
||||
Use predefined function to format visual report:
|
||||
|
||||
```bash
|
||||
# Generate formatted report
|
||||
python3 skills/nav-stats/functions/report_formatter.py \
|
||||
--baseline ${BASELINE_TOKENS} \
|
||||
--loaded ${LOADED_TOKENS} \
|
||||
--saved ${TOKENS_SAVED} \
|
||||
--savings-percent ${SAVINGS_PERCENT} \
|
||||
--cache-efficiency ${CACHE_EFFICIENCY} \
|
||||
--context-usage ${CONTEXT_USAGE_PERCENT} \
|
||||
--efficiency-score ${EFFICIENCY_SCORE} \
|
||||
--time-saved ${TIME_SAVED_MINUTES}
|
||||
```
|
||||
|
||||
**Output Format**:
|
||||
```
|
||||
╔══════════════════════════════════════════════════════╗
|
||||
║ NAVIGATOR EFFICIENCY REPORT ║
|
||||
╚══════════════════════════════════════════════════════╝
|
||||
|
||||
📊 TOKEN USAGE
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Documentation loaded: 12,000 tokens
|
||||
Baseline (all docs): 150,000 tokens
|
||||
Tokens saved: 138,000 tokens (92% ↓)
|
||||
|
||||
💾 CACHE PERFORMANCE
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Cache efficiency: 100.0% (perfect)
|
||||
|
||||
📈 SESSION METRICS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Context usage: 35% (excellent)
|
||||
Efficiency score: 94/100 (excellent)
|
||||
|
||||
⏱️ TIME SAVED
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Estimated time saved: ~42 minutes
|
||||
|
||||
💡 WHAT THIS MEANS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Navigator loaded 92% fewer tokens than loading all docs.
|
||||
Your context window is 65% available for actual work.
|
||||
|
||||
🎯 RECOMMENDATIONS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
✅ Excellent efficiency - keep using lazy-loading strategy
|
||||
✅ Context usage healthy - plenty of room for work
|
||||
|
||||
Share your efficiency: Take a screenshot! #ContextEfficiency
|
||||
```
|
||||
|
||||
### Step 5: Add Context-Specific Recommendations
|
||||
|
||||
Based on efficiency score, provide actionable advice:
|
||||
|
||||
**If efficiency_score < 70**:
|
||||
```
|
||||
⚠️ RECOMMENDATIONS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
⚠️ Token savings below target (70%+)
|
||||
→ Check: Are you loading more docs than needed?
|
||||
→ Tip: Use navigator to find docs, don't load all upfront
|
||||
|
||||
Read more: .agent/philosophy/CONTEXT-EFFICIENCY.md
|
||||
```
|
||||
|
||||
**If context_usage > 80%**:
|
||||
```
|
||||
⚠️ RECOMMENDATIONS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
⚠️ Context usage high (80%+)
|
||||
→ Consider: Create context marker and compact
|
||||
→ Tip: Compact after completing sub-tasks
|
||||
|
||||
Read more: .agent/philosophy/ANTI-PATTERNS.md
|
||||
```
|
||||
|
||||
**If cache_efficiency < 80%**:
|
||||
```
|
||||
⚠️ RECOMMENDATIONS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
⚠️ Cache efficiency low (<80%)
|
||||
→ Check: CLAUDE.md properly configured?
|
||||
→ Tip: Ensure prompt caching enabled
|
||||
|
||||
Read more: .agent/philosophy/PATTERNS.md (Caching pattern)
|
||||
```
|
||||
|
||||
## Predefined Functions
|
||||
|
||||
### `efficiency_scorer.py`
|
||||
|
||||
Calculate Navigator efficiency score (0-100) based on:
|
||||
- Token savings (40 points)
|
||||
- Cache efficiency (30 points)
|
||||
- Context usage (30 points)
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
python3 skills/nav-stats/functions/efficiency_scorer.py \
|
||||
--tokens-saved-percent 92 \
|
||||
--cache-efficiency 100 \
|
||||
--context-usage 35
|
||||
```
|
||||
|
||||
**Output**: `94` (integer score)
|
||||
|
||||
### `report_formatter.py`
|
||||
|
||||
Format efficiency metrics into visual, shareable report.
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
python3 skills/nav-stats/functions/report_formatter.py \
|
||||
--baseline 150000 \
|
||||
--loaded 12000 \
|
||||
--saved 138000 \
|
||||
--savings-percent 92 \
|
||||
--cache-efficiency 100 \
|
||||
--context-usage 35 \
|
||||
--efficiency-score 94 \
|
||||
--time-saved 42
|
||||
```
|
||||
|
||||
**Output**: Formatted ASCII report (see Step 4)
|
||||
|
||||
## Philosophy Integration
|
||||
|
||||
**Context Engineering Principle**: Measurement validates optimization
|
||||
|
||||
From `.agent/philosophy/PATTERNS.md`:
|
||||
> "Measure to validate. Navigator tracks real metrics, not estimates."
|
||||
|
||||
This skill proves:
|
||||
- **Token savings** are real (baseline comparison)
|
||||
- **Cache efficiency** works (OpenTelemetry data)
|
||||
- **Context usage** is healthy (window not overloaded)
|
||||
- **Time saved** is quantifiable (6s per 1k tokens)
|
||||
|
||||
## User Experience
|
||||
|
||||
**User says**: "Show my stats"
|
||||
|
||||
**Skill displays**:
|
||||
1. Visual efficiency report
|
||||
2. Clear metrics (tokens, cache, context)
|
||||
3. Interpretation ("What this means")
|
||||
4. Actionable recommendations
|
||||
|
||||
**User can**:
|
||||
- Screenshot and share (#ContextEfficiency)
|
||||
- Understand Navigator's impact
|
||||
- Optimize workflow based on recommendations
|
||||
- Validate context engineering principles
|
||||
|
||||
## Example Output Scenarios
|
||||
|
||||
### Scenario 1: Excellent Efficiency (Score 94)
|
||||
|
||||
User following lazy-loading pattern, cache working perfectly:
|
||||
- 92% token savings ✅
|
||||
- 100% cache efficiency ✅
|
||||
- 35% context usage ✅
|
||||
- Score: 94/100
|
||||
|
||||
**Recommendation**: Keep it up! Share your efficiency.
|
||||
|
||||
### Scenario 2: Fair Efficiency (Score 72)
|
||||
|
||||
User loading too many docs upfront:
|
||||
- 65% token savings ⚠️
|
||||
- 95% cache efficiency ✅
|
||||
- 55% context usage ✅
|
||||
- Score: 72/100
|
||||
|
||||
**Recommendation**: Review lazy-loading strategy. Load docs on-demand.
|
||||
|
||||
### Scenario 3: Poor Efficiency (Score 48)
|
||||
|
||||
User not using Navigator patterns:
|
||||
- 45% token savings ❌
|
||||
- 70% cache efficiency ⚠️
|
||||
- 85% context usage ❌
|
||||
- Score: 48/100
|
||||
|
||||
**Recommendation**: Read philosophy docs. Consider /nav:compact. Review CLAUDE.md.
|
||||
|
||||
## Success Metrics
|
||||
|
||||
**After using this skill, users should**:
|
||||
- Understand their efficiency score
|
||||
- See quantified token savings
|
||||
- Know what to improve (if anything)
|
||||
- Feel motivated to share results
|
||||
|
||||
**Long-term impact**:
|
||||
- Users screenshot reports and share
|
||||
- "Navigator saved me 138k tokens" becomes common
|
||||
- Efficiency becomes visible, not abstract
|
||||
- Continuous improvement through measurement
|
||||
|
||||
---
|
||||
|
||||
**This skill makes Navigator's value tangible and shareable.**
|
||||
120
skills/nav-stats/functions/efficiency_scorer.py
Executable file
120
skills/nav-stats/functions/efficiency_scorer.py
Executable file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Calculate Navigator efficiency score (0-100).
|
||||
|
||||
Weights:
|
||||
- Token savings: 40 points (85%+ = max)
|
||||
- Cache efficiency: 30 points (100% = max)
|
||||
- Context usage: 30 points (<40% = max, >80% = 0)
|
||||
"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
def calculate_efficiency_score(
|
||||
tokens_saved_percent: float,
|
||||
cache_efficiency: float,
|
||||
context_usage_percent: float
|
||||
) -> int:
|
||||
"""
|
||||
Calculate Navigator efficiency score (0-100).
|
||||
|
||||
Args:
|
||||
tokens_saved_percent: Percentage of tokens saved vs baseline (0-100)
|
||||
cache_efficiency: Cache hit rate (0-100)
|
||||
context_usage_percent: Percentage of context window used (0-100)
|
||||
|
||||
Returns:
|
||||
int: Efficiency score (0-100)
|
||||
"""
|
||||
# Token savings (40 points max)
|
||||
# 85%+ savings = 40 points, linear scale below
|
||||
token_score = min(40, (tokens_saved_percent / 85) * 40)
|
||||
|
||||
# Cache efficiency (30 points max)
|
||||
# 100% = 30 points, linear scale
|
||||
cache_score = (cache_efficiency / 100) * 30
|
||||
|
||||
# Context usage (30 points max)
|
||||
# <40% = 30 points (excellent)
|
||||
# 40-80% = linear from 30 to 0 (good → fair)
|
||||
# >80% = 0 points (poor - context overloaded)
|
||||
if context_usage_percent < 40:
|
||||
context_score = 30
|
||||
elif context_usage_percent <= 80:
|
||||
# Linear decay from 30 (at 40%) to 0 (at 80%)
|
||||
context_score = 30 - ((context_usage_percent - 40) / 40) * 30
|
||||
else:
|
||||
context_score = 0
|
||||
|
||||
total_score = int(token_score + cache_score + context_score)
|
||||
|
||||
# Ensure score is in valid range
|
||||
return max(0, min(100, total_score))
|
||||
|
||||
def interpret_score(score: int) -> str:
|
||||
"""
|
||||
Interpret efficiency score into human-readable rating.
|
||||
|
||||
Args:
|
||||
score: Efficiency score (0-100)
|
||||
|
||||
Returns:
|
||||
str: Rating (excellent, good, fair, poor)
|
||||
"""
|
||||
if score >= 90:
|
||||
return "excellent"
|
||||
elif score >= 80:
|
||||
return "good"
|
||||
elif score >= 70:
|
||||
return "fair"
|
||||
else:
|
||||
return "poor"
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Calculate Navigator efficiency score"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tokens-saved-percent",
|
||||
type=float,
|
||||
required=True,
|
||||
help="Percentage of tokens saved vs baseline (0-100)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cache-efficiency",
|
||||
type=float,
|
||||
required=True,
|
||||
help="Cache hit rate percentage (0-100)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--context-usage",
|
||||
type=float,
|
||||
required=True,
|
||||
help="Context window usage percentage (0-100)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="Show detailed breakdown"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
score = calculate_efficiency_score(
|
||||
args.tokens_saved_percent,
|
||||
args.cache_efficiency,
|
||||
args.context_usage
|
||||
)
|
||||
|
||||
if args.verbose:
|
||||
rating = interpret_score(score)
|
||||
print(f"Efficiency Score: {score}/100 ({rating})")
|
||||
print(f" Token savings: {args.tokens_saved_percent}%")
|
||||
print(f" Cache efficiency: {args.cache_efficiency}%")
|
||||
print(f" Context usage: {args.context_usage}%")
|
||||
else:
|
||||
# Output just the score (parseable)
|
||||
print(score)
|
||||
|
||||
sys.exit(0)
|
||||
160
skills/nav-stats/functions/report_formatter.py
Executable file
160
skills/nav-stats/functions/report_formatter.py
Executable file
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Format Navigator efficiency metrics into visual, shareable report.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
def format_number(num: int) -> str:
|
||||
"""Format number with commas for readability."""
|
||||
return f"{num:,}"
|
||||
|
||||
def interpret_score(score: int) -> str:
|
||||
"""Get rating label for score."""
|
||||
if score >= 90:
|
||||
return "excellent"
|
||||
elif score >= 80:
|
||||
return "good"
|
||||
elif score >= 70:
|
||||
return "fair"
|
||||
else:
|
||||
return "poor"
|
||||
|
||||
def get_recommendations(
|
||||
savings_percent: int,
|
||||
cache_efficiency: float,
|
||||
context_usage: int,
|
||||
efficiency_score: int
|
||||
) -> list:
|
||||
"""
|
||||
Generate actionable recommendations based on metrics.
|
||||
|
||||
Returns:
|
||||
list: List of recommendation strings
|
||||
"""
|
||||
recs = []
|
||||
|
||||
# Check token savings
|
||||
if savings_percent < 70:
|
||||
recs.append(("⚠️", "Token savings below target (70%+)"))
|
||||
recs.append(("→", "Check: Are you loading more docs than needed?"))
|
||||
recs.append(("→", "Tip: Use navigator to find docs, don't load all upfront"))
|
||||
recs.append(("", "Read more: .agent/philosophy/CONTEXT-EFFICIENCY.md"))
|
||||
elif savings_percent >= 85:
|
||||
recs.append(("✅", "Excellent token savings - keep using lazy-loading strategy"))
|
||||
|
||||
# Check cache efficiency
|
||||
if cache_efficiency < 80:
|
||||
recs.append(("⚠️", "Cache efficiency low (<80%)"))
|
||||
recs.append(("→", "Check: CLAUDE.md properly configured?"))
|
||||
recs.append(("→", "Tip: Ensure prompt caching enabled"))
|
||||
recs.append(("", "Read more: .agent/philosophy/PATTERNS.md (Caching pattern)"))
|
||||
elif cache_efficiency >= 95:
|
||||
recs.append(("✅", "Cache working perfectly - no optimization needed"))
|
||||
|
||||
# Check context usage
|
||||
if context_usage > 80:
|
||||
recs.append(("⚠️", "Context usage high (80%+)"))
|
||||
recs.append(("→", "Consider: Create context marker and compact"))
|
||||
recs.append(("→", "Tip: Compact after completing sub-tasks"))
|
||||
recs.append(("", "Read more: .agent/philosophy/ANTI-PATTERNS.md"))
|
||||
elif context_usage < 40:
|
||||
recs.append(("✅", "Context usage healthy - plenty of room for work"))
|
||||
|
||||
# Default excellent message
|
||||
if not recs and efficiency_score >= 90:
|
||||
recs.append(("✅", "Excellent efficiency - keep it up!"))
|
||||
recs.append(("", ""))
|
||||
recs.append(("", "Share your efficiency: Take a screenshot! #ContextEfficiency"))
|
||||
|
||||
return recs
|
||||
|
||||
def format_report(
|
||||
baseline: int,
|
||||
loaded: int,
|
||||
saved: int,
|
||||
savings_percent: int,
|
||||
cache_efficiency: float,
|
||||
context_usage: int,
|
||||
efficiency_score: int,
|
||||
time_saved: int
|
||||
) -> str:
|
||||
"""
|
||||
Format efficiency report.
|
||||
|
||||
Returns:
|
||||
str: Formatted report
|
||||
"""
|
||||
rating = interpret_score(efficiency_score)
|
||||
recs = get_recommendations(savings_percent, cache_efficiency, context_usage, efficiency_score)
|
||||
|
||||
report = f"""╔══════════════════════════════════════════════════════╗
|
||||
║ NAVIGATOR EFFICIENCY REPORT ║
|
||||
╚══════════════════════════════════════════════════════╝
|
||||
|
||||
📊 TOKEN USAGE
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Documentation loaded: {format_number(loaded):>12} tokens
|
||||
Baseline (all docs): {format_number(baseline):>12} tokens
|
||||
Tokens saved: {format_number(saved):>12} tokens ({savings_percent}% ↓)
|
||||
|
||||
💾 CACHE PERFORMANCE
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Cache efficiency: {cache_efficiency:>16.1f}% ({"perfect" if cache_efficiency >= 99 else "good" if cache_efficiency >= 90 else "fair"})
|
||||
|
||||
📈 SESSION METRICS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Context usage: {context_usage:>16}% ({rating})
|
||||
Efficiency score: {efficiency_score:>12}/100 ({rating})
|
||||
|
||||
⏱️ TIME SAVED
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Estimated time saved: {time_saved:>13} minutes
|
||||
|
||||
💡 WHAT THIS MEANS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
Navigator loaded {savings_percent}% fewer tokens than loading all docs.
|
||||
Your context window is {100 - context_usage}% available for actual work.
|
||||
"""
|
||||
|
||||
# Add recommendations section
|
||||
if recs:
|
||||
report += "\n🎯 RECOMMENDATIONS\n"
|
||||
report += "━" * 54 + "\n"
|
||||
for icon, text in recs:
|
||||
if icon:
|
||||
report += f"{icon} {text}\n"
|
||||
else:
|
||||
report += f"{text}\n"
|
||||
|
||||
return report
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Format Navigator efficiency report"
|
||||
)
|
||||
parser.add_argument("--baseline", type=int, required=True, help="Baseline tokens (all docs)")
|
||||
parser.add_argument("--loaded", type=int, required=True, help="Actually loaded tokens")
|
||||
parser.add_argument("--saved", type=int, required=True, help="Tokens saved")
|
||||
parser.add_argument("--savings-percent", type=int, required=True, help="Savings percentage")
|
||||
parser.add_argument("--cache-efficiency", type=float, required=True, help="Cache efficiency %")
|
||||
parser.add_argument("--context-usage", type=int, required=True, help="Context usage %")
|
||||
parser.add_argument("--efficiency-score", type=int, required=True, help="Efficiency score (0-100)")
|
||||
parser.add_argument("--time-saved", type=int, required=True, help="Time saved (minutes)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
report = format_report(
|
||||
args.baseline,
|
||||
args.loaded,
|
||||
args.saved,
|
||||
args.savings_percent,
|
||||
args.cache_efficiency,
|
||||
args.context_usage,
|
||||
args.efficiency_score,
|
||||
args.time_saved
|
||||
)
|
||||
|
||||
print(report)
|
||||
sys.exit(0)
|
||||
Reference in New Issue
Block a user