diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..c26e7ef3774f6297578970ec3c48da1a4c0945cf --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git +.vercel +venv +frontend/node_modules +frontend/dist +data +*.log +*-dev.out.log +*-dev.err.log +MalwareGuard_Report.* +test_folder diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..51f6d625f0dae6183095578cb355901b92e455d2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +urlmodel_info/case_study_scores.png filter=lfs diff=lfs merge=lfs -text +urlmodel_info/eda_feature_distributions.png filter=lfs diff=lfs merge=lfs -text +urlmodel_info/feature_importance_xgb.png filter=lfs diff=lfs merge=lfs -text +urlmodel_info/results_accuracy_bar.png filter=lfs diff=lfs merge=lfs -text +urlmodel_info/results_roc_curves.png filter=lfs diff=lfs merge=lfs -text diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..a9c4b48b63f05824e3d4e4c036dc6b1e42536d20 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +RUN apt-get update \ + && apt-get install -y --no-install-recommends build-essential curl \ + && rm -rf /var/lib/apt/lists/* + +COPY backend/requirements.txt /app/backend/requirements.txt +RUN pip install --no-cache-dir -r /app/backend/requirements.txt + +COPY backend /app/backend +COPY xgb_malware_model.joblib /app/xgb_malware_model.joblib +COPY urlmodel_info /app/urlmodel_info + +WORKDIR /app/backend +EXPOSE 7860 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"] diff --git a/README.md b/README.md index 399ffcc32e9ed1967314847d2d8f8a0d52060f90..15094054aa815c80bf30974039c94b96f4837c38 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ --- title: MalwareGuard -emoji: 🐒 -colorFrom: indigo -colorTo: purple +emoji: πŸ›‘οΈ +colorFrom: red +colorTo: gray sdk: docker pinned: false +license: mit --- -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +# MalwareGuard Backend + +FastAPI backend for MalwareGuard, deployed as a Hugging Face Docker Space. diff --git a/backend/app/__init__.py b/backend/app/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c50b236a0a0030ac68f131da12d4aa06ab3785d1 --- /dev/null +++ b/backend/app/__init__.py @@ -0,0 +1 @@ +# Backend package diff --git a/backend/app/config.py b/backend/app/config.py new file mode 100644 index 0000000000000000000000000000000000000000..b1ba522293e54f6b8a529cc6ceeae1a8d60fb67d --- /dev/null +++ b/backend/app/config.py @@ -0,0 +1,78 @@ +""" +Configuration module for the Malware Detection Platform. +Loads environment variables and provides app-wide settings. +""" + + + +import os +from pathlib import Path +from pydantic_settings import BaseSettings +from functools import lru_cache + + + +class Settings(BaseSettings): + """Application settings loaded from environment variables.""" + + + # API Keys + gemini_api_key: str = "" + virustotal_api_key: str = "" + + + # Model Configuration + model_path: str = "xgb_malware_model.joblib" + prediction_threshold: float = 0.5 + + + # Server Configuration + host: str = "0.0.0.0" + port: int = 8000 + debug: bool = True + + + # EMBER Dataset Configuration + ember_feature_count: int = 2381 # EMBER 2018 v2 feature count + + + # Rate Limiting + rate_limit_prediction: str = "60/minute" + rate_limit_virustotal: str = "10/minute" + + + # CORS Origins + cors_origins: list[str] = [ + "http://localhost:5173", + "http://localhost:3000", + "http://127.0.0.1:5173", + "http://127.0.0.1:3000", + ] + + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + extra = "ignore" + + +@lru_cache() +def get_settings() -> Settings: + """ + Get cached settings instance. + Uses LRU cache to avoid re-reading .env file on every call. + """ + # Look for .env in parent directory (project root) + env_path = Path(__file__).parent.parent.parent / ".env" + if env_path.exists(): + os.environ.setdefault("ENV_FILE", str(env_path)) + + + return Settings(_env_file=env_path if env_path.exists() else ".env") + + + +# Export settings instance for easy import +settings = get_settings() + + + diff --git a/backend/app/main.py b/backend/app/main.py new file mode 100644 index 0000000000000000000000000000000000000000..2f56100abb698c998931676e62c92a357cabd9c7 --- /dev/null +++ b/backend/app/main.py @@ -0,0 +1,232 @@ +""" +Malware Detection Platform - FastAPI Main Application + +Production-ready malware detection API combining: +- XGBoost ML model for EMBER 2018 v2 feature classification +- Gemini AI for human-readable explanations +- VirusTotal API for secondary verification + +Author: AI Security Engineer +""" +# Used libraries +import logging +from contextlib import asynccontextmanager +from fastapi import FastAPI, Request +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse +from slowapi import Limiter, _rate_limit_exceeded_handler +from slowapi.util import get_remote_address +from slowapi.errors import RateLimitExceeded + +from .config import settings +from .routers import predict, virustotal, chat, upload, url, feedback +from .services.ml_service import get_ml_service +from .services.shap_service import get_shap_service +from .services.gemini_service import get_gemini_service +from .services.virustotal_service import get_virustotal_service +from .services.url_service import get_url_service +from .services.feedback_service import get_feedback_service + +# Configure logging. +logging.basicConfig( + level=logging.INFO if settings.debug else logging.WARNING, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +# Rate limiter +limiter = Limiter(key_func=get_remote_address) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + """ + Application lifespan manager. + Handles startup and shutdown events. + """ + # Startup. + logger.info("=" * 60) + logger.info("Malware Detection Platform Starting...") + logger.info("=" * 60) + + # Load ML model (single load for all requests). + try: + ml_service = get_ml_service() + logger.info(f"ML Model loaded: {ml_service.get_model_info()}") + except Exception as e: + logger.error(f"Failed to load ML model: {e}") + raise + + # Initialize SHAP service. + try: + shap_service = get_shap_service() + shap_service.initialize(ml_service.model) + logger.info("SHAP service initialized") + except Exception as e: + logger.warning(f"SHAP initialization failed (non-critical): {e}") + + # Initialize Gemini service + try: + gemini_service = get_gemini_service() + if gemini_service.initialized: + logger.info("Gemini AI service initialized") + else: + logger.warning("Gemini AI service not initialized (check API key)") + except Exception as e: + logger.warning(f"Gemini initialization failed (non-critical): {e}") + + # Check VirusTotal configuration + vt_service = get_virustotal_service() + if vt_service.initialized: + logger.info("VirusTotal service configured") + else: + logger.warning("VirusTotal API key not configured") + + # Load URL HyperModel + try: + url_service = get_url_service() + if url_service.model_loaded: + logger.info(f"URL HyperModel loaded: {url_service.get_model_info()['model_type']}") + else: + logger.warning("URL HyperModel not loaded") + except Exception as e: + logger.warning(f"URL HyperModel initialization failed (non-critical): {e}") + + # Initialize RL Feedback service + try: + fb_service = get_feedback_service() + stats = fb_service.get_stats() + logger.info( + f"RL Feedback service ready " + f"(malware={stats['malware_total']}, url={stats['url_total']} samples)" + ) + except Exception as e: + logger.warning(f"RL Feedback initialization failed (non-critical): {e}") + + logger.info("=" * 60) + logger.info("Malware Detection Platform Ready!") + logger.info(f"API available at: http://{settings.host}:{settings.port}") + logger.info("=" * 60) + + yield + + # Shutdown + logger.info("Shutting down Malware Detection Platform...") + + # Close VirusTotal client + await vt_service.close() + + logger.info("Shutdown complete") + + +# Create FastAPI app +app = FastAPI( + title="Malware Detection Platform", + description=""" + ## AI-Powered Malware Detection API + + This platform combines machine learning with AI explanations for comprehensive malware analysis. + + ### Features + - **XGBoost Prediction**: Fast malware classification using EMBER 2018 v2 features + - **Gemini AI Explanation**: Human-readable analysis and recommendations + - **VirusTotal Verification**: Cross-reference with 70+ antivirus engines + - **URL Scanner**: Malicious URL detection via stacking HyperModel + + ### Endpoints + - `/api/predict` - Run XGBoost malware prediction + - `/api/predict/explain` - Prediction with Gemini AI explanation + - `/api/virustotal/{hash}` - Look up file hash on VirusTotal + - `/api/virustotal/compare` - Compare XGBoost vs VirusTotal verdicts + - `/api/url/analyze` - Analyze URL for malicious indicators + """, + version="1.0.0", + lifespan=lifespan, + docs_url="/docs", + redoc_url="/redoc" +) + +# Add rate limiter to app state +app.state.limiter = limiter +app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) + +# Configure CORS +app.add_middleware( + CORSMiddleware, + allow_origins=settings.cors_origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +# Global exception handler +@app.exception_handler(Exception) +async def global_exception_handler(request: Request, exc: Exception): + """Handle uncaught exceptions with meaningful error messages.""" + logger.error(f"Unhandled exception: {exc}", exc_info=True) + + # Don't expose internal errors in production + if settings.debug: + detail = str(exc) + else: + detail = "An internal error occurred. Please try again later." + + return JSONResponse( + status_code=500, + content={"detail": detail} + ) + + +# Include routers +app.include_router(predict.router) +app.include_router(virustotal.router) +app.include_router(chat.router) +app.include_router(upload.router) +app.include_router(url.router) +app.include_router(feedback.router) + + +@app.get("/", tags=["root"]) +async def root(): + """Root endpoint with API information.""" + return { + "name": "Malware Detection Platform", + "version": "1.0.0", + "status": "running", + "docs": "/docs", + "endpoints": { + "prediction": "/api/predict", + "prediction_with_explanation": "/api/predict/explain", + "virustotal_lookup": "/api/virustotal/{hash}", + "comparison": "/api/virustotal/compare" + } + } + + +@app.get("/health", tags=["health"]) +async def health_check(): + """Global health check endpoint.""" + ml_service = get_ml_service() + vt_service = get_virustotal_service() + gemini_service = get_gemini_service() + + return { + "status": "healthy", + "services": { + "ml_model": ml_service.model_loaded, + "gemini": gemini_service.initialized, + "virustotal": vt_service.initialized + } + } + + +# For running with: python -m app.main +if __name__ == "__main__": + import uvicorn + uvicorn.run( + "app.main:app", + host=settings.host, + port=settings.port, + reload=settings.debug + ) diff --git a/backend/app/models/__init__.py b/backend/app/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..26593abe4e017014b6961246486461f3829dbf3a --- /dev/null +++ b/backend/app/models/__init__.py @@ -0,0 +1 @@ +# Models package diff --git a/backend/app/models/feedback.py b/backend/app/models/feedback.py new file mode 100644 index 0000000000000000000000000000000000000000..99fc9d9f29fed5dd633f91130e40e843a5962f6c --- /dev/null +++ b/backend/app/models/feedback.py @@ -0,0 +1,126 @@ +""" +Pydantic models for Reinforcement Learning feedback. + +Two feedback channels: + 1. Malware analysis: auto-reward based on VirusTotal agreement (+1 agree, -1 disagree) + 2. URL analysis: user-submitted reward via popup ("Was this correct?" Yes β†’ +1, No β†’ -1) +""" + +from pydantic import BaseModel, Field +from typing import Optional, List, Dict +from enum import Enum + + +class FeedbackType(str, Enum): + MALWARE = "malware" + URL = "url" + + +# ── Malware RL Feedback ────────────────────────────────────────────────────── + +class MalwareFeedbackRequest(BaseModel): + """ + Auto-generated feedback when VirusTotal results are compared with + XGBoost prediction. Reward is computed server-side. + """ + features: List[float] = Field( + ..., + min_length=2381, + max_length=2381, + description="EMBER 2018 v2 feature vector", + ) + sha256: str = Field( + ..., + pattern=r"^[a-fA-F0-9]{64}$", + description="SHA256 hash of the analysed file", + ) + predicted_label: str = Field( + ..., + description="XGBoost prediction: 'Malicious' or 'Benign'", + ) + predicted_probability: float = Field(..., ge=0.0, le=1.0) + vt_malicious_count: int = Field(..., ge=0) + vt_total_engines: int = Field(..., ge=0) + vt_detection_ratio: float = Field(..., ge=0.0, le=1.0) + + +# ── URL RL Feedback ────────────────────────────────────────────────────────── + +class URLFeedbackRequest(BaseModel): + """ + User-submitted feedback for URL predictions. + The user confirms or denies the model's verdict. + """ + url: str = Field(..., min_length=3, description="Analysed URL") + predicted_label: str = Field( + ..., + description="Model prediction: 'Malicious' or 'Benign'", + ) + malicious_score: float = Field(..., ge=0.0, le=1.0) + is_correct: bool = Field( + ..., + description="True if user confirms prediction is correct, False otherwise", + ) + base_model_scores: Dict[str, float] = Field( + default_factory=dict, + description="Base model malicious probabilities for meta-feature reconstruction", + ) + + +# ── Responses ──────────────────────────────────────────────────────────────── + +class FeedbackResponse(BaseModel): + """Response after submitting feedback.""" + success: bool + reward: int + message: str + total_feedback_count: int + + +class FeedbackStats(BaseModel): + """Aggregated RL statistics.""" + malware_total: int + malware_agree: int + malware_disagree: int + malware_agreement_rate: float + url_total: int + url_correct: int + url_incorrect: int + url_accuracy_rate: float + recent_malware: List[dict] = [] + recent_url: List[dict] = [] + model_updates: List[dict] = [] + + +class ModelUpdateRequest(BaseModel): + """Request to trigger incremental model update.""" + model_type: str = Field( + ..., + description="Which model to update: 'malware' or 'url'", + pattern=r"^(malware|url)$", + ) + min_samples: int = Field( + 10, + ge=1, + description="Minimum feedback samples required to proceed", + ) + learning_rate: float = Field( + 0.01, + ge=0.001, + le=0.1, + description="Learning rate for incremental training", + ) + num_boost_rounds: int = Field( + 5, + ge=1, + le=50, + description="Number of additional boosting rounds", + ) + + +class ModelUpdateResponse(BaseModel): + """Response from model update trigger.""" + success: bool + model_type: str + samples_used: int + message: str diff --git a/backend/app/models/prediction.py b/backend/app/models/prediction.py new file mode 100644 index 0000000000000000000000000000000000000000..a2a0f355e43937380f834de12b5efec3f5d609e4 --- /dev/null +++ b/backend/app/models/prediction.py @@ -0,0 +1,149 @@ +""" +Pydantic models for prediction requests and responses. +Defines the data structures for the XGBoost malware detection API. +""" + +from pydantic import BaseModel, Field, field_validator + +from typing import Optional, List + +from enum import Enum + + +class PredictionLabel(str, Enum): + """Prediction classification labels.""" + MALICIOUS = "Malicious" + BENIGN = "Benign" + + +class ConfidenceLevel(str, Enum): + """Confidence level categories based on probability.""" + HIGH = "High" + MEDIUM = "Medium" + LOW = "Low" + + +class SeverityLevel(str, Enum): + """Severity levels for Gemini analysis.""" + CRITICAL = "Critical" + HIGH = "High" + MEDIUM = "Medium" + LOW = "Low" + NONE = "None" + + +class PredictionRequest(BaseModel): + """ + Request model for malware prediction. + Accepts EMBER 2018 v2 feature vector (2381 features). + """ + features: List[float] = Field( + ..., + description="EMBER 2018 v2 feature vector (2381 float values)", + min_length=2381, + max_length=2381 + ) + sha256: Optional[str] = Field( + None, + description="Optional SHA256 hash for reference", + pattern=r"^[a-fA-F0-9]{64}$" + ) + threshold: Optional[float] = Field( + None, + description="Custom prediction threshold (0.0-1.0)", + ge=0.0, + le=1.0 + ) + include_shap: Optional[bool] = Field( + False, + description="Include SHAP feature importance analysis" + ) + + + @field_validator('features') + @classmethod + def validate_features(cls, v): + """Validate feature values are within reasonable bounds.""" + if not all(isinstance(x, (int, float)) for x in v): + raise ValueError("All features must be numeric values") + return v + + + +class FeatureImportance(BaseModel): + """Single feature importance entry from SHAP analysis.""" + feature_index: int + feature_name: str + importance_value: float + contribution: str # "increases" or "decreases" malware probability + + + +class PredictionResponse(BaseModel): + """ + Response model for malware prediction. + Contains prediction, probability, and optional SHAP analysis. + """ + prediction: PredictionLabel + probability: float = Field(..., ge=0.0, le=1.0) + confidence: ConfidenceLevel + threshold_used: float + sha256: Optional[str] = None + top_features: Optional[List[FeatureImportance]] = None + inference_time_ms: float + + + +class GeminiExplanation(BaseModel): + """Gemini AI analysis response.""" + risk_explanation: str + severity_level: SeverityLevel + key_indicators: List[str] + analyst_summary: str + mitigation_steps: Optional[List[str]] = None + + + +class MalwareTypeInfo(BaseModel): + """Malware type classification result.""" + primary_type: str + confidence: str + secondary_types: List[str] = [] + indicators: List[str] = [] + source: str + + + +class PredictionWithExplanationResponse(BaseModel): + """ + Combined response with XGBoost prediction and Gemini explanation. + """ + prediction: PredictionResponse + explanation: GeminiExplanation + malware_type: Optional[MalwareTypeInfo] = None + + + +class CompareRequest(BaseModel): + """Request to compare XGBoost prediction with VirusTotal.""" + features: List[float] = Field( + ..., + min_length=2381, + max_length=2381 + ) + sha256: str = Field( + ..., + pattern=r"^[a-fA-F0-9]{64}$", + description="SHA256 hash to check on VirusTotal" + ) + + +class ComparisonResult(BaseModel): + """Result of comparing XGBoost and VirusTotal verdicts.""" + xgboost_prediction: PredictionLabel + xgboost_probability: float + virustotal_malicious_count: int + virustotal_total_engines: int + virustotal_detection_ratio: float + agreement: bool + agreement_description: str diff --git a/backend/app/models/url.py b/backend/app/models/url.py new file mode 100644 index 0000000000000000000000000000000000000000..537aa72e3bd7b28a83a4a9e0e497912077612550 --- /dev/null +++ b/backend/app/models/url.py @@ -0,0 +1,68 @@ +""" +Pydantic models for URL malware detection requests and responses. +""" + +from pydantic import BaseModel, Field, field_validator +from typing import Optional, Dict, List +from enum import Enum + + +class URLPredictionLabel(str, Enum): + """URL prediction labels.""" + MALICIOUS = "Malicious" + BENIGN = "Benign" + + +class URLConfidenceLevel(str, Enum): + """Confidence levels.""" + HIGH = "High" + MEDIUM = "Medium" + LOW = "Low" + + +class URLAnalyzeRequest(BaseModel): + """Request to analyze a URL for malicious indicators.""" + url: str = Field( + ..., + description="URL to analyze", + min_length=3, + max_length=4096, + ) + threshold: Optional[float] = Field( + None, + description="Custom prediction threshold (0.0-1.0)", + ge=0.0, + le=1.0, + ) + + @field_validator("url") + @classmethod + def validate_url(cls, v): + v = v.strip() + if not v: + raise ValueError("URL cannot be empty") + return v + + +class URLAnalyzeResponse(BaseModel): + """Response from URL malware analysis.""" + url: str + prediction: URLPredictionLabel + malicious_score: float = Field(..., ge=0.0, le=1.0) + confidence: str + confidence_level: URLConfidenceLevel + threshold_used: float + base_model_scores: Dict[str, float] + top_signals: Dict[str, float] + inference_time_ms: float + + +class URLModelInfoResponse(BaseModel): + """Information about the URL model.""" + model_type: str + base_models: List[str] + meta_learner: str + scaler_features: int + meta_features: int + dl_available: bool + feature_categories: List[str] diff --git a/backend/app/models/virustotal.py b/backend/app/models/virustotal.py new file mode 100644 index 0000000000000000000000000000000000000000..aba7a815001b342227f78ef1557ab1be238f16d1 --- /dev/null +++ b/backend/app/models/virustotal.py @@ -0,0 +1,72 @@ +""" +Pydantic models for VirusTotal API responses. +""" + +from pydantic import BaseModel, Field +from typing import Optional, Dict, List +from datetime import datetime + + +class EngineResult(BaseModel): + """Single antivirus engine scan result.""" + engine_name: str + category: str # "malicious", "undetected", "suspicious", etc. + result: Optional[str] = None # Detection name if malicious + engine_version: Optional[str] = None + engine_update: Optional[str] = None + + +class VirusTotalStats(BaseModel): + """Aggregated statistics from VirusTotal scan.""" + malicious: int = 0 + suspicious: int = 0 + undetected: int = 0 + harmless: int = 0 + timeout: int = 0 + confirmed_timeout: int = 0 + failure: int = 0 + type_unsupported: int = 0 + + +class MalwareTypeInfo(BaseModel): + """Malware type classification information.""" + primary_type: str + confidence: str # "High", "Medium", "Low" + secondary_types: List[str] = [] + indicators: List[str] = [] + source: str # "heuristic", "virustotal", "combined" + + +class VirusTotalRequest(BaseModel): + """Request model for VirusTotal hash lookup.""" + sha256: str = Field( + ..., + pattern=r"^[a-fA-F0-9]{64}$", + description="SHA256 hash to look up" + ) + + +class VirusTotalResponse(BaseModel): + """ + Response model for VirusTotal hash lookup. + Contains detection stats and engine results. + """ + sha256: str + found: bool + stats: Optional[VirusTotalStats] = None + detection_ratio: Optional[float] = None + total_engines: Optional[int] = None + malicious_count: Optional[int] = None + reputation_score: Optional[int] = None + engine_results: Optional[List[EngineResult]] = None + first_submission_date: Optional[str] = None + last_analysis_date: Optional[str] = None + meaningful_name: Optional[str] = None + malware_type: Optional[MalwareTypeInfo] = None + error_message: Optional[str] = None + + +class VirusTotalError(BaseModel): + """Error response from VirusTotal.""" + error: str + code: Optional[str] = None diff --git a/backend/app/routers/__init__.py b/backend/app/routers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2a2004f48b32f31f733ae7df98c9ab7acb540d11 --- /dev/null +++ b/backend/app/routers/__init__.py @@ -0,0 +1 @@ +# Routers package diff --git a/backend/app/routers/chat.py b/backend/app/routers/chat.py new file mode 100644 index 0000000000000000000000000000000000000000..53818f7e60745110946330a9680cead0129e439d --- /dev/null +++ b/backend/app/routers/chat.py @@ -0,0 +1,179 @@ +""" +Chat Router - Gemini-powered chatbot endpoint for the malware detection platform. +""" + +from fastapi import APIRouter +from pydantic import BaseModel, Field +from typing import Optional, List +import logging + +from ..services.gemini_service import get_gemini_service + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/chat", tags=["chat"]) + + +class ChatRequest(BaseModel): + """Chat request model.""" + + message: str = Field(..., description="User message", min_length=1, max_length=2000) + history: Optional[List[str]] = Field(default=[], description="Conversation history") + + +class ChatResponse(BaseModel): + """Chat response model.""" + + response: str = Field(..., description="AI response") + success: bool = Field(default=True) + + +def _fallback_chat_response(message: str) -> str: + """Return a local fallback answer when Gemini is unavailable.""" + text = message.lower() + + if any( + keyword in text + for keyword in [ + "malware detection", + "how does malware", + "how it works", + "detect malware", + ] + ): + return ( + "MalwareGuard analyzes Windows PE files by extracting EMBER features, " + "running an XGBoost malware classifier, and then showing confidence, " + "SHAP feature importance, and an optional malware-type interpretation." + ) + + if any(keyword in text for keyword in ["ember", "dataset", "features"]): + return ( + "The platform uses the EMBER 2018 v2 feature format. Each sample is " + "represented by 2,381 static features derived from PE structure, imports, " + "exports, strings, headers, and byte-level statistics." + ) + + if any( + keyword in text for keyword in ["virustotal", "hash", "sha256", "md5", "sha1"] + ): + return ( + "Use the VirusTotal lookup tab to submit a file hash such as SHA256, MD5, " + "or SHA1. MalwareGuard queries VirusTotal and returns detection ratio, engine " + "results, and malware-type hints when available." + ) + + if any(keyword in text for keyword in ["url", "link", "phishing"]): + return ( + "The URL scanner extracts lexical and structural signals from a URL, runs the " + "URL model stack, and returns a malicious or benign verdict with top signals. " + "Users can also submit feedback to improve the model over time." + ) + + if any( + keyword in text for keyword in ["dashboard", "feedback", "reinforcement", "rl"] + ): + return ( + "The dashboard summarizes malware and URL feedback, agreement rates, and model " + "update activity. Feedback is stored locally and can be used to trigger model updates." + ) + + return ( + "Gemini is currently unavailable, so I am answering in fallback mode. " + "I can still help explain MalwareGuard features such as PE file analysis, URL scanning, " + "VirusTotal lookup, SHAP explanations, and the feedback dashboard." + ) + + +# System context for the chatbot +CHATBOT_SYSTEM_PROMPT = """You are MalwareGuard AI, a helpful and knowledgeable assistant for a malware detection platform. Your role is to help users understand: + +1. **About the Platform**: MalwareGuard is an AI-powered malware detection platform that uses: + - XGBoost machine learning model trained on the EMBER 2018 v2 dataset + - SHAP (SHapley Additive exPlanations) for feature importance analysis + - Gemini AI for human-readable explanations + - VirusTotal API integration for cross-referencing with 70+ antivirus engines + +2. **How Malware Detection Works**: + - The platform analyzes PE (Portable Executable) file features + - Features include: byte histograms, PE header info, import/export tables, section characteristics, string analysis + - The ML model outputs a probability (0-1) indicating malware likelihood + - SHAP explains which features contributed most to the prediction + +3. **How to Use the Platform**: + - AI Prediction Tab: Input EMBER features (2381 float values) for malware analysis + - VirusTotal Tab: Look up file hashes (SHA256, MD5, SHA1) for antivirus scan results + - Results include confidence levels, explanations, and mitigation recommendations + +4. **The EMBER Dataset**: + - EMBER = Endgame Malware BEnchmark for Research + - Contains 2018 v2 features extracted from Windows PE files + - 2381 features per sample including: byte histograms (256), section info, imports, exports, etc. + - Training set: ~1 million samples (malware + benign) + +5. **Team Information**: + - This is a graduation project 2026 developed by a team of 5 members + - Hesham Ahmed Wageeh Elsayed β€” AI Engineer + - Ahmed Mohamed Ramadan β€” UI/UX Designer + - Kamal Khaled β€” AI Engineer + - Zeyad Waleed β€” Full Stack Developer + - Ali Hassan Ali β€” Full Stack Developer + +Guidelines: +- Be helpful, professional, and accurate +- Focus on cybersecurity and malware detection topics +- If asked about something outside your expertise, politely redirect +- Keep responses concise but informative +- Use markdown formatting for readability when appropriate +- Never reveal sensitive technical details about bypassing detection + +User message: {message}""" + + +@router.post("/", response_model=ChatResponse) +async def chat(request: ChatRequest): + """ + Send a message to the AI chatbot. + + The chatbot can answer questions about: + - How the malware detection platform works + - EMBER dataset and features + - Using the prediction and VirusTotal features + - General cybersecurity questions + """ + gemini_service = get_gemini_service() + + if not gemini_service.initialized: + gemini_service.initialize() + + if not gemini_service.initialized or gemini_service.model is None: + logger.warning("Gemini chatbot unavailable, using fallback response") + return ChatResponse(response=_fallback_chat_response(request.message)) + + try: + # Format the prompt with user message + prompt = CHATBOT_SYSTEM_PROMPT.format(message=request.message) + + # Call Gemini API + response = gemini_service.model.generate_content(prompt) + + if response.text: + return ChatResponse(response=response.text) + else: + logger.warning("Gemini returned an empty chatbot response, using fallback") + return ChatResponse(response=_fallback_chat_response(request.message)) + + except Exception as e: + logger.error(f"Chat error: {e}") + return ChatResponse(response=_fallback_chat_response(request.message)) + + +@router.get("/health") +async def chat_health(): + """Check if the chat service is healthy.""" + gemini_service = get_gemini_service() + + return { + "status": "healthy" if gemini_service.initialized else "unavailable", + "gemini_initialized": gemini_service.initialized, + } diff --git a/backend/app/routers/feedback.py b/backend/app/routers/feedback.py new file mode 100644 index 0000000000000000000000000000000000000000..db78cdb541c9267f48924d44c472d318427c39f8 --- /dev/null +++ b/backend/app/routers/feedback.py @@ -0,0 +1,156 @@ +""" +Reinforcement Learning Feedback Router + +Endpoints: + POST /api/feedback/malware β€” Log malware RL reward (VT agreement) + POST /api/feedback/url β€” Log URL RL reward (user confirmation) + GET /api/feedback/stats β€” Aggregated RL statistics + POST /api/feedback/update-model β€” Trigger incremental model update + GET /api/feedback/health β€” Health check +""" + +import logging +from fastapi import APIRouter, HTTPException + +from ..models.feedback import ( + MalwareFeedbackRequest, + URLFeedbackRequest, + FeedbackResponse, + FeedbackStats, + ModelUpdateRequest, + ModelUpdateResponse, +) +from ..services.feedback_service import get_feedback_service + +logger = logging.getLogger(__name__) + +router = APIRouter( + prefix="/api/feedback", + tags=["Reinforcement Learning"], + responses={500: {"description": "Internal Server Error"}}, +) + + +# ── Malware RL ──────────────────────────────────────────────────────────────── + +@router.post("/malware", response_model=FeedbackResponse) +async def submit_malware_feedback(body: MalwareFeedbackRequest): + """ + Submit malware RL feedback based on VirusTotal comparison. + + Reward: + +1 if XGBoost and VirusTotal agree (both malicious or both benign) + -1 if they disagree + """ + try: + svc = get_feedback_service() + result = svc.log_malware_feedback( + features=body.features, + sha256=body.sha256, + predicted=body.predicted_label, + probability=body.predicted_probability, + vt_mal=body.vt_malicious_count, + vt_total=body.vt_total_engines, + vt_ratio=body.vt_detection_ratio, + ) + # Auto-trigger incremental update when enough samples accumulate + svc.maybe_auto_update("malware") + return FeedbackResponse(**result) + except Exception as e: + logger.error(f"Malware feedback error: {e}", exc_info=True) + raise HTTPException(status_code=500, detail=f"Feedback failed: {e}") + + +# ── URL RL ──────────────────────────────────────────────────────────────────── + +@router.post("/url", response_model=FeedbackResponse) +async def submit_url_feedback(body: URLFeedbackRequest): + """ + Submit URL RL feedback from user confirmation popup. + + Reward: + +1 if user confirms prediction is correct + -1 if user says prediction is wrong + """ + try: + svc = get_feedback_service() + result = svc.log_url_feedback( + url=body.url, + predicted=body.predicted_label, + malicious_score=body.malicious_score, + is_correct=body.is_correct, + base_model_scores=body.base_model_scores, + ) + # Auto-trigger incremental update when enough samples accumulate + svc.maybe_auto_update("url") + return FeedbackResponse(**result) + except Exception as e: + logger.error(f"URL feedback error: {e}", exc_info=True) + raise HTTPException(status_code=500, detail=f"Feedback failed: {e}") + + +# ── Statistics ──────────────────────────────────────────────────────────────── + +@router.get("/stats", response_model=FeedbackStats) +async def get_feedback_stats(): + """Get aggregated RL feedback statistics for both channels.""" + try: + svc = get_feedback_service() + return FeedbackStats(**svc.get_stats()) + except Exception as e: + logger.error(f"Stats error: {e}", exc_info=True) + raise HTTPException(status_code=500, detail=str(e)) + + +# ── Model Update ───────────────────────────────────────────────────────────── + +@router.post("/update-model", response_model=ModelUpdateResponse) +async def update_model(body: ModelUpdateRequest): + """ + Trigger incremental model update using accumulated feedback. + + Uses XGBoost continuation training (xgb_model parameter) to add + additional boosting rounds from feedback samples without full re-training. + """ + try: + svc = get_feedback_service() + if body.model_type == "malware": + result = svc.update_malware_model( + min_samples=body.min_samples, + lr=body.learning_rate, + rounds=body.num_boost_rounds, + ) + elif body.model_type == "url": + result = svc.update_url_model( + min_samples=body.min_samples, + lr=body.learning_rate, + rounds=body.num_boost_rounds, + ) + else: + raise HTTPException( + status_code=400, + detail="model_type must be 'malware' or 'url'", + ) + return ModelUpdateResponse(**result) + except HTTPException: + raise + except Exception as e: + logger.error(f"Model update error: {e}", exc_info=True) + raise HTTPException(status_code=500, detail=f"Model update failed: {e}") + + +# ── Health ──────────────────────────────────────────────────────────────────── + +@router.get("/health") +async def feedback_health(): + """Health check for the RL feedback service.""" + try: + svc = get_feedback_service() + stats = svc.get_stats() + return { + "status": "healthy", + "malware_samples": stats["malware_total"], + "url_samples": stats["url_total"], + } + except Exception as e: + return {"status": "unhealthy", "error": str(e)} diff --git a/backend/app/routers/predict.py b/backend/app/routers/predict.py new file mode 100644 index 0000000000000000000000000000000000000000..281df60d3f55458c42495d91b4cd9a62dab85daf --- /dev/null +++ b/backend/app/routers/predict.py @@ -0,0 +1,205 @@ +""" +Prediction API Router. +Handles XGBoost malware prediction and Gemini explanation endpoints. +""" + +import logging +from fastapi import APIRouter, HTTPException, Depends +from typing import Optional +from pydantic import BaseModel, Field + +from ..models.prediction import ( + PredictionRequest, + PredictionResponse, + PredictionWithExplanationResponse, +) +from ..services.ml_service import get_ml_service, MLService +from ..services.gemini_service import get_gemini_service, GeminiService +from ..services.shap_service import get_shap_service, SHAPService +from ..services.malware_type_service import get_malware_type_service + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/predict", tags=["prediction"]) + + +class MalwareTypeInfo(BaseModel): + """Malware type classification result.""" + primary_type: str + confidence: str + secondary_types: list = [] + indicators: list = [] + source: str + + +class PredictionWithTypeResponse(BaseModel): + """Prediction response with malware type.""" + prediction: PredictionResponse + malware_type: Optional[MalwareTypeInfo] = None + + +@router.post("", response_model=PredictionWithTypeResponse) +async def predict( + request: PredictionRequest, + ml_service: MLService = Depends(get_ml_service) +) -> PredictionWithTypeResponse: + """ + Run XGBoost malware prediction on EMBER features. + + Accepts a feature vector of 2381 float values (EMBER 2018 v2 format) + and returns the prediction, probability, and confidence level. + + - **features**: List of 2381 float values (EMBER 2018 v2 features) + - **sha256**: Optional SHA256 hash for reference + - **threshold**: Optional custom prediction threshold (default: 0.5) + - **include_shap**: Include SHAP feature importance (slower) + """ + try: + # Run prediction + prediction = ml_service.predict( + features=request.features, + threshold=request.threshold, + sha256=request.sha256 + ) + + # Add SHAP analysis if requested + if request.include_shap: + shap_service = get_shap_service() + if not shap_service.initialized: + shap_service.initialize(ml_service.model) + + top_features = shap_service.get_feature_importance( + features=request.features, + model=ml_service.model, + top_k=10 + ) + prediction.top_features = top_features + + # Classify malware type if suspicious/malicious + malware_type_info = None + if prediction.prediction == "Malicious" or prediction.probability > 0.3: + try: + malware_type_service = get_malware_type_service() + # Use heuristic classification based on features + type_result = malware_type_service.classify() + malware_type_info = MalwareTypeInfo( + primary_type=type_result.primary_type, + confidence=type_result.confidence, + secondary_types=type_result.secondary_types, + indicators=type_result.indicators, + source=type_result.source + ) + except Exception as e: + logger.warning(f"Malware type classification failed: {e}") + + return PredictionWithTypeResponse( + prediction=prediction, + malware_type=malware_type_info + ) + + except ValueError as e: + logger.error(f"Validation error: {e}") + raise HTTPException(status_code=400, detail=str(e)) + except RuntimeError as e: + logger.error(f"Runtime error: {e}") + raise HTTPException(status_code=500, detail=str(e)) + except Exception as e: + logger.error(f"Prediction error: {e}") + raise HTTPException(status_code=500, detail="Prediction failed") + + +@router.post("/explain", response_model=PredictionWithExplanationResponse) +async def predict_with_explanation( + request: PredictionRequest, + ml_service: MLService = Depends(get_ml_service), + gemini_service: GeminiService = Depends(get_gemini_service) +) -> PredictionWithExplanationResponse: + """ + Run XGBoost prediction with Gemini AI explanation. + + Combines the XGBoost prediction with a detailed analysis from + Gemini AI explaining why the sample was classified as malicious + or benign. + + **Note**: Gemini does NOT override the model prediction. It only + provides explanation and context. + """ + try: + # Run prediction + prediction = ml_service.predict( + features=request.features, + threshold=request.threshold, + sha256=request.sha256 + ) + + # Get SHAP features for better explanation + shap_service = get_shap_service() + if not shap_service.initialized: + shap_service.initialize(ml_service.model) + + top_features = shap_service.get_feature_importance( + features=request.features, + model=ml_service.model, + top_k=10 + ) + prediction.top_features = top_features + + # Get Gemini explanation + explanation = await gemini_service.explain_prediction( + prediction=prediction, + features=top_features + ) + + # Classify malware type if suspicious/malicious + malware_type_info = None + if prediction.prediction == "Malicious" or prediction.probability > 0.3: + try: + from ..services.malware_type_service import get_malware_type_service + from ..models.prediction import MalwareTypeInfo + malware_type_service = get_malware_type_service() + type_result = malware_type_service.classify() + malware_type_info = MalwareTypeInfo( + primary_type=type_result.primary_type, + confidence=type_result.confidence, + secondary_types=type_result.secondary_types, + indicators=type_result.indicators, + source=type_result.source + ) + except Exception as e: + logger.warning(f"Malware type classification failed: {e}") + + return PredictionWithExplanationResponse( + prediction=prediction, + explanation=explanation, + malware_type=malware_type_info + ) + + except ValueError as e: + logger.error(f"Validation error: {e}") + raise HTTPException(status_code=400, detail=str(e)) + except RuntimeError as e: + logger.error(f"Runtime error: {e}") + raise HTTPException(status_code=500, detail=str(e)) + except Exception as e: + logger.error(f"Prediction with explanation error: {e}") + raise HTTPException(status_code=500, detail="Prediction with explanation failed") + + +@router.get("/model-info") +async def get_model_info( + ml_service: MLService = Depends(get_ml_service) +) -> dict: + """Get information about the loaded XGBoost model.""" + return ml_service.get_model_info() + + +@router.get("/health") +async def health_check( + ml_service: MLService = Depends(get_ml_service) +) -> dict: + """Health check endpoint for the prediction service.""" + return { + "status": "healthy", + "model_loaded": ml_service.model_loaded, + "feature_count": ml_service.feature_count + } diff --git a/backend/app/routers/upload.py b/backend/app/routers/upload.py new file mode 100644 index 0000000000000000000000000000000000000000..438dc0f72387bc51fc543978d0cc5af3087b4375 --- /dev/null +++ b/backend/app/routers/upload.py @@ -0,0 +1,284 @@ +""" +File Upload Router - Handle PE file uploads for malware analysis. +""" + +from fastapi import APIRouter, HTTPException, UploadFile, File, Depends +from pydantic import BaseModel, Field +from typing import Optional, List +import logging +import hashlib + + +from ..services.ember_features import extract_features_from_bytes, extract_features_and_lief, LIEF_AVAILABLE +from ..services.ml_service import get_ml_service +from ..services.shap_service import get_shap_service +from ..services.gemini_service import get_gemini_service +from ..services.malware_type_service import get_malware_type_service, MalwareTypeResult +from ..models.prediction import ( + PredictionResponse, + ConfidenceLevel, + GeminiExplanation, +) + +logger = logging.getLogger(__name__) + +router = APIRouter( + prefix="/api/upload", + tags=["upload"] +) + + + +class MalwareTypeInfo(BaseModel): + """Malware type classification result.""" + primary_type: str + confidence: str + secondary_types: List[str] = [] + indicators: List[str] = [] + source: str + + + +class FileAnalysisResponse(BaseModel): + """Response model for file analysis.""" + filename: str + sha256: str + file_size: int + features_extracted: bool + feature_count: int + features: Optional[List[float]] = None # Include features for copy functionality + prediction: Optional[PredictionResponse] = None + malware_type: Optional[MalwareTypeInfo] = None + explanation: Optional[GeminiExplanation] = None + error: Optional[str] = None + + + +class FeatureExtractionResponse(BaseModel): + """Response model for feature extraction only.""" + filename: str + sha256: str + file_size: int + features: List[float] + feature_count: int + + + +@router.post("/analyze", response_model=FileAnalysisResponse) +async def analyze_file( + file: UploadFile = File(..., description="PE file to analyze"), + include_explanation: bool = True +): + """ + Upload a PE file for complete malware analysis. + + This endpoint: + 1. Extracts EMBER 2018 v2 features from the PE file + 2. Runs XGBoost prediction + 3. Optionally generates Gemini AI explanation + + + **Supported files**: Windows PE executables (.exe, .dll, .sys, etc.) + + + **Note**: Maximum file size is 50MB. + """ + if not LIEF_AVAILABLE: + raise HTTPException( + status_code=503, + detail="PE parsing library (LIEF) is not available. Feature extraction disabled." + ) + + # Read file content + try: + content = await file.read() + except Exception as e: + raise HTTPException(status_code=400, detail=f"Failed to read file: {str(e)}") + + if len(content) == 0: + raise HTTPException(status_code=400, detail="Empty file uploaded") + + if len(content) > 50 * 1024 * 1024: # 50MB limit + raise HTTPException(status_code=400, detail="File too large. Maximum size is 50MB.") + + + # Check for PE signature (MZ header) + if content[:2] != b'MZ': + raise HTTPException( + status_code=400, + detail="Invalid PE file. File must be a Windows executable (PE format)." + ) + + + + filename = file.filename or "unknown" + file_size = len(content) + sha256 = hashlib.sha256(content).hexdigest() + + # Extract features and LIEF binary + lief_binary = None + try: + features, _, lief_binary = extract_features_and_lief(content) + features_list = features.tolist() + feature_count = len(features_list) + features_extracted = True + except Exception as e: + logger.error(f"Feature extraction failed for {filename}: {e}") + return FileAnalysisResponse( + filename=filename, + sha256=sha256, + file_size=file_size, + features_extracted=False, + feature_count=0, + error=f"Feature extraction failed: {str(e)}" + ) + + + # Run prediction + try: + ml_service = get_ml_service() + # ml_service.predict returns PredictionResponse directly + prediction_response = ml_service.predict(features_list, sha256=sha256) + except Exception as e: + logger.error(f"Prediction failed for {filename}: {e}") + return FileAnalysisResponse( + filename=filename, + sha256=sha256, + file_size=file_size, + features_extracted=True, + feature_count=feature_count, + error=f"Prediction failed: {str(e)}" + ) + + + + # Classify malware type if prediction is malware + malware_type_info = None + if prediction_response.prediction == "Malware" or prediction_response.probability > 0.3: + try: + malware_type_service = get_malware_type_service() + if lief_binary: + type_result = malware_type_service.classify_from_lief(lief_binary) + else: + type_result = malware_type_service.classify() + + malware_type_info = MalwareTypeInfo( + primary_type=type_result.primary_type, + confidence=type_result.confidence, + secondary_types=type_result.secondary_types, + indicators=type_result.indicators, + source=type_result.source + ) + except Exception as e: + logger.warning(f"Malware type classification failed: {e}") + + + + # Generate explanation if requested + explanation = None + if include_explanation: + try: + # Get SHAP feature importance + shap_service = get_shap_service() + feature_importance = None + if shap_service.initialized: + feature_importance = shap_service.explain(features_list) + + # Generate Gemini explanation + gemini_service = get_gemini_service() + if gemini_service.initialized: + explanation = await gemini_service.explain_prediction( + prediction_response, + feature_importance + ) + except Exception as e: + logger.warning(f"Explanation generation failed for {filename}: {e}") + # Continue without explanation + + + + return FileAnalysisResponse( + filename=filename, + sha256=sha256, + file_size=file_size, + features_extracted=True, + feature_count=feature_count, + features=features_list, # Include features for copy functionality + prediction=prediction_response, + malware_type=malware_type_info, + explanation=explanation + ) + + + +@router.post("/extract-features", response_model=FeatureExtractionResponse) +async def extract_features( + file: UploadFile = File(..., description="PE file to extract features from") +): + """ + Extract EMBER 2018 v2 features from a PE file without running prediction. + + Returns the 2381-dimensional feature vector that can be used + for custom analysis or stored for later prediction. + + **Supported files**: Windows PE executables (.exe, .dll, .sys, etc.) + """ + if not LIEF_AVAILABLE: + raise HTTPException( + status_code=503, + detail="PE parsing library (LIEF) is not available. Feature extraction disabled." + ) + + + # Read file content + try: + content = await file.read() + except Exception as e: + raise HTTPException(status_code=400, detail=f"Failed to read file: {str(e)}") + + if len(content) == 0: + raise HTTPException(status_code=400, detail="Empty file uploaded") + + if len(content) > 50 * 1024 * 1024: # 50MB limit + raise HTTPException(status_code=400, detail="File too large. Maximum size is 50MB.") + + # Check for PE signature + if content[:2] != b'MZ': + raise HTTPException( + status_code=400, + detail="Invalid PE file. File must be a Windows executable (PE format)." + ) + + filename = file.filename or "unknown" + + + # Extract features + try: + features, sha256 = extract_features_from_bytes(content) + features_list = features.tolist() + except Exception as e: + logger.error(f"Feature extraction failed for {filename}: {e}") + raise HTTPException( + status_code=500, + detail=f"Feature extraction failed: {str(e)}" + ) + + + return FeatureExtractionResponse( + filename=filename, + sha256=sha256, + file_size=len(content), + features=features_list, + feature_count=len(features_list) + ) + + + +@router.get("/health") +async def upload_health(): + """Check if the upload/feature extraction service is healthy.""" + return { + "status": "healthy" if LIEF_AVAILABLE else "degraded", + "lief_available": LIEF_AVAILABLE, + "feature_extraction": "enabled" if LIEF_AVAILABLE else "disabled" + } diff --git a/backend/app/routers/url.py b/backend/app/routers/url.py new file mode 100644 index 0000000000000000000000000000000000000000..4211cd18f1478be8fab434976ff0812ed7083459 --- /dev/null +++ b/backend/app/routers/url.py @@ -0,0 +1,89 @@ +""" +URL Analysis Router β€” Malicious URL detection via stacking HyperModel. + +Endpoints: + POST /api/url/analyze β€” Analyze a URL for malicious indicators + GET /api/url/model-info β€” Get URL model information + GET /api/url/health β€” Health check +""" + +import logging +from fastapi import APIRouter, HTTPException, Request +from slowapi import Limiter +from slowapi.util import get_remote_address + +from ..config import settings +from ..models.url import URLAnalyzeRequest, URLAnalyzeResponse, URLModelInfoResponse +from ..services.url_service import get_url_service + +logger = logging.getLogger(__name__) + +limiter = Limiter(key_func=get_remote_address) + +router = APIRouter( + prefix="/api/url", + tags=["URL Analysis"], + responses={404: {"description": "Not found"}}, +) + + +@router.post("/analyze", response_model=URLAnalyzeResponse) +async def analyze_url(request: Request, body: URLAnalyzeRequest): + """ + Analyze a URL for malicious indicators using the stacking HyperModel. + + The HyperModel combines 5 base models: + - XGBoost & LightGBM on 54 lexical features + - TF-IDF + Logistic Regression on raw URL text + - CharCNN & CharBiLSTM deep learning on character-level URL encoding + + Their probability outputs are stacked and fed to an XGBoost meta-learner. + """ + try: + url_service = get_url_service() + + if not url_service.model_loaded: + raise HTTPException(status_code=503, detail="URL model not loaded") + + threshold = body.threshold or settings.prediction_threshold + result = url_service.predict(body.url, threshold=threshold) + + logger.info( + f"URL analyzed: {body.url[:60]}... β†’ {result['prediction']} " + f"(score={result['malicious_score']:.4f}, {result['inference_time_ms']:.1f}ms)" + ) + + return URLAnalyzeResponse(**result) + + except HTTPException: + raise + except Exception as e: + logger.error(f"URL analysis failed: {e}", exc_info=True) + raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}") + + +@router.get("/model-info", response_model=URLModelInfoResponse) +async def url_model_info(): + """Get information about the URL detection model.""" + try: + url_service = get_url_service() + return URLModelInfoResponse(**url_service.get_model_info()) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + +@router.get("/health") +async def url_health(): + """Health check for URL analysis service.""" + try: + url_service = get_url_service() + return { + "status": "healthy" if url_service.model_loaded else "unhealthy", + "model_loaded": url_service.model_loaded, + "dl_available": url_service._dl_available, + } + except Exception as e: + return { + "status": "unhealthy", + "error": str(e), + } diff --git a/backend/app/routers/virustotal.py b/backend/app/routers/virustotal.py new file mode 100644 index 0000000000000000000000000000000000000000..60df669dcd00706fe89343076e97f0e96e1f4249 --- /dev/null +++ b/backend/app/routers/virustotal.py @@ -0,0 +1,167 @@ +""" +VirusTotal API Router. +Handles hash lookup and comparison endpoints. +""" + +import logging +from fastapi import APIRouter, HTTPException, Depends, Path +from pydantic import BaseModel, Field +from typing import List + +from ..models.virustotal import VirusTotalResponse +from ..models.prediction import ( + PredictionLabel, + CompareRequest, + ComparisonResult, +) +from ..services.virustotal_service import get_virustotal_service, VirusTotalService +from ..services.ml_service import get_ml_service, MLService +from ..services.feedback_service import get_feedback_service + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/virustotal", tags=["virustotal"]) + + +@router.get("/health") +async def health_check( + vt_service: VirusTotalService = Depends(get_virustotal_service) +) -> dict: + """Health check endpoint for VirusTotal service.""" + return { + "status": "healthy", + "api_configured": vt_service.initialized + } + + +@router.get("/{hash}", response_model=VirusTotalResponse) +async def lookup_hash( + hash: str = Path( + ..., + description="SHA256, SHA1, or MD5 hash to look up", + min_length=32, + max_length=64 + ), + vt_service: VirusTotalService = Depends(get_virustotal_service) +) -> VirusTotalResponse: + """ + Look up a file hash on VirusTotal. + + Returns detection results from multiple antivirus engines, + including detection ratio, engine verdicts, and reputation score. + + - **hash**: SHA256 (64 chars), SHA1 (40 chars), or MD5 (32 chars) + """ + # Basic validation + if len(hash) not in [32, 40, 64]: + raise HTTPException( + status_code=400, + detail="Invalid hash length. Expected MD5 (32), SHA1 (40), or SHA256 (64)" + ) + + if not all(c in '0123456789abcdefABCDEF' for c in hash): + raise HTTPException( + status_code=400, + detail="Invalid hash format. Only hexadecimal characters allowed." + ) + + result = await vt_service.lookup_hash(hash.lower()) + + if not result.found and result.error_message: + # Don't raise error for "not found" - just return the response + if "not found" not in result.error_message.lower(): + logger.warning(f"VirusTotal lookup issue: {result.error_message}") + + return result + + +@router.post("/compare", response_model=ComparisonResult) +async def compare_predictions( + request: CompareRequest, + ml_service: MLService = Depends(get_ml_service), + vt_service: VirusTotalService = Depends(get_virustotal_service) +) -> ComparisonResult: + """ + Compare XGBoost prediction with VirusTotal results. + + Runs the XGBoost model on the provided features and queries + VirusTotal for the hash, then compares the verdicts. + + Returns an agreement indicator showing whether both systems + agree on whether the sample is malicious or benign. + """ + try: + # Run XGBoost prediction + prediction = ml_service.predict( + features=request.features, + sha256=request.sha256 + ) + + # Query VirusTotal + vt_result = await vt_service.lookup_hash(request.sha256) + + if not vt_result.found: + raise HTTPException( + status_code=404, + detail=f"Hash not found on VirusTotal: {vt_result.error_message or 'Unknown error'}" + ) + + # Determine VirusTotal verdict + # Consider malicious if >10% of engines detect it + vt_is_malicious = ( + vt_result.detection_ratio is not None and + vt_result.detection_ratio > 0.1 + ) + xgb_is_malicious = prediction.prediction == PredictionLabel.MALICIOUS + + # Check agreement + agreement = vt_is_malicious == xgb_is_malicious + + if agreement: + if xgb_is_malicious: + agreement_desc = "Both XGBoost and VirusTotal flag this sample as malicious." + else: + agreement_desc = "Both XGBoost and VirusTotal consider this sample benign." + else: + if xgb_is_malicious: + agreement_desc = "XGBoost flags as malicious, but VirusTotal has low detection rate." + else: + agreement_desc = "VirusTotal flags as malicious, but XGBoost predicts benign." + + # ── Log RL feedback from the comparison ────────────────────────── + try: + feedback_svc = get_feedback_service() + rl_result = feedback_svc.log_malware_feedback( + features=request.features, + sha256=request.sha256, + predicted=prediction.prediction.value, + probability=prediction.probability, + vt_mal=vt_result.malicious_count or 0, + vt_total=vt_result.total_engines or 0, + vt_ratio=vt_result.detection_ratio or 0.0, + ) + # Auto-trigger incremental update when enough samples accumulate + feedback_svc.maybe_auto_update("malware") + logger.info(f"Compare RL feedback: reward={rl_result['reward']}") + except Exception as e: + logger.warning(f"RL feedback during compare failed (non-critical): {e}") + + return ComparisonResult( + xgboost_prediction=prediction.prediction, + xgboost_probability=prediction.probability, + virustotal_malicious_count=vt_result.malicious_count or 0, + virustotal_total_engines=vt_result.total_engines or 0, + virustotal_detection_ratio=vt_result.detection_ratio or 0.0, + agreement=agreement, + agreement_description=agreement_desc + ) + + except HTTPException: + raise + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + except Exception as e: + logger.error(f"Comparison error: {e}") + raise HTTPException(status_code=500, detail="Comparison failed") + + diff --git a/backend/app/services/__init__.py b/backend/app/services/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ca92f0ddcb6dab031fad5968419b1548e88c5036 --- /dev/null +++ b/backend/app/services/__init__.py @@ -0,0 +1,6 @@ +# Services package +from .ml_service import MLService, get_ml_service +from .gemini_service import GeminiService, get_gemini_service +from .virustotal_service import VirusTotalService, get_virustotal_service +from .shap_service import SHAPService, get_shap_service +from .feedback_service import FeedbackService, get_feedback_service diff --git a/backend/app/services/ember_features.py b/backend/app/services/ember_features.py new file mode 100644 index 0000000000000000000000000000000000000000..00d1cf00464ffa0f4bf7ab177ef1469ef03abdfd --- /dev/null +++ b/backend/app/services/ember_features.py @@ -0,0 +1,645 @@ +""" +EMBER Feature Extraction Service +Ported from elastic/ember for Python 3.12+ compatibility + +Extracts 2381 features from PE (Portable Executable) files for malware detection. +Based on EMBER 2018 v2 feature format. + +Original source: https://github.com/elastic/ember +""" + +import re +import hashlib +import logging +import numpy as np +from typing import Dict, List, Any, Optional, Tuple + +logger = logging.getLogger(__name__) + +# Try to import lief - required for PE parsing +try: + import lief + LIEF_AVAILABLE = True + LIEF_MAJOR, LIEF_MINOR, *_ = lief.__version__.split('.') + LIEF_MAJOR = int(LIEF_MAJOR) + LIEF_MINOR = int(LIEF_MINOR) + LIEF_EXPORT_OBJECT = LIEF_MAJOR > 0 or (LIEF_MAJOR == 0 and LIEF_MINOR >= 10) + LIEF_HAS_SIGNATURE = LIEF_MAJOR > 0 or (LIEF_MAJOR == 0 and LIEF_MINOR >= 11) + logger.info(f"LIEF version {lief.__version__} loaded successfully") +except ImportError: + LIEF_AVAILABLE = False + LIEF_MAJOR = LIEF_MINOR = 0 + LIEF_EXPORT_OBJECT = False + LIEF_HAS_SIGNATURE = False + logger.warning("LIEF library not available. PE feature extraction disabled.") + +# Try to import sklearn FeatureHasher +try: + from sklearn.feature_extraction import FeatureHasher + SKLEARN_AVAILABLE = True +except ImportError: + SKLEARN_AVAILABLE = False + logger.warning("sklearn not available. Feature hashing disabled.") + + +class FeatureType: + """Base class for feature extractors.""" + name = '' + dim = 0 + + def __repr__(self): + return f'{self.name}({self.dim})' + + def raw_features(self, bytez: bytes, lief_binary) -> Any: + """Generate JSON-able representation of the file.""" + raise NotImplementedError + + def process_raw_features(self, raw_obj: Any) -> np.ndarray: + """Generate a feature vector from raw features.""" + raise NotImplementedError + + def feature_vector(self, bytez: bytes, lief_binary) -> np.ndarray: + """Calculate feature vector directly from sample.""" + return self.process_raw_features(self.raw_features(bytez, lief_binary)) + + +class ByteHistogram(FeatureType): + """Byte histogram (normalized) over the entire binary file.""" + name = 'histogram' + dim = 256 + + def raw_features(self, bytez: bytes, lief_binary) -> List[int]: + counts = np.bincount(np.frombuffer(bytez, dtype=np.uint8), minlength=256) + return counts.tolist() + + def process_raw_features(self, raw_obj: List[int]) -> np.ndarray: + counts = np.array(raw_obj, dtype=np.float32) + total = counts.sum() + if total > 0: + normalized = counts / total + else: + normalized = counts + return normalized + + +class ByteEntropyHistogram(FeatureType): + """ + 2D byte/entropy histogram based on Saxe and Berlin, 2015. + Approximates the joint probability of byte value and local entropy. + """ + name = 'byteentropy' + dim = 256 + + def __init__(self, step: int = 1024, window: int = 2048): + self.window = window + self.step = step + + def _entropy_bin_counts(self, block: np.ndarray) -> Tuple[int, np.ndarray]: + """Calculate entropy bin and coarse histogram.""" + # Coarse histogram, 16 bytes per bin + c = np.bincount(block >> 4, minlength=16) + p = c.astype(np.float32) / self.window + wh = np.where(c)[0] + + if len(wh) > 0: + H = np.sum(-p[wh] * np.log2(p[wh])) * 2 + else: + H = 0.0 + + Hbin = int(H * 2) # Up to 16 bins (max entropy is 8 bits) + if Hbin == 16: + Hbin = 15 + + return Hbin, c + + def raw_features(self, bytez: bytes, lief_binary) -> List[int]: + output = np.zeros((16, 16), dtype=np.int64) + a = np.frombuffer(bytez, dtype=np.uint8) + + if a.shape[0] < self.window: + Hbin, c = self._entropy_bin_counts(a) + output[Hbin, :] += c + else: + # Strided trick for efficiency + shape = a.shape[:-1] + (a.shape[-1] - self.window + 1, self.window) + strides = a.strides + (a.strides[-1],) + blocks = np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)[::self.step, :] + + for block in blocks: + Hbin, c = self._entropy_bin_counts(block) + output[Hbin, :] += c + + return output.flatten().tolist() + + def process_raw_features(self, raw_obj: List[int]) -> np.ndarray: + counts = np.array(raw_obj, dtype=np.float32) + total = counts.sum() + if total > 0: + normalized = counts / total + else: + normalized = counts + return normalized + + +class StringExtractor(FeatureType): + """Extract string-based features from raw byte stream.""" + name = 'strings' + dim = 104 # 1 + 1 + 1 + 96 + 1 + 1 + 1 + 1 + 1 + + def __init__(self): + # All consecutive runs of printable ASCII (0x20-0x7f) that are 5+ chars + self._allstrings = re.compile(b'[\x20-\x7f]{5,}') + # Occurrences of 'C:\' + self._paths = re.compile(b'c:\\\\', re.IGNORECASE) + # Occurrences of http:// or https:// + self._urls = re.compile(b'https?://', re.IGNORECASE) + # Occurrences of HKEY_ + self._registry = re.compile(b'HKEY_') + # Evidence of MZ header (dropper?) + self._mz = re.compile(b'MZ') + + def raw_features(self, bytez: bytes, lief_binary) -> Dict: + allstrings = self._allstrings.findall(bytez) + + if allstrings: + string_lengths = [len(s) for s in allstrings] + avlength = sum(string_lengths) / len(string_lengths) + + # Map printable characters 0x20-0x7f to int array 0-95 + as_shifted_string = [b - ord(b'\x20') for b in b''.join(allstrings)] + c = np.bincount(as_shifted_string, minlength=96) + csum = c.sum() + p = c.astype(np.float32) / csum if csum > 0 else c.astype(np.float32) + wh = np.where(c)[0] + H = np.sum(-p[wh] * np.log2(p[wh])) if len(wh) > 0 else 0.0 + else: + avlength = 0 + c = np.zeros((96,), dtype=np.float32) + H = 0 + csum = 0 + + return { + 'numstrings': len(allstrings), + 'avlength': avlength, + 'printabledist': c.tolist(), + 'printables': int(csum), + 'entropy': float(H), + 'paths': len(self._paths.findall(bytez)), + 'urls': len(self._urls.findall(bytez)), + 'registry': len(self._registry.findall(bytez)), + 'MZ': len(self._mz.findall(bytez)) + } + + def process_raw_features(self, raw_obj: Dict) -> np.ndarray: + hist_divisor = float(raw_obj['printables']) if raw_obj['printables'] > 0 else 1.0 + return np.hstack([ + raw_obj['numstrings'], + raw_obj['avlength'], + raw_obj['printables'], + np.asarray(raw_obj['printabledist']) / hist_divisor, + raw_obj['entropy'], + raw_obj['paths'], + raw_obj['urls'], + raw_obj['registry'], + raw_obj['MZ'] + ]).astype(np.float32) + + +class GeneralFileInfo(FeatureType): + """General information about the PE file.""" + name = 'general' + dim = 10 + + def raw_features(self, bytez: bytes, lief_binary) -> Dict: + if lief_binary is None: + return { + 'size': len(bytez), + 'vsize': 0, + 'has_debug': 0, + 'exports': 0, + 'imports': 0, + 'has_relocations': 0, + 'has_resources': 0, + 'has_signature': 0, + 'has_tls': 0, + 'symbols': 0 + } + + return { + 'size': len(bytez), + 'vsize': lief_binary.virtual_size, + 'has_debug': int(lief_binary.has_debug), + 'exports': len(lief_binary.exported_functions), + 'imports': len(lief_binary.imported_functions), + 'has_relocations': int(lief_binary.has_relocations), + 'has_resources': int(lief_binary.has_resources), + 'has_signature': int(lief_binary.has_signatures) if LIEF_HAS_SIGNATURE else int(lief_binary.has_signature), + 'has_tls': int(lief_binary.has_tls), + 'symbols': len(lief_binary.symbols), + } + + def process_raw_features(self, raw_obj: Dict) -> np.ndarray: + return np.asarray([ + raw_obj['size'], + raw_obj['vsize'], + raw_obj['has_debug'], + raw_obj['exports'], + raw_obj['imports'], + raw_obj['has_relocations'], + raw_obj['has_resources'], + raw_obj['has_signature'], + raw_obj['has_tls'], + raw_obj['symbols'] + ], dtype=np.float32) + + +class HeaderFileInfo(FeatureType): + """Machine, architecture, OS, linker and other header information.""" + name = 'header' + dim = 62 + + def raw_features(self, bytez: bytes, lief_binary) -> Dict: + raw_obj = { + 'coff': {'timestamp': 0, 'machine': "", 'characteristics': []}, + 'optional': { + 'subsystem': "", + 'dll_characteristics': [], + 'magic': "", + 'major_image_version': 0, + 'minor_image_version': 0, + 'major_linker_version': 0, + 'minor_linker_version': 0, + 'major_operating_system_version': 0, + 'minor_operating_system_version': 0, + 'major_subsystem_version': 0, + 'minor_subsystem_version': 0, + 'sizeof_code': 0, + 'sizeof_headers': 0, + 'sizeof_heap_commit': 0 + } + } + + if lief_binary is None: + return raw_obj + + raw_obj['coff']['timestamp'] = lief_binary.header.time_date_stamps + raw_obj['coff']['machine'] = str(lief_binary.header.machine).split('.')[-1] + raw_obj['coff']['characteristics'] = [ + str(c).split('.')[-1] for c in lief_binary.header.characteristics_list + ] + + raw_obj['optional']['subsystem'] = str(lief_binary.optional_header.subsystem).split('.')[-1] + raw_obj['optional']['dll_characteristics'] = [ + str(c).split('.')[-1] for c in lief_binary.optional_header.dll_characteristics_lists + ] + raw_obj['optional']['magic'] = str(lief_binary.optional_header.magic).split('.')[-1] + raw_obj['optional']['major_image_version'] = lief_binary.optional_header.major_image_version + raw_obj['optional']['minor_image_version'] = lief_binary.optional_header.minor_image_version + raw_obj['optional']['major_linker_version'] = lief_binary.optional_header.major_linker_version + raw_obj['optional']['minor_linker_version'] = lief_binary.optional_header.minor_linker_version + raw_obj['optional']['major_operating_system_version'] = lief_binary.optional_header.major_operating_system_version + raw_obj['optional']['minor_operating_system_version'] = lief_binary.optional_header.minor_operating_system_version + raw_obj['optional']['major_subsystem_version'] = lief_binary.optional_header.major_subsystem_version + raw_obj['optional']['minor_subsystem_version'] = lief_binary.optional_header.minor_subsystem_version + raw_obj['optional']['sizeof_code'] = lief_binary.optional_header.sizeof_code + raw_obj['optional']['sizeof_headers'] = lief_binary.optional_header.sizeof_headers + raw_obj['optional']['sizeof_heap_commit'] = lief_binary.optional_header.sizeof_heap_commit + + return raw_obj + + def process_raw_features(self, raw_obj: Dict) -> np.ndarray: + return np.hstack([ + raw_obj['coff']['timestamp'], + FeatureHasher(10, input_type="string").transform([[raw_obj['coff']['machine']]]).toarray()[0], + FeatureHasher(10, input_type="string").transform([raw_obj['coff']['characteristics']]).toarray()[0], + FeatureHasher(10, input_type="string").transform([[raw_obj['optional']['subsystem']]]).toarray()[0], + FeatureHasher(10, input_type="string").transform([raw_obj['optional']['dll_characteristics']]).toarray()[0], + FeatureHasher(10, input_type="string").transform([[raw_obj['optional']['magic']]]).toarray()[0], + raw_obj['optional']['major_image_version'], + raw_obj['optional']['minor_image_version'], + raw_obj['optional']['major_linker_version'], + raw_obj['optional']['minor_linker_version'], + raw_obj['optional']['major_operating_system_version'], + raw_obj['optional']['minor_operating_system_version'], + raw_obj['optional']['major_subsystem_version'], + raw_obj['optional']['minor_subsystem_version'], + raw_obj['optional']['sizeof_code'], + raw_obj['optional']['sizeof_headers'], + raw_obj['optional']['sizeof_heap_commit'], + ]).astype(np.float32) + + +class SectionInfo(FeatureType): + """Information about section names, sizes and entropy.""" + name = 'section' + dim = 255 # 5 + 50 + 50 + 50 + 50 + 50 + + @staticmethod + def _properties(s) -> List[str]: + return [str(c).split('.')[-1] for c in s.characteristics_lists] + + def raw_features(self, bytez: bytes, lief_binary) -> Dict: + if lief_binary is None: + return {"entry": "", "sections": []} + + # Find entry section + try: + if LIEF_MAJOR > 0 or (LIEF_MAJOR == 0 and LIEF_MINOR >= 12): + section = lief_binary.section_from_rva( + lief_binary.entrypoint - lief_binary.imagebase + ) + if section is None: + raise lief.not_found + entry_section = section.name + else: + entry_section = lief_binary.section_from_offset(lief_binary.entrypoint).name + except: + # Bad entry point, find first executable section + entry_section = "" + for s in lief_binary.sections: + if lief.PE.SECTION_CHARACTERISTICS.MEM_EXECUTE in s.characteristics_lists: + entry_section = s.name + break + + raw_obj = {"entry": entry_section} + raw_obj["sections"] = [{ + 'name': s.name, + 'size': s.size, + 'entropy': s.entropy, + 'vsize': s.virtual_size, + 'props': self._properties(s) + } for s in lief_binary.sections] + + return raw_obj + + def process_raw_features(self, raw_obj: Dict) -> np.ndarray: + sections = raw_obj['sections'] + general = [ + len(sections), + sum(1 for s in sections if s['size'] == 0), + sum(1 for s in sections if s['name'] == ""), + sum(1 for s in sections if 'MEM_READ' in s['props'] and 'MEM_EXECUTE' in s['props']), + sum(1 for s in sections if 'MEM_WRITE' in s['props']) + ] + + # Section characteristics hashed + section_sizes = [(s['name'], s['size']) for s in sections] + section_sizes_hashed = FeatureHasher(50, input_type="pair").transform([section_sizes]).toarray()[0] + + section_entropy = [(s['name'], s['entropy']) for s in sections] + section_entropy_hashed = FeatureHasher(50, input_type="pair").transform([section_entropy]).toarray()[0] + + section_vsize = [(s['name'], s['vsize']) for s in sections] + section_vsize_hashed = FeatureHasher(50, input_type="pair").transform([section_vsize]).toarray()[0] + + entry_name_hashed = FeatureHasher(50, input_type="string").transform([[raw_obj['entry']]]).toarray()[0] + + characteristics = [p for s in sections for p in s['props'] if s['name'] == raw_obj['entry']] + characteristics_hashed = FeatureHasher(50, input_type="string").transform([characteristics]).toarray()[0] + + return np.hstack([ + general, + section_sizes_hashed, + section_entropy_hashed, + section_vsize_hashed, + entry_name_hashed, + characteristics_hashed + ]).astype(np.float32) + + +class ImportsInfo(FeatureType): + """Information about imported libraries and functions.""" + name = 'imports' + dim = 1280 + + def raw_features(self, bytez: bytes, lief_binary) -> Dict[str, List[str]]: + imports = {} + if lief_binary is None: + return imports + + for lib in lief_binary.imports: + if lib.name not in imports: + imports[lib.name] = [] + + for entry in lib.entries: + if entry.is_ordinal: + imports[lib.name].append("ordinal" + str(entry.ordinal)) + else: + imports[lib.name].append(entry.name[:10000]) + + return imports + + def process_raw_features(self, raw_obj: Dict[str, List[str]]) -> np.ndarray: + # Unique libraries + libraries = list(set([l.lower() for l in raw_obj.keys()])) + libraries_hashed = FeatureHasher(256, input_type="string").transform([libraries]).toarray()[0] + + # Fully qualified import names + imports = [lib.lower() + ':' + e for lib, elist in raw_obj.items() for e in elist] + imports_hashed = FeatureHasher(1024, input_type="string").transform([imports]).toarray()[0] + + return np.hstack([libraries_hashed, imports_hashed]).astype(np.float32) + + +class ExportsInfo(FeatureType): + """Information about exported functions.""" + name = 'exports' + dim = 128 + + def raw_features(self, bytez: bytes, lief_binary) -> List[str]: + if lief_binary is None: + return [] + + if LIEF_EXPORT_OBJECT: + clipped_exports = [export.name[:10000] for export in lief_binary.exported_functions] + else: + clipped_exports = [export[:10000] for export in lief_binary.exported_functions] + + return clipped_exports + + def process_raw_features(self, raw_obj: List[str]) -> np.ndarray: + exports_hashed = FeatureHasher(128, input_type="string").transform([raw_obj]).toarray()[0] + return exports_hashed.astype(np.float32) + + +class DataDirectories(FeatureType): + """Size and virtual address of the first 15 data directories.""" + name = 'datadirectories' + dim = 30 # 15 * 2 + + def __init__(self): + self._name_order = [ + "EXPORT_TABLE", "IMPORT_TABLE", "RESOURCE_TABLE", "EXCEPTION_TABLE", + "CERTIFICATE_TABLE", "BASE_RELOCATION_TABLE", "DEBUG", "ARCHITECTURE", + "GLOBAL_PTR", "TLS_TABLE", "LOAD_CONFIG_TABLE", "BOUND_IMPORT", + "IAT", "DELAY_IMPORT_DESCRIPTOR", "CLR_RUNTIME_HEADER" + ] + + def raw_features(self, bytez: bytes, lief_binary) -> List[Dict]: + output = [] + if lief_binary is None: + return output + + for data_directory in lief_binary.data_directories: + output.append({ + "name": str(data_directory.type).replace("DATA_DIRECTORY.", ""), + "size": data_directory.size, + "virtual_address": data_directory.rva + }) + return output + + def process_raw_features(self, raw_obj: List[Dict]) -> np.ndarray: + features = np.zeros(2 * len(self._name_order), dtype=np.float32) + for i in range(len(self._name_order)): + if i < len(raw_obj): + features[2 * i] = raw_obj[i]["size"] + features[2 * i + 1] = raw_obj[i]["virtual_address"] + return features + + +class PEFeatureExtractor: + """ + Extract 2381 features from a PE file (EMBER 2018 v2 format). + + Usage: + extractor = PEFeatureExtractor() + with open("sample.exe", "rb") as f: + features = extractor.feature_vector(f.read()) + # features is now a numpy array of 2381 float values + """ + + def __init__(self, feature_version: int = 2): + if not LIEF_AVAILABLE: + raise ImportError("LIEF library is required for PE feature extraction. Install with: pip install lief") + + if not SKLEARN_AVAILABLE: + raise ImportError("scikit-learn is required for feature hashing. Install with: pip install scikit-learn") + + self.features = [ + ByteHistogram(), + ByteEntropyHistogram(), + StringExtractor(), + GeneralFileInfo(), + HeaderFileInfo(), + SectionInfo(), + ImportsInfo(), + ExportsInfo(), + ] + + if feature_version == 2: + self.features.append(DataDirectories()) + + self.dim = sum([fe.dim for fe in self.features]) + logger.info(f"PEFeatureExtractor initialized with {self.dim} features (version {feature_version})") + + def raw_features(self, bytez: bytes) -> Dict[str, Any]: + """Extract raw features from PE bytes.""" + lief_binary = None + + try: + lief_binary = lief.PE.parse(list(bytez)) + except Exception as e: + logger.warning(f"LIEF parsing error: {e}") + lief_binary = None + + features = {"sha256": hashlib.sha256(bytez).hexdigest()} + features.update({fe.name: fe.raw_features(bytez, lief_binary) for fe in self.features}) + return features + + def process_raw_features(self, raw_obj: Dict[str, Any]) -> np.ndarray: + """Process raw features into a feature vector.""" + feature_vectors = [fe.process_raw_features(raw_obj[fe.name]) for fe in self.features] + return np.hstack(feature_vectors).astype(np.float32) + + def feature_vector(self, bytez: bytes) -> np.ndarray: + """ + Extract feature vector directly from PE file bytes. + + Args: + bytez: Raw bytes of the PE file + + Returns: + numpy array of 2381 float32 features + """ + return self.process_raw_features(self.raw_features(bytez)) + + def extract_with_hash(self, bytez: bytes) -> Tuple[np.ndarray, str]: + """ + Extract features and return SHA256 hash. + + Args: + bytez: Raw bytes of the PE file + + Returns: + Tuple of (feature_vector, sha256_hash) + """ + raw = self.raw_features(bytez) + return self.process_raw_features(raw), raw["sha256"] + + +# Singleton instance +_extractor_instance: Optional[PEFeatureExtractor] = None + + +def get_feature_extractor() -> PEFeatureExtractor: + """Get or create the singleton feature extractor.""" + global _extractor_instance + if _extractor_instance is None: + _extractor_instance = PEFeatureExtractor() + return _extractor_instance + + +def extract_features_from_file(file_path: str) -> Tuple[np.ndarray, str]: + """ + Extract EMBER features from a PE file. + + Args: + file_path: Path to the PE file + + Returns: + Tuple of (feature_vector, sha256_hash) + """ + with open(file_path, 'rb') as f: + bytez = f.read() + + extractor = get_feature_extractor() + return extractor.extract_with_hash(bytez) + + +def extract_features_from_bytes(bytez: bytes) -> Tuple[np.ndarray, str]: + """ + Extract EMBER features from PE file bytes. + + Args: + bytez: Raw bytes of the PE file + + Returns: + Tuple of (feature_vector, sha256_hash) + """ + extractor = get_feature_extractor() + return extractor.extract_with_hash(bytez) + + +def extract_features_and_lief(bytez: bytes) -> Tuple[np.ndarray, str, any]: + """ + Extract EMBER features and return LIEF binary for additional analysis. + + Args: + bytez: Raw bytes of the PE file + + Returns: + Tuple of (feature_vector, sha256_hash, lief_binary) + """ + if not LIEF_AVAILABLE: + raise ImportError("LIEF is not available") + + extractor = get_feature_extractor() + features, sha256 = extractor.extract_with_hash(bytez) + + # Parse with LIEF for additional analysis + try: + lief_binary = lief.PE.parse(list(bytez)) + except Exception: + lief_binary = None + + return features, sha256, lief_binary diff --git a/backend/app/services/feedback_service.py b/backend/app/services/feedback_service.py new file mode 100644 index 0000000000000000000000000000000000000000..33c0e80a9d0fd59c9e4353bff88a0321fb40e4b0 --- /dev/null +++ b/backend/app/services/feedback_service.py @@ -0,0 +1,474 @@ +""" +Reinforcement Learning Feedback Service + +Persistent SQLite store for reward signals + incremental model updates. + +Malware channel: XGBoost prediction vs VirusTotal consensus β†’ auto-reward +URL channel: user confirms/denies model verdict β†’ manual reward + +Model updates use XGBoost's `xgb_model` parameter for incremental boosting +from the existing model β€” no full re-training required. +""" + +from __future__ import annotations + +import json +import logging +import sqlite3 +import time +from datetime import datetime, timezone +from pathlib import Path +from typing import Optional + +import joblib +import numpy as np + +logger = logging.getLogger(__name__) + +# Database lives alongside backend code β€” not committed to git +_DB_DIR = Path(__file__).parent.parent.parent.parent / "data" +_DB_PATH = _DB_DIR / "feedback.db" + + +class FeedbackService: + """SQLite-backed RL feedback store with incremental training.""" + + def __init__(self): + _DB_DIR.mkdir(parents=True, exist_ok=True) + self._conn: Optional[sqlite3.Connection] = None + self._init_db() + + # ── Database setup ──────────────────────────────────────────────────── + + def _get_conn(self) -> sqlite3.Connection: + if self._conn is None: + self._conn = sqlite3.connect(str(_DB_PATH), check_same_thread=False) + self._conn.row_factory = sqlite3.Row + self._conn.execute("PRAGMA journal_mode=WAL") + return self._conn + # Create the Feedback In Database + def _init_db(self): + conn = self._get_conn() + conn.executescript(""" + CREATE TABLE IF NOT EXISTS malware_feedback ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + sha256 TEXT NOT NULL, + features TEXT NOT NULL, + predicted TEXT NOT NULL, + probability REAL NOT NULL, + vt_ratio REAL NOT NULL, + vt_mal INTEGER NOT NULL, + vt_total INTEGER NOT NULL, + reward INTEGER NOT NULL, + correct_label TEXT NOT NULL, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS url_feedback ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + url TEXT NOT NULL, + predicted TEXT NOT NULL, + malicious_score REAL NOT NULL, + reward INTEGER NOT NULL, + correct_label TEXT NOT NULL, + base_model_scores TEXT NOT NULL, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS model_updates ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + model_type TEXT NOT NULL, + samples_used INTEGER NOT NULL, + lr REAL NOT NULL, + rounds INTEGER NOT NULL, + created_at TEXT NOT NULL + ); + """) + conn.commit() + logger.info(f"Feedback DB ready at {_DB_PATH}") + + # ── Malware feedback ────────────────────────────────────────────────── + + def log_malware_feedback( + self, + features: list[float], + sha256: str, + predicted: str, + probability: float, + vt_mal: int, + vt_total: int, + vt_ratio: float, + ) -> dict: + """ + Log malware prediction feedback based on VirusTotal agreement. + + Reward logic: + VT considers malicious if detection_ratio > 0.1 + +1 if XGBoost and VT agree + -1 if they disagree + """ + vt_is_malicious = vt_ratio > 0.1 + xgb_is_malicious = predicted.lower() == "malicious" + agree = vt_is_malicious == xgb_is_malicious + reward = 1 if agree else -1 + + # Correct label according to VT consensus + correct_label = "Malicious" if vt_is_malicious else "Benign" + + now = datetime.now(timezone.utc).isoformat() + conn = self._get_conn() + conn.execute( + """INSERT INTO malware_feedback + (sha256, features, predicted, probability, vt_ratio, vt_mal, vt_total, + reward, correct_label, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", + ( + sha256, + json.dumps(features), + predicted, + probability, + vt_ratio, + vt_mal, + vt_total, + reward, + correct_label, + now, + ), + ) + conn.commit() + + total = conn.execute("SELECT COUNT(*) FROM malware_feedback").fetchone()[0] + logger.info( + f"Malware RL: sha256={sha256[:12]}… pred={predicted} vt_ratio={vt_ratio:.2f} " + f"reward={reward:+d} (total={total})" + ) + return { + "success": True, + "reward": reward, + "message": f"{'Agreement' if agree else 'Disagreement'} with VirusTotal logged", + "total_feedback_count": total, + } + + # ── URL feedback ────────────────────────────────────────────────────── + + def log_url_feedback( + self, + url: str, + predicted: str, + malicious_score: float, + is_correct: bool, + base_model_scores: dict, + ) -> dict: + """ + Log URL prediction feedback from user. + + +1 if user says prediction is correct + -1 if user says prediction is wrong + """ + reward = 1 if is_correct else -1 + + if is_correct: + correct_label = predicted + else: + correct_label = "Benign" if predicted == "Malicious" else "Malicious" + + now = datetime.now(timezone.utc).isoformat() + conn = self._get_conn() + conn.execute( + """INSERT INTO url_feedback + (url, predicted, malicious_score, reward, correct_label, + base_model_scores, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?)""", + ( + url, + predicted, + malicious_score, + reward, + correct_label, + json.dumps(base_model_scores), + now, + ), + ) + conn.commit() + + total = conn.execute("SELECT COUNT(*) FROM url_feedback").fetchone()[0] + logger.info( + f"URL RL: url={url[:40]}… pred={predicted} correct={is_correct} " + f"reward={reward:+d} (total={total})" + ) + return { + "success": True, + "reward": reward, + "message": f"Feedback recorded β€” {'correct' if is_correct else 'incorrect'} prediction", + "total_feedback_count": total, + } + + # ── Statistics ──────────────────────────────────────────────────────── + + # Auto-update threshold: update model after this many NEW samples since last update + AUTO_UPDATE_THRESHOLD = 50 + + def maybe_auto_update(self, model_type: str) -> Optional[dict]: + """ + Check if enough feedback has accumulated since the last + incremental update and trigger one automatically. + + Returns update result dict or None if threshold not yet reached. + """ + conn = self._get_conn() + table = "malware_feedback" if model_type == "malware" else "url_feedback" + + total_feedback = conn.execute(f"SELECT COUNT(*) FROM {table}").fetchone()[0] + + # How many samples were used in the most recent update? + row = conn.execute( + "SELECT samples_used FROM model_updates " + "WHERE model_type = ? ORDER BY id DESC LIMIT 1", + (model_type,), + ).fetchone() + last_samples = row["samples_used"] if row else 0 + + new_samples = total_feedback - last_samples + if new_samples >= self.AUTO_UPDATE_THRESHOLD: + logger.info( + f"Auto-update triggered for {model_type}: " + f"{new_samples} new samples β‰₯ {self.AUTO_UPDATE_THRESHOLD}" + ) + try: + if model_type == "malware": + return self.update_malware_model(min_samples=1) + else: + return self.update_url_model(min_samples=1) + except Exception as e: + logger.error(f"Auto-update failed for {model_type}: {e}") + return None + return None + + def get_stats(self) -> dict: + conn = self._get_conn() + + # Malware stats + m_total = conn.execute("SELECT COUNT(*) FROM malware_feedback").fetchone()[0] + m_agree = conn.execute( + "SELECT COUNT(*) FROM malware_feedback WHERE reward = 1" + ).fetchone()[0] + m_disagree = m_total - m_agree + m_rate = (m_agree / m_total * 100) if m_total > 0 else 0.0 + + # URL stats + u_total = conn.execute("SELECT COUNT(*) FROM url_feedback").fetchone()[0] + u_correct = conn.execute( + "SELECT COUNT(*) FROM url_feedback WHERE reward = 1" + ).fetchone()[0] + u_incorrect = u_total - u_correct + u_rate = (u_correct / u_total * 100) if u_total > 0 else 0.0 + + # Recent malware feedback (last 10) + recent_m = [ + dict(r) + for r in conn.execute( + "SELECT id, sha256, predicted, probability, vt_ratio, reward, created_at " + "FROM malware_feedback ORDER BY id DESC LIMIT 10" + ).fetchall() + ] + + # Recent URL feedback (last 10) + recent_u = [ + dict(r) + for r in conn.execute( + "SELECT id, url, predicted, malicious_score, reward, created_at " + "FROM url_feedback ORDER BY id DESC LIMIT 10" + ).fetchall() + ] + + # Model updates + updates = [ + dict(r) + for r in conn.execute( + "SELECT * FROM model_updates ORDER BY id DESC LIMIT 10" + ).fetchall() + ] + + return { + "malware_total": m_total, + "malware_agree": m_agree, + "malware_disagree": m_disagree, + "malware_agreement_rate": round(m_rate, 1), + "url_total": u_total, + "url_correct": u_correct, + "url_incorrect": u_incorrect, + "url_accuracy_rate": round(u_rate, 1), + "recent_malware": recent_m, + "recent_url": recent_u, + "model_updates": updates, + } + + # ── Incremental model updates ───────────────────────────────────────── + + def update_malware_model( + self, min_samples: int = 10, lr: float = 0.01, rounds: int = 5 + ) -> dict: + """ + Incrementally update the malware XGBoost model with accumulated + feedback. Uses `xgb_model` for continuation training. + """ + import xgboost as xgb + from .ml_service import get_ml_service + + conn = self._get_conn() + rows = conn.execute( + "SELECT features, correct_label FROM malware_feedback" + ).fetchall() + + if len(rows) < min_samples: + return { + "success": False, + "model_type": "malware", + "samples_used": len(rows), + "message": f"Need β‰₯ {min_samples} samples, have {len(rows)}", + } + + X = np.array([json.loads(r["features"]) for r in rows], dtype=np.float32) + y = np.array( + [1 if r["correct_label"] == "Malicious" else 0 for r in rows], + dtype=np.float32, + ) + + ml_service = get_ml_service() + booster = ml_service.model.get_booster() + dtrain = xgb.DMatrix(X, label=y) + + params = { + "objective": "binary:logistic", + "eval_metric": "logloss", + "learning_rate": lr, + "max_depth": 3, + } + + updated = xgb.train( + params, dtrain, num_boost_round=rounds, xgb_model=booster + ) + + # Patch sklearn model with updated booster + ml_service.model._Booster = updated + + # Persist + model_path = ( + Path(__file__).parent.parent.parent.parent / "xgb_malware_model.joblib" + ) + joblib.dump(ml_service.model, model_path) + + # Log update + now = datetime.now(timezone.utc).isoformat() + conn.execute( + "INSERT INTO model_updates (model_type, samples_used, lr, rounds, created_at) " + "VALUES (?, ?, ?, ?, ?)", + ("malware", len(rows), lr, rounds, now), + ) + conn.commit() + + logger.info( + f"Malware model updated: {len(rows)} samples, lr={lr}, rounds={rounds}" + ) + return { + "success": True, + "model_type": "malware", + "samples_used": len(rows), + "message": f"Model updated with {len(rows)} feedback samples ({rounds} rounds, lr={lr})", + } + + def update_url_model( + self, min_samples: int = 10, lr: float = 0.01, rounds: int = 5 + ) -> dict: + """ + Incrementally update the URL meta-learner with accumulated + user feedback. Reconstructs 10 meta-features from stored + base model scores. + """ + import xgboost as xgb + from .url_service import get_url_service + + conn = self._get_conn() + rows = conn.execute( + "SELECT base_model_scores, correct_label FROM url_feedback" + ).fetchall() + + if len(rows) < min_samples: + return { + "success": False, + "model_type": "url", + "samples_used": len(rows), + "message": f"Need β‰₯ {min_samples} samples, have {len(rows)}", + } + + BASE_MODEL_ORDER = [ + "XGBoost", "LightGBM", "TF-IDF + LR", "CharCNN", "CharBiLSTM" + ] + + meta_features = [] + labels = [] + for r in rows: + scores = json.loads(r["base_model_scores"]) + mf = [] + for name in BASE_MODEL_ORDER: + mal = scores.get(name, 0.5) + mf.extend([1.0 - mal, mal]) + meta_features.append(mf) + labels.append(1 if r["correct_label"] == "Malicious" else 0) + + X = np.array(meta_features, dtype=np.float32) + y = np.array(labels, dtype=np.float32) + + url_service = get_url_service() + booster = url_service.meta_learner.get_booster() + dtrain = xgb.DMatrix(X, label=y) + + params = { + "objective": "binary:logistic", + "eval_metric": "logloss", + "learning_rate": lr, + "max_depth": 3, + } + + updated = xgb.train( + params, dtrain, num_boost_round=rounds, xgb_model=booster + ) + + # Patch sklearn model + url_service.meta_learner._Booster = updated + + # Persist + meta_path = url_service.models_dir / "hypermodel_meta.joblib" + joblib.dump(url_service.meta_learner, meta_path) + + # Log update + now = datetime.now(timezone.utc).isoformat() + conn.execute( + "INSERT INTO model_updates (model_type, samples_used, lr, rounds, created_at) " + "VALUES (?, ?, ?, ?, ?)", + ("url", len(rows), lr, rounds, now), + ) + conn.commit() + + logger.info( + f"URL meta-learner updated: {len(rows)} samples, lr={lr}, rounds={rounds}" + ) + return { + "success": True, + "model_type": "url", + "samples_used": len(rows), + "message": f"URL meta-learner updated with {len(rows)} feedback samples ({rounds} rounds, lr={lr})", + } + + +# ── Singleton ───────────────────────────────────────────────────────────────── + +_feedback_service: Optional[FeedbackService] = None + + +def get_feedback_service() -> FeedbackService: + """Get or create the singleton feedback service.""" + global _feedback_service + if _feedback_service is None: + _feedback_service = FeedbackService() + return _feedback_service diff --git a/backend/app/services/gemini_service.py b/backend/app/services/gemini_service.py new file mode 100644 index 0000000000000000000000000000000000000000..2b7ed7d9a0146bc39e5886ea8fd7a03c164a00c1 --- /dev/null +++ b/backend/app/services/gemini_service.py @@ -0,0 +1,263 @@ +""" +Gemini AI Service for malware analysis explanations. +Provides human-readable explanations of XGBoost predictions. +""" + +import logging +from typing import Optional, List +import json + +from ..config import settings +from ..models.prediction import ( + PredictionResponse, + GeminiExplanation, + SeverityLevel, + FeatureImportance, +) + +logger = logging.getLogger(__name__) + + +PREFERRED_GEMINI_MODELS = [ + "gemini-flash-lite-latest", + "gemini-2.0-flash-lite", + "gemini-2.0-flash-lite-001", + "gemini-flash-latest", + "gemini-2.0-flash", +] + + +# Gemini prompt template for malware analysis +ANALYSIS_PROMPT_TEMPLATE = """You are an expert malware analyst assistant. Analyze the following malware detection results and provide a professional cybersecurity assessment. + +## Prediction Results +- **Classification**: {prediction} +- **Malware Probability**: {probability:.1%} +- **Confidence Level**: {confidence} +{sha256_section} + +## Top Contributing Features +{features_section} + +## Instructions +Based on the above prediction results, provide your analysis in the following JSON format: + +{{ + "risk_explanation": "A 2-3 sentence explanation of why this sample was classified as {prediction}. Focus on the technical indicators from the features.", + "severity_level": "One of: Critical, High, Medium, Low, None", + "key_indicators": ["List of 3-5 key indicators identified from the features"], + "analyst_summary": "A professional 2-3 sentence summary suitable for a security analyst report.", + "mitigation_steps": ["If malicious, list 3-5 recommended mitigation steps. If benign, set to null."] +}} + +Important: +- DO NOT override the model's prediction. Your role is to explain, not reclassify. +- Base your analysis on the provided features and probability. +- Be specific about which feature categories contribute to the classification. +- Use professional cybersecurity terminology. +- If probability is high (>80%), emphasize the confidence. If low confidence, mention uncertainty. + +Respond ONLY with the JSON object, no additional text.""" + + +def _format_features_section(features: Optional[List[FeatureImportance]]) -> str: + """Format feature importance for the prompt.""" + if not features: + return "No detailed feature analysis available." + + lines = [] + for f in features[:10]: # Limit to top 10 + lines.append( + f"- **{f.feature_name}**: {f.importance_value:.4f} ({f.contribution} malware probability)" + ) + + return "\n".join(lines) + + +class GeminiService: + """ + Gemini AI Service for generating malware analysis explanations. + + This service: + - Takes XGBoost prediction results + - Sends them to Gemini for analysis + - Returns structured explanations + - Does NOT override the model's prediction + """ + + def __init__(self): + self.model = None + self.initialized = False + self._genai = None + + def initialize(self) -> bool: + """ + Initialize the Gemini AI client. + + Returns: + True if initialization successful + """ + if not settings.gemini_api_key: + logger.warning("Gemini API key not configured") + return False + + try: + import google.generativeai as genai + + self._genai = genai + + genai.configure(api_key=settings.gemini_api_key) + + self.model = None + for model_name in PREFERRED_GEMINI_MODELS: + try: + self.model = genai.GenerativeModel(model_name) + logger.info( + "Gemini AI service initialized with model %s", model_name + ) + break + except Exception as model_error: + logger.warning( + "Failed to prepare Gemini model %s: %s", model_name, model_error + ) + + if self.model is None: + logger.error("No Gemini model could be initialized") + return False + + self.initialized = True + return True + + except ImportError: + logger.error("google-generativeai package not installed") + return False + except Exception as e: + logger.error(f"Failed to initialize Gemini: {e}") + return False + + async def explain_prediction( + self, + prediction: PredictionResponse, + features: Optional[List[FeatureImportance]] = None, + ) -> GeminiExplanation: + """ + Generate explanation for a malware prediction. + + Args: + prediction: XGBoost prediction result + features: Optional list of top contributing features + + Returns: + GeminiExplanation with analysis + """ + if not self.initialized: + self.initialize() + + if not self.initialized or self.model is None: + return self._get_fallback_explanation(prediction) + + try: + # Build the prompt + sha256_section = "" + if prediction.sha256: + sha256_section = f"- **SHA256 Hash**: {prediction.sha256}" + + features_section = _format_features_section(features) + + prompt = ANALYSIS_PROMPT_TEMPLATE.format( + prediction=prediction.prediction.value, + probability=prediction.probability, + confidence=prediction.confidence.value, + sha256_section=sha256_section, + features_section=features_section, + ) + + # Call Gemini API + response = self.model.generate_content(prompt) + + # Parse JSON response + response_text = response.text.strip() + + # Clean up response if wrapped in code blocks + if response_text.startswith("```json"): + response_text = response_text[7:] + if response_text.startswith("```"): + response_text = response_text[3:] + if response_text.endswith("```"): + response_text = response_text[:-3] + + analysis = json.loads(response_text.strip()) + + return GeminiExplanation( + risk_explanation=analysis.get( + "risk_explanation", "Analysis unavailable" + ), + severity_level=SeverityLevel(analysis.get("severity_level", "Medium")), + key_indicators=analysis.get("key_indicators", []), + analyst_summary=analysis.get("analyst_summary", ""), + mitigation_steps=analysis.get("mitigation_steps"), + ) + + except json.JSONDecodeError as e: + logger.error(f"Failed to parse Gemini response: {e}") + return self._get_fallback_explanation(prediction) + except Exception as e: + logger.error(f"Gemini API error: {e}") + return self._get_fallback_explanation(prediction) + + def _get_fallback_explanation( + self, prediction: PredictionResponse + ) -> GeminiExplanation: + """Generate a basic explanation when Gemini is unavailable.""" + is_malicious = prediction.prediction.value == "Malicious" + + if is_malicious: + severity = ( + SeverityLevel.HIGH + if prediction.probability > 0.8 + else SeverityLevel.MEDIUM + ) + return GeminiExplanation( + risk_explanation=f"The XGBoost model classified this sample as malicious with {prediction.probability:.1%} probability. This indicates the presence of suspicious patterns commonly found in malware.", + severity_level=severity, + key_indicators=[ + "Sample matches malware patterns in trained dataset", + f"Prediction confidence: {prediction.confidence.value}", + f"Probability score: {prediction.probability:.1%}", + ], + analyst_summary=f"Automated analysis flagged this sample as potentially malicious. Manual review recommended.", + mitigation_steps=[ + "Quarantine the file immediately", + "Do not execute or open the file", + "Scan with multiple antivirus engines", + "Check VirusTotal for additional context", + "Report to security team if in enterprise environment", + ], + ) + else: + return GeminiExplanation( + risk_explanation=f"The XGBoost model classified this sample as benign with {1 - prediction.probability:.1%} confidence. The feature patterns do not match known malware signatures.", + severity_level=SeverityLevel.NONE, + key_indicators=[ + "Sample does not match malware patterns", + f"Benign probability: {1 - prediction.probability:.1%}", + f"Prediction confidence: {prediction.confidence.value}", + ], + analyst_summary="Automated analysis did not detect malicious patterns. Sample appears to be benign based on static analysis.", + mitigation_steps=None, + ) + + +# Global service instance +_gemini_service: Optional[GeminiService] = None + + +def get_gemini_service() -> GeminiService: + """Get the global Gemini service instance.""" + global _gemini_service + + if _gemini_service is None: + _gemini_service = GeminiService() + _gemini_service.initialize() + + return _gemini_service diff --git a/backend/app/services/malware_type_service.py b/backend/app/services/malware_type_service.py new file mode 100644 index 0000000000000000000000000000000000000000..6c45e5a6a97485573bae271e78ee874cbb0b0870 --- /dev/null +++ b/backend/app/services/malware_type_service.py @@ -0,0 +1,403 @@ +""" +Malware Type Classification Service + +Combines heuristic analysis of PE features with VirusTotal labels +to determine the likely type/family of detected malware. +""" + +import logging +import re +from typing import Optional, Dict, List, Tuple +from dataclasses import dataclass +from enum import Enum + +logger = logging.getLogger(__name__) + + +class MalwareType(str, Enum): + """Common malware types/categories.""" + RANSOMWARE = "Ransomware" + TROJAN = "Trojan" + WORM = "Worm" + SPYWARE = "Spyware" + ADWARE = "Adware" + BACKDOOR = "Backdoor" + ROOTKIT = "Rootkit" + KEYLOGGER = "Keylogger" + BANKER = "Banking Trojan" + DROPPER = "Dropper" + DOWNLOADER = "Downloader" + RAT = "Remote Access Trojan" + CRYPTOMINER = "Cryptominer" + BOTNET = "Botnet" + PUP = "Potentially Unwanted Program" + GENERIC = "Generic Malware" + UNKNOWN = "Unknown" + + +@dataclass +class MalwareTypeResult: + """Result of malware type classification.""" + primary_type: str + confidence: str # High, Medium, Low + secondary_types: List[str] + indicators: List[str] + source: str # "heuristic", "virustotal", "combined" + + +# Suspicious import patterns for different malware types +MALWARE_IMPORT_SIGNATURES = { + MalwareType.RANSOMWARE: [ + "CryptEncrypt", "CryptDecrypt", "CryptGenKey", "CryptAcquireContext", + "CryptImportKey", "CryptDestroyKey", "BCryptEncrypt", "BCryptDecrypt", + "FindFirstFile", "FindNextFile", "MoveFileEx", "DeleteFile", + "GetLogicalDriveStrings", "GetDriveType" + ], + MalwareType.KEYLOGGER: [ + "GetAsyncKeyState", "GetKeyState", "GetKeyboardState", "SetWindowsHookEx", + "CallNextHookEx", "GetForegroundWindow", "GetWindowText", "AttachThreadInput" + ], + MalwareType.SPYWARE: [ + "GetClipboardData", "OpenClipboard", "CreateToolhelp32Snapshot", + "Process32First", "Process32Next", "RegOpenKeyEx", "RegQueryValueEx", + "GetUserName", "GetComputerName", "SHGetFolderPath" + ], + MalwareType.BACKDOOR: [ + "socket", "connect", "send", "recv", "bind", "listen", "accept", + "WSAStartup", "WSASocket", "CreateProcess", "ShellExecute", + "WinExec", "CreateRemoteThread" + ], + MalwareType.RAT: [ + "CreateDesktop", "SwitchDesktop", "GetDesktopWindow", "keybd_event", + "mouse_event", "SendInput", "GetDC", "BitBlt", "CreateCompatibleBitmap", + "StartServiceCtrlDispatcher", "RegisterServiceCtrlHandler" + ], + MalwareType.ROOTKIT: [ + "NtQuerySystemInformation", "ZwQuerySystemInformation", + "NtOpenProcess", "ZwOpenProcess", "NtWriteVirtualMemory", + "IoCreateDriver", "ObRegisterCallbacks", "PsSetCreateProcessNotifyRoutine" + ], + MalwareType.DROPPER: [ + "URLDownloadToFile", "InternetOpen", "InternetOpenUrl", "InternetReadFile", + "CreateFile", "WriteFile", "CreateProcess", "WinExec", + "VirtualAlloc", "VirtualProtect" + ], + MalwareType.DOWNLOADER: [ + "URLDownloadToFile", "URLDownloadToCacheFile", "InternetOpen", + "InternetConnect", "HttpOpenRequest", "HttpSendRequest", + "WinHttpOpen", "WinHttpConnect", "WinHttpOpenRequest" + ], + MalwareType.CRYPTOMINER: [ + "CreateThread", "GetSystemInfo", "GetCurrentProcess", "SetPriorityClass", + "SetThreadPriority", "GetTickCount", "QueryPerformanceCounter" + ], + MalwareType.WORM: [ + "NetShareEnum", "NetUserEnum", "WNetOpenEnum", "WNetEnumResource", + "FindFirstFile", "FindNextFile", "CopyFile", "GetDriveType", + "GetLogicalDriveStrings" + ], + MalwareType.BANKER: [ + "InternetQueryOption", "HttpQueryInfo", "InternetSetOption", + "CertOpenStore", "CertFindCertificateInStore", "PFXImportCertStore", + "SetWindowsHookEx", "GetWindowText", "FindWindow" + ], +} + +# String patterns commonly found in malware +MALWARE_STRING_PATTERNS = { + MalwareType.RANSOMWARE: [ + r"bitcoin", r"btc", r"wallet", r"ransom", r"decrypt", r"encrypt", + r"\.locked", r"\.encrypted", r"your files", r"pay.*\$", r"tor.*onion" + ], + MalwareType.CRYPTOMINER: [ + r"stratum\+tcp", r"xmrig", r"monero", r"hashrate", r"pool\.", + r"mining", r"nicehash", r"coinhive" + ], + MalwareType.BOTNET: [ + r"c2", r"command.*control", r"bot.*net", r"ddos", r"flood", + r"irc\.", r"mirai", r"tsunami" + ], + MalwareType.RAT: [ + r"remote.*access", r"rat", r"njrat", r"darkcomet", r"quasar", + r"asyncrat", r"reverse.*shell" + ], +} + +# Section characteristics indicating malware types +SECTION_INDICATORS = { + "high_entropy": (7.5, MalwareType.RANSOMWARE), # Encrypted/packed content + "upx": MalwareType.DROPPER, # UPX packed often used by droppers + "executable_data": MalwareType.BACKDOOR, # Data sections with execute permission +} + + +class MalwareTypeService: + """ + Service for classifying malware into specific types/families. + + Uses a combination of: + 1. Import table analysis + 2. String pattern matching + 3. PE section characteristics + 4. VirusTotal vendor labels (if available) + """ + + def __init__(self): + self.initialized = True + logger.info("Malware Type Service initialized") + + def classify( + self, + imports: List[str] = None, + strings: List[str] = None, + sections: List[Dict] = None, + entropy: float = None, + vt_labels: List[str] = None + ) -> MalwareTypeResult: + """ + Classify malware based on available indicators. + + Args: + imports: List of imported function names + strings: List of strings extracted from the file + sections: List of PE section info dicts + entropy: Overall file entropy + vt_labels: Labels from VirusTotal vendors + + Returns: + MalwareTypeResult with classification + """ + type_scores: Dict[MalwareType, float] = {t: 0.0 for t in MalwareType} + indicators: List[str] = [] + + # 1. Analyze imports + if imports: + import_results = self._analyze_imports(imports) + for mtype, score, indicator in import_results: + type_scores[mtype] += score + if indicator: + indicators.append(indicator) + + # 2. Analyze strings + if strings: + string_results = self._analyze_strings(strings) + for mtype, score, indicator in string_results: + type_scores[mtype] += score + if indicator: + indicators.append(indicator) + + # 3. Analyze entropy + if entropy and entropy > 7.5: + type_scores[MalwareType.RANSOMWARE] += 2.0 + type_scores[MalwareType.DROPPER] += 1.5 + indicators.append(f"High entropy ({entropy:.2f}) suggests encryption/packing") + + # 4. Analyze sections + if sections: + section_results = self._analyze_sections(sections) + for mtype, score, indicator in section_results: + type_scores[mtype] += score + if indicator: + indicators.append(indicator) + + # 5. Use VirusTotal labels if available + vt_type = None + if vt_labels: + vt_type = self._parse_vt_labels(vt_labels) + if vt_type and vt_type != MalwareType.UNKNOWN: + type_scores[vt_type] += 5.0 # VT labels are authoritative + indicators.append(f"VirusTotal classification: {vt_type.value}") + + # Determine primary type + sorted_types = sorted(type_scores.items(), key=lambda x: x[1], reverse=True) + primary_type = sorted_types[0][0] + primary_score = sorted_types[0][1] + + # If no strong signals, mark as generic + if primary_score < 1.0: + primary_type = MalwareType.GENERIC + confidence = "Low" + elif primary_score < 3.0: + confidence = "Medium" + else: + confidence = "High" + + # Get secondary types (score > 1.0 and not primary) + secondary_types = [ + t.value for t, score in sorted_types[1:4] + if score >= 1.0 and t != primary_type + ] + + # Determine source + if vt_type and vt_type == primary_type: + source = "virustotal" + elif vt_labels and indicators: + source = "combined" + else: + source = "heuristic" + + return MalwareTypeResult( + primary_type=primary_type.value, + confidence=confidence, + secondary_types=secondary_types, + indicators=indicators[:5], # Limit to top 5 indicators + source=source + ) + + def _analyze_imports(self, imports: List[str]) -> List[Tuple[MalwareType, float, str]]: + """Analyze imported functions for malware indicators.""" + results = [] + imports_lower = [i.lower() for i in imports] + + for mtype, signatures in MALWARE_IMPORT_SIGNATURES.items(): + matches = [] + for sig in signatures: + if sig.lower() in imports_lower or any(sig.lower() in imp for imp in imports_lower): + matches.append(sig) + + if matches: + score = min(len(matches) * 0.5, 3.0) # Cap at 3.0 + indicator = f"Suspicious imports for {mtype.value}: {', '.join(matches[:3])}" + results.append((mtype, score, indicator)) + + return results + + def _analyze_strings(self, strings: List[str]) -> List[Tuple[MalwareType, float, str]]: + """Analyze strings for malware indicators.""" + results = [] + strings_combined = " ".join(strings).lower() + + for mtype, patterns in MALWARE_STRING_PATTERNS.items(): + matches = [] + for pattern in patterns: + if re.search(pattern, strings_combined, re.IGNORECASE): + matches.append(pattern) + + if matches: + score = min(len(matches) * 0.7, 3.0) + indicator = f"String patterns suggest {mtype.value}" + results.append((mtype, score, indicator)) + + return results + + def _analyze_sections(self, sections: List[Dict]) -> List[Tuple[MalwareType, float, str]]: + """Analyze PE sections for malware indicators.""" + results = [] + + for section in sections: + name = section.get("name", "").lower() + entropy = section.get("entropy", 0) + characteristics = section.get("characteristics", 0) + + # Check for UPX packing + if "upx" in name: + results.append((MalwareType.DROPPER, 1.5, "UPX packed section detected")) + + # Check for high entropy sections + if entropy > 7.5: + results.append(( + MalwareType.RANSOMWARE, 1.0, + f"High entropy section '{name}' ({entropy:.2f})" + )) + + # Check for executable data sections + if characteristics: + is_executable = characteristics & 0x20000000 # IMAGE_SCN_MEM_EXECUTE + is_writable = characteristics & 0x80000000 # IMAGE_SCN_MEM_WRITE + if is_executable and is_writable and "text" not in name: + results.append(( + MalwareType.BACKDOOR, 1.5, + f"Suspicious RWX section '{name}'" + )) + + return results + + def _parse_vt_labels(self, labels: List[str]) -> Optional[MalwareType]: + """Parse VirusTotal vendor labels to determine malware type.""" + labels_combined = " ".join(labels).lower() + + # Priority order for type detection + type_keywords = [ + (MalwareType.RANSOMWARE, ["ransom", "crypt", "locker", "wannacry", "locky", "cerber"]), + (MalwareType.RAT, ["rat", "remoteaccess", "njrat", "darkcomet", "quasar", "asyncrat"]), + (MalwareType.BANKER, ["banker", "banking", "zeus", "emotet", "trickbot", "dridex"]), + (MalwareType.BACKDOOR, ["backdoor", "back door", "reverseshell"]), + (MalwareType.ROOTKIT, ["rootkit", "bootkit"]), + (MalwareType.KEYLOGGER, ["keylog", "keylogger"]), + (MalwareType.CRYPTOMINER, ["miner", "coinminer", "cryptominer", "xmrig"]), + (MalwareType.WORM, ["worm", "conficker", "mydoom"]), + (MalwareType.SPYWARE, ["spyware", "spy", "infostealer", "stealer"]), + (MalwareType.ADWARE, ["adware", "pup", "unwanted"]), + (MalwareType.DROPPER, ["dropper", "downloader"]), + (MalwareType.TROJAN, ["trojan", "troj", "agent"]), + ] + + for mtype, keywords in type_keywords: + for keyword in keywords: + if keyword in labels_combined: + return mtype + + return MalwareType.UNKNOWN + + def classify_from_lief(self, lief_binary) -> MalwareTypeResult: + """ + Classify malware type directly from a LIEF parsed binary. + + Args: + lief_binary: LIEF PE binary object + + Returns: + MalwareTypeResult + """ + imports = [] + sections = [] + + try: + # Extract imports + if hasattr(lief_binary, 'imports'): + for lib in lief_binary.imports: + for entry in lib.entries: + if entry.name: + imports.append(entry.name) + + # Extract section info + if hasattr(lief_binary, 'sections'): + for section in lief_binary.sections: + sections.append({ + "name": section.name, + "entropy": section.entropy, + "characteristics": section.characteristics + }) + + # Calculate overall entropy + entropy = None + if sections: + entropy = sum(s.get("entropy", 0) for s in sections) / len(sections) + + return self.classify( + imports=imports, + sections=sections, + entropy=entropy + ) + + except Exception as e: + logger.error(f"Error classifying from LIEF: {e}") + return MalwareTypeResult( + primary_type=MalwareType.UNKNOWN.value, + confidence="Low", + secondary_types=[], + indicators=["Error during classification"], + source="heuristic" + ) + + +# Singleton instance +_malware_type_service: Optional[MalwareTypeService] = None + + +def get_malware_type_service() -> MalwareTypeService: + """Get or create the malware type service singleton.""" + global _malware_type_service + if _malware_type_service is None: + _malware_type_service = MalwareTypeService() + return _malware_type_service diff --git a/backend/app/services/ml_service.py b/backend/app/services/ml_service.py new file mode 100644 index 0000000000000000000000000000000000000000..a35b1373a7fcbb3e189b92eeebf5d7d022548afe --- /dev/null +++ b/backend/app/services/ml_service.py @@ -0,0 +1,198 @@ +""" +Machine Learning Service for XGBoost Malware Detection. +Handles model loading, inference, and prediction formatting. +Optimized for fast inference with single model load. +""" + +import time +import logging +from pathlib import Path +from typing import Optional, Tuple +import numpy as np +import joblib + +from ..config import settings +from ..models.prediction import ( + PredictionLabel, + ConfidenceLevel, + PredictionResponse, +) + +logger = logging.getLogger(__name__) + + +class MLService: + """ + XGBoost ML Service for malware detection. + + Features: + - Single model load at startup (no reload per request) + - NumPy vectorization for fast inference + - Configurable prediction threshold + - Confidence level calculation + """ + + def __init__(self): + self.model = None + self.model_loaded = False + self.feature_count = settings.ember_feature_count + self.default_threshold = settings.prediction_threshold + + def load_model(self, model_path: Optional[str] = None) -> bool: + """ + Load the XGBoost model from disk. + Should be called once at application startup. + + Args: + model_path: Path to the .joblib model file + + Returns: + True if model loaded successfully + """ + if model_path is None: + # Look in parent directory (project root) + model_path = Path(__file__).parent.parent.parent.parent / settings.model_path + else: + model_path = Path(model_path) + + try: + logger.info(f"Loading XGBoost model from: {model_path}") + start_time = time.time() + + self.model = joblib.load(model_path) + + load_time = (time.time() - start_time) * 1000 + logger.info(f"Model loaded successfully in {load_time:.2f}ms") + + self.model_loaded = True + return True + + except FileNotFoundError: + logger.error(f"Model file not found: {model_path}") + raise RuntimeError(f"Model file not found: {model_path}") + except Exception as e: + logger.error(f"Failed to load model: {e}") + raise RuntimeError(f"Failed to load model: {e}") + + def predict( + self, + features: list[float], + threshold: Optional[float] = None, + sha256: Optional[str] = None + ) -> PredictionResponse: + """ + Run malware prediction on feature vector. + + Args: + features: EMBER 2018 v2 feature vector (2381 values) + threshold: Custom threshold (default from config) + sha256: Optional hash for reference + + Returns: + PredictionResponse with prediction, probability, confidence + """ + if not self.model_loaded: + raise RuntimeError("Model not loaded. Call load_model() first.") + + # Validate feature count + if len(features) != self.feature_count: + raise ValueError( + f"Expected {self.feature_count} features, got {len(features)}" + ) + + # Use default threshold if not provided + if threshold is None: + threshold = self.default_threshold + + # Convert to NumPy array for vectorized inference + start_time = time.time() + feature_array = np.array(features, dtype=np.float32).reshape(1, -1) + + # Get probability prediction + # XGBoost predict_proba returns [[prob_benign, prob_malicious]] + try: + probabilities = self.model.predict_proba(feature_array) + malware_probability = float(probabilities[0][1]) + except AttributeError: + # Fallback for models without predict_proba + prediction = self.model.predict(feature_array) + malware_probability = float(prediction[0]) + + inference_time = (time.time() - start_time) * 1000 + + # Determine prediction based on threshold + is_malicious = malware_probability >= threshold + prediction_label = ( + PredictionLabel.MALICIOUS if is_malicious + else PredictionLabel.BENIGN + ) + + # Calculate confidence level + confidence = self._calculate_confidence(malware_probability) + + return PredictionResponse( + prediction=prediction_label, + probability=round(malware_probability, 4), + confidence=confidence, + threshold_used=threshold, + sha256=sha256, + inference_time_ms=round(inference_time, 2) + ) + + def _calculate_confidence(self, probability: float) -> ConfidenceLevel: + """ + Calculate confidence level based on probability distance from threshold. + + High confidence: probability < 0.2 or > 0.8 + Medium confidence: probability 0.2-0.35 or 0.65-0.8 + Low confidence: probability 0.35-0.65 + """ + distance_from_uncertain = abs(probability - 0.5) + + if distance_from_uncertain >= 0.3: + return ConfidenceLevel.HIGH + elif distance_from_uncertain >= 0.15: + return ConfidenceLevel.MEDIUM + else: + return ConfidenceLevel.LOW + + def get_model_info(self) -> dict: + """Get information about the loaded model.""" + if not self.model_loaded: + return {"loaded": False} + + info = { + "loaded": True, + "feature_count": self.feature_count, + "default_threshold": self.default_threshold, + "model_type": type(self.model).__name__, + } + + # Try to get additional model attributes + try: + if hasattr(self.model, 'n_estimators'): + info["n_estimators"] = self.model.n_estimators + if hasattr(self.model, 'max_depth'): + info["max_depth"] = self.model.max_depth + except Exception: + pass + + return info + + +# Global service instance (singleton pattern) +_ml_service: Optional[MLService] = None + + +def get_ml_service() -> MLService: + """ + Get the global ML service instance. + Creates and loads model on first call. + """ + global _ml_service + + if _ml_service is None: + _ml_service = MLService() + _ml_service.load_model() + + return _ml_service diff --git a/backend/app/services/shap_service.py b/backend/app/services/shap_service.py new file mode 100644 index 0000000000000000000000000000000000000000..cd0efd97bc235ce7adf8ad990fe639e664e97af8 --- /dev/null +++ b/backend/app/services/shap_service.py @@ -0,0 +1,203 @@ +""" +SHAP Service for feature importance extraction. +Provides explainability for XGBoost malware predictions. +""" + +import logging +from typing import Optional, List +import numpy as np + +from ..config import settings +from ..models.prediction import FeatureImportance + +logger = logging.getLogger(__name__) + +# EMBER 2018 v2 Feature Name Mapping +# These are the high-level feature categories from EMBER +EMBER_FEATURE_GROUPS = { + # Byte histogram (256 features, indices 0-255) + (0, 256): "byte_histogram", + # Byte-entropy histogram (256 features, indices 256-511) + (256, 512): "byte_entropy_histogram", + # String features (104 features, indices 512-615) + (512, 616): "string_features", + # General file info (10 features, indices 616-625) + (616, 626): "general_file_info", + # Header features (62 features, indices 626-687) + (626, 688): "header_features", + # Section features (255 features, indices 688-942) + (688, 943): "section_features", + # Import features (1280 features, indices 943-2222) + (943, 2223): "import_features", + # Export features (128 features, indices 2223-2350) + (2223, 2351): "export_features", + # Data directory features (30 features, indices 2351-2380) + (2351, 2381): "data_directory_features", +} + +def get_feature_name(index: int) -> str: + """Get human-readable feature name from index.""" + for (start, end), name in EMBER_FEATURE_GROUPS.items(): + if start <= index < end: + offset = index - start + return f"{name}[{offset}]" + return f"feature_{index}" + + +def get_feature_category(index: int) -> str: + """Get feature category from index.""" + for (start, end), name in EMBER_FEATURE_GROUPS.items(): + if start <= index < end: + return name + return "unknown" + + +class SHAPService: + """ + SHAP (SHapley Additive exPlanations) service for model explainability. + + Provides feature importance analysis to understand why + the model classified a sample as malicious or benign. + """ + + def __init__(self): + self.explainer = None + self.initialized = False + self._shap_available = False + + # Try to import SHAP + try: + import shap + self._shap = shap + self._shap_available = True + except ImportError: + logger.warning("SHAP library not available. Feature importance will be limited.") + + def initialize(self, model) -> bool: + """ + Initialize SHAP explainer with the model. + + Args: + model: Trained XGBoost model + + Returns: + True if initialization successful + """ + if not self._shap_available: + logger.warning("SHAP not available, using fallback importance") + self.initialized = True + return True + + try: + logger.info("Initializing SHAP TreeExplainer...") + self.explainer = self._shap.TreeExplainer(model) + self.initialized = True + logger.info("SHAP explainer initialized successfully") + return True + except Exception as e: + logger.error(f"Failed to initialize SHAP: {e}") + self.initialized = True # Still mark as initialized to use fallback + return False + + def get_feature_importance( + self, + features: List[float], + model, + top_k: int = 10 + ) -> List[FeatureImportance]: + """ + Get top contributing features for a prediction. + + Args: + features: Input feature vector + model: XGBoost model + top_k: Number of top features to return + + Returns: + List of FeatureImportance objects + """ + feature_array = np.array(features, dtype=np.float32).reshape(1, -1) + + if self._shap_available and self.explainer is not None: + return self._get_shap_importance(feature_array, top_k) + else: + return self._get_fallback_importance(feature_array, model, top_k) + + def _get_shap_importance( + self, + feature_array: np.ndarray, + top_k: int + ) -> List[FeatureImportance]: + """Get feature importance using SHAP values.""" + try: + shap_values = self.explainer.shap_values(feature_array) + + # Handle different SHAP output formats + if isinstance(shap_values, list): + # For binary classification, use positive class + values = shap_values[1][0] if len(shap_values) > 1 else shap_values[0][0] + else: + values = shap_values[0] + + # Get indices of top features by absolute value + top_indices = np.argsort(np.abs(values))[-top_k:][::-1] + + importance_list = [] + for idx in top_indices: + importance = float(values[idx]) + importance_list.append(FeatureImportance( + feature_index=int(idx), + feature_name=get_feature_name(idx), + importance_value=round(importance, 4), + contribution="increases" if importance > 0 else "decreases" + )) + + return importance_list + + except Exception as e: + logger.error(f"SHAP calculation failed: {e}") + return [] + + def _get_fallback_importance( + self, + feature_array: np.ndarray, + model, + top_k: int + ) -> List[FeatureImportance]: + """ + Fallback importance using model's feature_importances_. + Less accurate than SHAP but faster. + """ + try: + if hasattr(model, 'feature_importances_'): + importances = model.feature_importances_ + top_indices = np.argsort(importances)[-top_k:][::-1] + + importance_list = [] + for idx in top_indices: + importance_list.append(FeatureImportance( + feature_index=int(idx), + feature_name=get_feature_name(idx), + importance_value=round(float(importances[idx]), 4), + contribution="contributes" # Can't determine direction without SHAP + )) + + return importance_list + except Exception as e: + logger.error(f"Fallback importance failed: {e}") + + return [] + + +# Global service instance +_shap_service: Optional[SHAPService] = None + + +def get_shap_service() -> SHAPService: + """Get the global SHAP service instance.""" + global _shap_service + + if _shap_service is None: + _shap_service = SHAPService() + + return _shap_service diff --git a/backend/app/services/url_feature_engineering.py b/backend/app/services/url_feature_engineering.py new file mode 100644 index 0000000000000000000000000000000000000000..a92e7d181364ea15188099f78ae8803e614608dc --- /dev/null +++ b/backend/app/services/url_feature_engineering.py @@ -0,0 +1,307 @@ +""" +URL Feature Engineering β€” 54 lexical features for malicious URL detection. + +Adapted from the URL model notebook for backend integration. +Features are grouped into 8 categories: + 1. Length / structural (7 features) + 2. Character counts (14 features) + 3. Character ratios (5 features) + 4. Entropy / randomness (2 features) + 5. Boolean indicators (10 features) + 6. Domain / TLD signals (6 features) + 7. Suspicious-pattern scores (5 features) + 8. Path & query analysis (5 features) +""" + +from __future__ import annotations + +import math +import re +from collections import Counter +from urllib.parse import urlparse, parse_qs + +import numpy as np + +try: + import tldextract +except ImportError: + tldextract = None + +# ── Regex patterns (compiled once) ──────────────────────────────────────────── +_IP_RE = re.compile( + r"(?:^|[/@])(\d{1,3}\.){3}\d{1,3}(?:[:/]|$)" +) +_HEX_RE = re.compile(r"%[0-9a-fA-F]{2}") +_SHORTENERS = frozenset([ + "bit.ly", "goo.gl", "tinyurl.com", "ow.ly", "t.co", "is.gd", + "buff.ly", "adf.ly", "tiny.cc", "lnkd.in", "rb.gy", "cutt.ly", + "shorturl.at", "rebrand.ly", +]) +_SUSPICIOUS_TLDS = frozenset([ + "tk", "ml", "ga", "cf", "gq", "xyz", "top", "pw", "cc", + "club", "work", "date", "racing", "stream", "download", + "win", "bid", "icu", "buzz", "monster", +]) +_SUSPICIOUS_EXT = re.compile( + r"\.(exe|zip|rar|scr|bat|cmd|js|vbs|ps1|dll|msi|apk|dmg|iso|php|cgi)(\?|$)", + re.IGNORECASE, +) +_PHISHING_KW = re.compile( + r"(login|signin|verify|account|update|secure|bank|confirm|password|" + r"credential|suspend|alert|notification|wallet|paypal|apple|microsoft|" + r"amazon|netflix|facebook|instagram|whatsapp|dropbox|google|icloud)", + re.IGNORECASE, +) +_BRAND_NAMES = [ + "google", "facebook", "apple", "amazon", "microsoft", "netflix", + "paypal", "instagram", "whatsapp", "dropbox", "linkedin", "twitter", + "yahoo", "ebay", "chase", "wellsfargo", "bankofamerica", "citibank", + "hsbc", "dhl", "fedex", "usps", +] + + +# Feature names in the exact order the scaler/models expect +FEATURE_NAMES = [ + # 1. Length + "url_length", "hostname_length", "domain_length", "path_length", + "query_length", "fragment_length", "tld_length", + # 2. Counts + "num_dots", "num_hyphens", "num_underscores", "num_slashes", + "num_at_signs", "num_ampersands", "num_equals", "num_question_marks", + "num_percent", "num_tilde", "num_digits", "num_letters", + "num_special", "num_params", + # 3. Ratios + "digit_ratio", "letter_ratio", "special_ratio", "uppercase_ratio", + "digit_letter_ratio", + # 4. Entropy + "url_entropy", "domain_entropy", + # 5. Booleans + "has_ip", "has_https", "has_http", "has_www", "has_port", + "has_at_symbol", "is_shortened", "has_double_slash_redirect", + "has_punycode", "has_hex_encoding", + # 6. Domain + "num_subdomains", "subdomain_length", "domain_token_count", + "has_suspicious_tld", "domain_has_digits", "domain_hyphen_count", + # 7. Suspicious + "phishing_keyword_count", "brand_count", "has_suspicious_ext", + "brand_in_subdomain", "suspicious_word_ratio", + # 8. Path / query + "path_depth", "longest_path_token", "avg_path_token_len", + "max_consecutive_digits", "path_entropy", +] + + +def _entropy(s: str) -> float: + """Shannon entropy of a string.""" + if not s: + return 0.0 + cnt = Counter(s) + length = len(s) + return -sum((c / length) * math.log2(c / length) for c in cnt.values()) + + +def extract_url_features(url: str) -> np.ndarray: + """ + Extract 54 lexical features from a single URL string. + Returns a 1D numpy array of shape (54,) in float32. + """ + try: + features = _extract_features_inner(url) + except Exception: + features = {name: 0 for name in FEATURE_NAMES} + + return np.array([features[name] for name in FEATURE_NAMES], dtype=np.float32) + + +def extract_url_features_dict(url: str) -> dict: + """Extract 54 features and return as a dict with feature names.""" + try: + return _extract_features_inner(url) + except Exception: + return {name: 0 for name in FEATURE_NAMES} + + +def _extract_features_inner(url: str) -> dict: + """Core feature extraction logic.""" + url = str(url).strip() + + try: + parsed = urlparse(url if "://" in url else f"http://{url}") + except Exception: + try: + safe = url.replace("[", "").replace("]", "") + parsed = urlparse(safe if "://" in safe else f"http://{safe}") + except Exception: + parsed = urlparse("http://invalid") + + try: + hostname = parsed.hostname or "" + except Exception: + hostname = "" + path = parsed.path or "" + query = parsed.query or "" + fragment = parsed.fragment or "" + scheme = (parsed.scheme or "").lower() + + # TLD extraction + if tldextract is not None: + ext = tldextract.extract(url) + domain = ext.domain + tld = ext.suffix + subdomain = ext.subdomain + else: + domain = hostname.split(".")[-2] if hostname.count(".") >= 1 else hostname + tld = hostname.split(".")[-1] if "." in hostname else "" + subdomain = ".".join(hostname.split(".")[:-2]) if hostname.count(".") >= 2 else "" + + url_lower = url.lower() + + # 1. Length / structural + url_length = len(url) + hostname_length = len(hostname) + domain_length = len(domain) + path_length = len(path) + query_length = len(query) + fragment_length = len(fragment) + tld_length = len(tld) + + # 2. Character counts + num_dots = url.count(".") + num_hyphens = url.count("-") + num_underscores = url.count("_") + num_slashes = url.count("/") + num_at_signs = url.count("@") + num_ampersands = url.count("&") + num_equals = url.count("=") + num_question_marks = url.count("?") + num_percent = url.count("%") + num_tilde = url.count("~") + num_digits = sum(c.isdigit() for c in url) + num_letters = sum(c.isalpha() for c in url) + num_special = sum(not c.isalnum() and c not in ":/." for c in url) + num_params = len(parse_qs(query)) + + # 3. Character ratios + safe_len = max(url_length, 1) + digit_ratio = num_digits / safe_len + letter_ratio = num_letters / safe_len + special_ratio = num_special / safe_len + uppercase_ratio = sum(c.isupper() for c in url) / safe_len + digit_letter_ratio = num_digits / max(num_letters, 1) + + # 4. Entropy + url_entropy = _entropy(url) + domain_entropy = _entropy(hostname) + + # 5. Boolean indicators + has_ip = int(bool(_IP_RE.search(url))) + has_https = int(scheme == "https") + has_http = int(scheme == "http") + has_www = int("www." in url_lower) + try: + _port = parsed.port + except (ValueError, TypeError): + _port = None + has_port = int(_port is not None and _port not in (80, 443)) + has_at_symbol = int("@" in url) + is_shortened = int(any(s in url_lower for s in _SHORTENERS)) + has_double_slash_redirect = int("//" in path) + has_punycode = int("xn--" in url_lower) + has_hex_encoding = int(bool(_HEX_RE.search(url))) + + # 6. Domain / TLD signals + num_subdomains = subdomain.count(".") + 1 if subdomain else 0 + subdomain_length = len(subdomain) + domain_token_count = len(re.split(r"[.\-_]", hostname)) + has_suspicious_tld = int(tld.lower() in _SUSPICIOUS_TLDS) + domain_has_digits = int(any(c.isdigit() for c in domain)) + domain_hyphen_count = domain.count("-") + + # 7. Suspicious-pattern scores + phishing_keyword_count = len(_PHISHING_KW.findall(url_lower)) + brand_count = sum(1 for b in _BRAND_NAMES if b in url_lower) + has_suspicious_ext = int(bool(_SUSPICIOUS_EXT.search(url_lower))) + brand_in_subdomain = int( + any(b in subdomain.lower() for b in _BRAND_NAMES) and + not any(b in domain.lower() for b in _BRAND_NAMES) + ) if subdomain else 0 + suspicious_word_ratio = phishing_keyword_count / max( + len(re.findall(r"[a-zA-Z]+", url)), 1 + ) + + # 8. Path & query analysis + path_tokens = [t for t in path.split("/") if t] + path_depth = len(path_tokens) + longest_path_token = max((len(t) for t in path_tokens), default=0) + avg_path_token_len = ( + sum(len(t) for t in path_tokens) / len(path_tokens) if path_tokens else 0.0 + ) + max_consecutive_digits = max( + (len(m.group()) for m in re.finditer(r"\d+", url)), default=0 + ) + path_entropy = _entropy(path) + + return { + # 1. Length + "url_length": url_length, + "hostname_length": hostname_length, + "domain_length": domain_length, + "path_length": path_length, + "query_length": query_length, + "fragment_length": fragment_length, + "tld_length": tld_length, + # 2. Counts + "num_dots": num_dots, + "num_hyphens": num_hyphens, + "num_underscores": num_underscores, + "num_slashes": num_slashes, + "num_at_signs": num_at_signs, + "num_ampersands": num_ampersands, + "num_equals": num_equals, + "num_question_marks": num_question_marks, + "num_percent": num_percent, + "num_tilde": num_tilde, + "num_digits": num_digits, + "num_letters": num_letters, + "num_special": num_special, + "num_params": num_params, + # 3. Ratios + "digit_ratio": digit_ratio, + "letter_ratio": letter_ratio, + "special_ratio": special_ratio, + "uppercase_ratio": uppercase_ratio, + "digit_letter_ratio": digit_letter_ratio, + # 4. Entropy + "url_entropy": url_entropy, + "domain_entropy": domain_entropy, + # 5. Booleans + "has_ip": has_ip, + "has_https": has_https, + "has_http": has_http, + "has_www": has_www, + "has_port": has_port, + "has_at_symbol": has_at_symbol, + "is_shortened": is_shortened, + "has_double_slash_redirect": has_double_slash_redirect, + "has_punycode": has_punycode, + "has_hex_encoding": has_hex_encoding, + # 6. Domain + "num_subdomains": num_subdomains, + "subdomain_length": subdomain_length, + "domain_token_count": domain_token_count, + "has_suspicious_tld": has_suspicious_tld, + "domain_has_digits": domain_has_digits, + "domain_hyphen_count": domain_hyphen_count, + # 7. Suspicious + "phishing_keyword_count": phishing_keyword_count, + "brand_count": brand_count, + "has_suspicious_ext": has_suspicious_ext, + "brand_in_subdomain": brand_in_subdomain, + "suspicious_word_ratio": suspicious_word_ratio, + # 8. Path / query + "path_depth": path_depth, + "longest_path_token": longest_path_token, + "avg_path_token_len": avg_path_token_len, + "max_consecutive_digits": max_consecutive_digits, + "path_entropy": path_entropy, + } diff --git a/backend/app/services/url_service.py b/backend/app/services/url_service.py new file mode 100644 index 0000000000000000000000000000000000000000..bd9f33e5f67ee56128ff04cbd6a37aca3caf1044 --- /dev/null +++ b/backend/app/services/url_service.py @@ -0,0 +1,334 @@ +ο»Ώ""" +URL Malware Detection Service Ò€” Stacking HyperModel. + +Full inference pipeline: + 1. Extract 54 lexical features from URL + 2. Scale features with StandardScaler + 3. Run 5 base models (XGBoost, LightGBM, TF-IDF+LR, CharCNN, CharBiLSTM) + 4. Stack their probability outputs Ò†’ 10 meta-features + 5. Meta-learner (XGBoost) produces final prediction +""" + +from __future__ import annotations + +import logging +import time +import warnings +from pathlib import Path +from functools import lru_cache + +import numpy as np +import joblib + +from .url_feature_engineering import extract_url_features, extract_url_features_dict, FEATURE_NAMES + +logger = logging.getLogger(__name__) + +# Ò”€Ò”€ DL architecture definitions (inline, no external dependency) Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€Ò”€ +# These mirror the exact architectures from the training notebook. + +MAX_URL_LEN = 200 + +# Character lookup table +_CHAR_LUT = np.zeros(256, dtype=np.int64) +_PRINTABLE = ( + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ " +) +for _i, _ch in enumerate(_PRINTABLE, start=1): + _CHAR_LUT[ord(_ch)] = _i +_UNK_ID = len(_PRINTABLE) + 1 # 96 +VOCAB_SIZE = _UNK_ID + 1 # 97 + +try: + import torch + import torch.nn as nn + TORCH_AVAILABLE = True +except ImportError: + TORCH_AVAILABLE = False + logger.warning("PyTorch not available Ò€” DL base models will be skipped") + + +def _url_to_tensor(urls: list[str], max_len: int = MAX_URL_LEN): + """Vectorised charÒ†’int encoding for a batch of URL strings.""" + arr = np.zeros((len(urls), max_len), dtype=np.int64) + for i, url in enumerate(urls): + raw = str(url)[:max_len] + chars = np.frombuffer(raw.encode("ascii", "ignore"), dtype=np.uint8) + if len(chars) == 0: + continue + ids = _CHAR_LUT[chars] + ids = np.where(ids > 0, ids, _UNK_ID) + arr[i, : len(ids)] = ids[: max_len] + import torch + return torch.from_numpy(arr) + + +if TORCH_AVAILABLE: + class CharCNNNet(nn.Module): + """1-D CNN on character-level URL embeddings.""" + def __init__(self, num_classes: int = 2, embed_dim: int = 64): + super().__init__() + self.embed = nn.Embedding(VOCAB_SIZE, embed_dim, padding_idx=0) + self.convs = nn.Sequential( + nn.Conv1d(embed_dim, 128, kernel_size=3, padding=1), + nn.BatchNorm1d(128), nn.ReLU(), nn.MaxPool1d(2), + nn.Conv1d(128, 128, kernel_size=3, padding=1), + nn.BatchNorm1d(128), nn.ReLU(), nn.MaxPool1d(2), + nn.Conv1d(128, 256, kernel_size=3, padding=1), + nn.BatchNorm1d(256), nn.ReLU(), nn.AdaptiveMaxPool1d(1), + ) + self.head = nn.Sequential( + nn.Dropout(0.3), nn.Linear(256, 128), nn.ReLU(), + nn.Dropout(0.2), nn.Linear(128, num_classes), + ) + + def forward(self, x): + x = self.embed(x).permute(0, 2, 1) + x = self.convs(x).squeeze(-1) + return self.head(x) + + class CharBiLSTMNet(nn.Module): + """Bidirectional LSTM on character embeddings.""" + def __init__(self, num_classes: int = 2, embed_dim: int = 64, + hidden: int = 128, n_layers: int = 2): + super().__init__() + self.embed = nn.Embedding(VOCAB_SIZE, embed_dim, padding_idx=0) + self.lstm = nn.LSTM( + embed_dim, hidden, num_layers=n_layers, + batch_first=True, bidirectional=True, dropout=0.3, + ) + self.head = nn.Sequential( + nn.Dropout(0.3), nn.Linear(hidden * 2, 128), nn.ReLU(), + nn.Dropout(0.2), nn.Linear(128, num_classes), + ) + + def forward(self, x): + x = self.embed(x) + _, (h, _) = self.lstm(x) + h = torch.cat([h[-2], h[-1]], dim=-1) + return self.head(h) + + +class URLModelService: + """ + Stacking HyperModel service for URL malware detection. + + Loads all base models + meta-learner at initialization time. + Thread-safe for concurrent FastAPI requests. + """ + + def __init__(self, models_dir: str | Path | None = None): + if models_dir is None: + # Default to urlmodel_info/ in project root + models_dir = Path(__file__).parent.parent.parent.parent / "urlmodel_info" + self.models_dir = Path(models_dir) + + self.scaler = None + self.meta_learner = None + self.xgb_model = None + self.lgbm_model = None + self.tfidf_lr_model = None + self.cnn_net = None + self.bilstm_net = None + self.model_loaded = False + self._dl_available = False + + self._load_models() + + def _load_models(self): + """Load all model components.""" + logger.info("Loading URL HyperModel components...") + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + + # 1. Scaler + scaler_path = self.models_dir / "scaler.joblib" + self.scaler = joblib.load(scaler_path) + logger.info(f" Scaler loaded ({self.scaler.n_features_in_} features)") + + # 2. Meta-learner + meta_path = self.models_dir / "hypermodel_meta.joblib" + self.meta_learner = joblib.load(meta_path) + logger.info(f" Meta-learner loaded ({self.meta_learner.n_features_in_} meta-features)") + + # 3. XGBoost base model + xgb_path = self.models_dir / "xgb_binary.joblib" + self.xgb_model = joblib.load(xgb_path) + logger.info(" XGBoost base model loaded") + + # 4. LightGBM base model + lgbm_path = self.models_dir / "lgbm_binary.joblib" + self.lgbm_model = joblib.load(lgbm_path) + logger.info(" LightGBM base model loaded") + + # 5. TF-IDF + LR pipeline + tfidf_path = self.models_dir / "tfidf_lr_binary.joblib" + self.tfidf_lr_model = joblib.load(tfidf_path) + logger.info(" TF-IDF + LR pipeline loaded") + + # 6. Deep Learning models (optional Ò€” requires PyTorch) + if TORCH_AVAILABLE: + try: + cnn_path = self.models_dir / "char_cnn_net.pt" + bilstm_path = self.models_dir / "char_bilstm_net.pt" + + self.cnn_net = CharCNNNet(num_classes=2) + self.cnn_net.load_state_dict( + torch.load(cnn_path, map_location="cpu", weights_only=True) + ) + self.cnn_net.eval() + logger.info(" CharCNN loaded") + + self.bilstm_net = CharBiLSTMNet(num_classes=2) + self.bilstm_net.load_state_dict( + torch.load(bilstm_path, map_location="cpu", weights_only=True) + ) + self.bilstm_net.eval() + logger.info(" CharBiLSTM loaded") + + self._dl_available = True + except Exception as e: + logger.warning(f" DL models failed to load: {e}") + self._dl_available = False + + self.model_loaded = True + n_base = 3 + (2 if self._dl_available else 0) + logger.info(f"URL HyperModel ready ({n_base} base models + meta-learner)") + + def predict(self, url: str, threshold: float = 0.5) -> dict: + """ + Run the full stacking pipeline on a single URL. + + Returns dict with: + - url: input URL + - prediction: 'Malicious' or 'Benign' + - malicious_score: float [0, 1] + - confidence: str percentage + - confidence_level: 'High', 'Medium', or 'Low' + - base_model_scores: dict of individual model scores + - top_signals: dict of most important feature values + - inference_time_ms: float + """ + start = time.perf_counter() + + # 1. Extract features + features = extract_url_features(url) + features_dict = extract_url_features_dict(url) + X_feat = features.reshape(1, -1) + + # 2. Scale features + X_scaled = self.scaler.transform(X_feat).astype(np.float32) + + # 3. Get base model predictions + p_xgb = self.xgb_model.predict_proba(X_scaled) + p_lgbm = self.lgbm_model.predict_proba(X_scaled) + p_tfidf = self.tfidf_lr_model.predict_proba(np.array([url])) + + base_scores = { + "XGBoost": float(p_xgb[0, 1]), + "LightGBM": float(p_lgbm[0, 1]), + "TF-IDF + LR": float(p_tfidf[0, 1]), + } + + # 4. DL models (if available) + if self._dl_available: + xt = _url_to_tensor([url]) + with torch.no_grad(): + p_cnn = torch.softmax(self.cnn_net(xt).float(), dim=-1).numpy() + p_bilstm = torch.softmax(self.bilstm_net(xt).float(), dim=-1).numpy() + base_scores["CharCNN"] = float(p_cnn[0, 1]) + base_scores["CharBiLSTM"] = float(p_bilstm[0, 1]) + meta_features = np.hstack([p_xgb, p_lgbm, p_tfidf, p_cnn, p_bilstm]) + else: + # Fallback: pad with zeros for missing DL models + zeros = np.zeros((1, 2), dtype=np.float32) + meta_features = np.hstack([p_xgb, p_lgbm, p_tfidf, zeros, zeros]) + + meta_features = meta_features.astype(np.float32) + + # 5. Meta-learner prediction + final_proba = self.meta_learner.predict_proba(meta_features) + malicious_score = float(final_proba[0, 1]) + + # Determine verdict + prediction = "Malicious" if malicious_score > threshold else "Benign" + confidence_pct = abs(malicious_score - 0.5) * 200 + + if confidence_pct >= 80: + confidence_level = "High" + elif confidence_pct >= 50: + confidence_level = "Medium" + else: + confidence_level = "Low" + + # Top feature signals + important_features = [ + "has_ip", "has_suspicious_tld", "phishing_keyword_count", + "brand_in_subdomain", "has_punycode", "is_shortened", + "url_length", "num_subdomains", "has_https", "domain_entropy", + "has_suspicious_ext", "has_hex_encoding", "brand_count", + "path_depth", "url_entropy", + ] + top_signals = {} + for feat in important_features: + if feat in features_dict: + val = features_dict[feat] + if val != 0: + top_signals[feat] = round(float(val), 4) + + elapsed = (time.perf_counter() - start) * 1000 + + return { + "url": url, + "prediction": prediction, + "malicious_score": round(malicious_score, 6), + "confidence": f"{confidence_pct:.1f}%", + "confidence_level": confidence_level, + "threshold_used": threshold, + "base_model_scores": base_scores, + "top_signals": top_signals, + "inference_time_ms": round(elapsed, 2), + } + + def get_model_info(self) -> dict: + """Return info about loaded models.""" + return { + "model_type": "Stacking HyperModel", + "base_models": list(self._get_base_model_names()), + "meta_learner": "XGBoost (GPU-trained)", + "scaler_features": self.scaler.n_features_in_, + "meta_features": self.meta_learner.n_features_in_, + "dl_available": self._dl_available, + "feature_categories": [ + "Length/structural (7)", + "Character counts (14)", + "Character ratios (5)", + "Entropy/randomness (2)", + "Boolean indicators (10)", + "Domain/TLD signals (6)", + "Suspicious patterns (5)", + "Path & query (5)", + ], + } + + def _get_base_model_names(self): + names = ["XGBoost", "LightGBM", "TF-IDF + LR"] + if self._dl_available: + names.extend(["CharCNN", "CharBiLSTM"]) + return names + + +# Singleton accessor +_url_service: URLModelService | None = None + + +def get_url_service() -> URLModelService: + """Get or create the singleton URL model service.""" + global _url_service + if _url_service is None: + _url_service = URLModelService() + return _url_service diff --git a/backend/app/services/virustotal_service.py b/backend/app/services/virustotal_service.py new file mode 100644 index 0000000000000000000000000000000000000000..705949cc3affaaaa14bf7ab98e1c8a1f5bd65cad --- /dev/null +++ b/backend/app/services/virustotal_service.py @@ -0,0 +1,226 @@ +""" +VirusTotal API Service for hash verification. +Provides secondary verification of malware samples. +""" + +import logging +from typing import Optional +import httpx + +from ..config import settings +from ..models.virustotal import ( + VirusTotalResponse, + VirusTotalStats, + EngineResult, + MalwareTypeInfo, +) +from .malware_type_service import get_malware_type_service + +logger = logging.getLogger(__name__) + +VIRUSTOTAL_API_BASE = "https://www.virustotal.com/api/v3" + + +class VirusTotalService: + """ + VirusTotal API Service for file hash lookups. + + Provides: + - Hash lookup for SHA256/SHA1/MD5 + - Detection ratio calculation + - Engine verdict extraction + - Reputation score + """ + + def __init__(self): + self.api_key = settings.virustotal_api_key + self.initialized = bool(self.api_key) + self._client: Optional[httpx.AsyncClient] = None + + async def _get_client(self) -> httpx.AsyncClient: + """Get or create HTTP client.""" + if self._client is None: + self._client = httpx.AsyncClient( + timeout=30.0, + headers={ + "x-apikey": self.api_key, + "Accept": "application/json" + } + ) + return self._client + + async def close(self): + """Close HTTP client.""" + if self._client: + await self._client.aclose() + self._client = None + + async def lookup_hash(self, sha256: str) -> VirusTotalResponse: + """ + Look up a file hash on VirusTotal. + + Args: + sha256: SHA256 hash to look up + + Returns: + VirusTotalResponse with detection results + """ + if not self.initialized: + return VirusTotalResponse( + sha256=sha256, + found=False, + error_message="VirusTotal API key not configured" + ) + + try: + client = await self._get_client() + url = f"{VIRUSTOTAL_API_BASE}/files/{sha256}" + + response = await client.get(url) + + if response.status_code == 404: + return VirusTotalResponse( + sha256=sha256, + found=False, + error_message="Hash not found in VirusTotal database" + ) + + if response.status_code == 401: + return VirusTotalResponse( + sha256=sha256, + found=False, + error_message="Invalid VirusTotal API key" + ) + + if response.status_code == 429: + return VirusTotalResponse( + sha256=sha256, + found=False, + error_message="VirusTotal API rate limit exceeded" + ) + + response.raise_for_status() + data = response.json() + + return self._parse_response(sha256, data) + + except httpx.TimeoutException: + logger.error(f"VirusTotal API timeout for hash: {sha256}") + return VirusTotalResponse( + sha256=sha256, + found=False, + error_message="VirusTotal API request timed out" + ) + except httpx.HTTPError as e: + logger.error(f"VirusTotal API error: {e}") + return VirusTotalResponse( + sha256=sha256, + found=False, + error_message=f"VirusTotal API error: {str(e)}" + ) + except Exception as e: + logger.error(f"Unexpected error in VirusTotal lookup: {e}") + return VirusTotalResponse( + sha256=sha256, + found=False, + error_message=f"Unexpected error: {str(e)}" + ) + + def _parse_response(self, sha256: str, data: dict) -> VirusTotalResponse: + """Parse VirusTotal API response into structured format.""" + try: + attributes = data.get("data", {}).get("attributes", {}) + + # Parse detection stats + stats_data = attributes.get("last_analysis_stats", {}) + stats = VirusTotalStats( + malicious=stats_data.get("malicious", 0), + suspicious=stats_data.get("suspicious", 0), + undetected=stats_data.get("undetected", 0), + harmless=stats_data.get("harmless", 0), + timeout=stats_data.get("timeout", 0), + confirmed_timeout=stats_data.get("confirmed-timeout", 0), + failure=stats_data.get("failure", 0), + type_unsupported=stats_data.get("type-unsupported", 0), + ) + + # Calculate totals + malicious_count = stats.malicious + stats.suspicious + total_engines = ( + stats.malicious + stats.suspicious + + stats.undetected + stats.harmless + ) + detection_ratio = malicious_count / total_engines if total_engines > 0 else 0 + + # Parse engine results (top 20 for brevity) + engine_results = [] + vt_labels = [] # Collect labels for malware type classification + last_analysis = attributes.get("last_analysis_results", {}) + for engine_name, result in list(last_analysis.items())[:20]: + engine_results.append(EngineResult( + engine_name=engine_name, + category=result.get("category", "unknown"), + result=result.get("result"), + engine_version=result.get("engine_version"), + engine_update=result.get("engine_update"), + )) + # Collect detection labels for malware type classification + if result.get("result"): + vt_labels.append(result.get("result")) + + # Get dates + first_submission = attributes.get("first_submission_date") + last_analysis_date = attributes.get("last_analysis_date") + + # Classify malware type if detected as malicious + malware_type = None + if malicious_count > 0 and vt_labels: + try: + malware_service = get_malware_type_service() + type_result = malware_service.classify(vt_labels=vt_labels) + malware_type = MalwareTypeInfo( + primary_type=type_result.primary_type, + confidence=type_result.confidence, + secondary_types=type_result.secondary_types, + indicators=type_result.indicators, + source=type_result.source + ) + except Exception as e: + logger.warning(f"Failed to classify malware type: {e}") + + return VirusTotalResponse( + sha256=sha256, + found=True, + stats=stats, + detection_ratio=round(detection_ratio, 4), + total_engines=total_engines, + malicious_count=malicious_count, + reputation_score=attributes.get("reputation"), + engine_results=engine_results, + first_submission_date=str(first_submission) if first_submission else None, + last_analysis_date=str(last_analysis_date) if last_analysis_date else None, + meaningful_name=attributes.get("meaningful_name"), + malware_type=malware_type, + ) + + except Exception as e: + logger.error(f"Failed to parse VirusTotal response: {e}") + return VirusTotalResponse( + sha256=sha256, + found=True, + error_message=f"Failed to parse response: {str(e)}" + ) + + +# Global service instance +_vt_service: Optional[VirusTotalService] = None + + +def get_virustotal_service() -> VirusTotalService: + """Get the global VirusTotal service instance.""" + global _vt_service + + if _vt_service is None: + _vt_service = VirusTotalService() + + return _vt_service diff --git a/backend/pytest.ini b/backend/pytest.ini new file mode 100644 index 0000000000000000000000000000000000000000..654b7ebb342160392d268cb0b01a2fbdb3b71519 --- /dev/null +++ b/backend/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +testpaths = tests +pythonpath = . +asyncio_mode = auto diff --git a/backend/requirements.txt b/backend/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a169e019887655c18b78aae3b418f9d25e6f3b4 --- /dev/null +++ b/backend/requirements.txt @@ -0,0 +1,40 @@ +# Malware Detection Platform - Backend Dependencies +# Python 3.10+ required + +# FastAPI Framework with all extras (includes uvicorn, etc.) +fastapi[standard]>=0.115.0 + +# Pydantic for data validation +pydantic>=2.10.0 +pydantic-settings>=2.7.0 + +# Async HTTP client for VirusTotal API +httpx>=0.28.0 + +# Testing +pytest>=8.3.0 +pytest-asyncio>=0.25.0 + +# Rate limiting +slowapi>=0.1.9 + +# Machine Learning +numpy>=2.2.0 +scikit-learn>=1.6.0 +joblib>=1.4.0 +xgboost>=2.1.0 + +# PE File Parsing for EMBER feature extraction +lief>=0.15.0 + +# SHAP for explainability (optional but recommended) +shap>=0.46.0 + +# Google Generative AI (Gemini) +google-generativeai>=0.8.0 + +# Multipart form data handling +python-multipart>=0.0.18 + +# Additional utilities +python-dotenv>=1.0.1 diff --git a/backend/tests/__init__.py b/backend/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/backend/tests/__init__.py @@ -0,0 +1 @@ + diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..f555081663c82568ed8c5c3ae1af5dc6eaf35eb1 --- /dev/null +++ b/backend/tests/conftest.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +from dataclasses import dataclass +import pytest +from fastapi.testclient import TestClient + +from app.main import app +from app.models.prediction import ConfidenceLevel, PredictionLabel, PredictionResponse +from app.models.virustotal import VirusTotalResponse + + +FEATURE_COUNT = 2381 +FEATURES = [0.0] * FEATURE_COUNT +SHA256 = "a" * 64 + + +class FakeMLService: + model_loaded = True + feature_count = FEATURE_COUNT + model = object() + + def predict(self, features, threshold=None, sha256=None): + if len(features) != self.feature_count: + raise ValueError(f"Expected {self.feature_count} features, got {len(features)}") + used_threshold = 0.5 if threshold is None else threshold + return PredictionResponse( + prediction=PredictionLabel.MALICIOUS, + probability=0.91, + confidence=ConfidenceLevel.HIGH, + threshold_used=used_threshold, + sha256=sha256, + inference_time_ms=1.2, + ) + + def get_model_info(self): + return { + "loaded": True, + "feature_count": self.feature_count, + "default_threshold": 0.5, + "model_type": "FakeModel", + } + + +class FakeSHAPService: + initialized = True + + def initialize(self, model): + self.initialized = True + + def get_feature_importance(self, features, model=None, top_k=10): + return [] + + def explain(self, features): + return [] + + +class FakeGeminiService: + initialized = False + model = None + + def initialize(self): + self.initialized = False + + async def explain_prediction(self, prediction, features=None): + return { + "risk_explanation": "Deterministic test explanation.", + "severity_level": "High", + "key_indicators": ["test signal"], + "analyst_summary": "Smoke test summary.", + "mitigation_steps": ["isolate sample"], + } + + +class FakeURLService: + model_loaded = True + _dl_available = False + + def predict(self, url, threshold=0.5): + return { + "url": url, + "prediction": "Malicious", + "malicious_score": 0.84, + "confidence": "84.0%", + "confidence_level": "High", + "threshold_used": threshold, + "base_model_scores": {"XGBoost": 0.8}, + "top_signals": {"url_length": 0.4}, + "inference_time_ms": 3.4, + } + + def get_model_info(self): + return { + "model_type": "Fake URL HyperModel", + "base_models": ["XGBoost"], + "meta_learner": "XGBoost", + "scaler_features": 54, + "meta_features": 10, + "dl_available": self._dl_available, + "feature_categories": ["lexical"], + } + + +class FakeVirusTotalService: + initialized = True + next_result: VirusTotalResponse | None = None + + async def lookup_hash(self, sha256): + if self.next_result is not None: + return self.next_result + return VirusTotalResponse( + sha256=sha256, + found=True, + detection_ratio=0.25, + total_engines=20, + malicious_count=5, + ) + + +class FakeFeedbackService: + def __init__(self): + self.malware_total = 0 + self.url_total = 0 + + def log_malware_feedback(self, **kwargs): + self.malware_total += 1 + return { + "success": True, + "reward": 1, + "message": "Agreement with VirusTotal logged", + "total_feedback_count": self.malware_total, + } + + def log_url_feedback(self, **kwargs): + self.url_total += 1 + return { + "success": True, + "reward": 1, + "message": "Feedback recorded", + "total_feedback_count": self.url_total, + } + + def maybe_auto_update(self, model_type): + return None + + def get_stats(self): + return { + "malware_total": self.malware_total, + "malware_agree": self.malware_total, + "malware_disagree": 0, + "malware_agreement_rate": 100.0 if self.malware_total else 0.0, + "url_total": self.url_total, + "url_correct": self.url_total, + "url_incorrect": 0, + "url_accuracy_rate": 100.0 if self.url_total else 0.0, + "recent_malware": [], + "recent_url": [], + "model_updates": [], + } + + +@dataclass +class Services: + ml: FakeMLService + shap: FakeSHAPService + gemini: FakeGeminiService + url: FakeURLService + virustotal: FakeVirusTotalService + feedback: FakeFeedbackService + + +@pytest.fixture +def features(): + return list(FEATURES) + + +@pytest.fixture +def sha256(): + return SHA256 + + +@pytest.fixture +def services(monkeypatch): + fakes = Services( + ml=FakeMLService(), + shap=FakeSHAPService(), + gemini=FakeGeminiService(), + url=FakeURLService(), + virustotal=FakeVirusTotalService(), + feedback=FakeFeedbackService(), + ) + + from app.routers import chat, feedback, predict, upload, url, virustotal + from app import main + + app.dependency_overrides[predict.get_ml_service] = lambda: fakes.ml + app.dependency_overrides[predict.get_gemini_service] = lambda: fakes.gemini + app.dependency_overrides[virustotal.get_ml_service] = lambda: fakes.ml + app.dependency_overrides[virustotal.get_virustotal_service] = lambda: fakes.virustotal + + monkeypatch.setattr(main, "get_ml_service", lambda: fakes.ml) + monkeypatch.setattr(main, "get_gemini_service", lambda: fakes.gemini) + monkeypatch.setattr(main, "get_virustotal_service", lambda: fakes.virustotal) + monkeypatch.setattr(predict, "get_shap_service", lambda: fakes.shap) + monkeypatch.setattr(chat, "get_gemini_service", lambda: fakes.gemini) + monkeypatch.setattr(upload, "get_ml_service", lambda: fakes.ml) + monkeypatch.setattr(upload, "get_shap_service", lambda: fakes.shap) + monkeypatch.setattr(upload, "get_gemini_service", lambda: fakes.gemini) + monkeypatch.setattr(upload, "LIEF_AVAILABLE", True) + monkeypatch.setattr(url, "get_url_service", lambda: fakes.url) + monkeypatch.setattr(feedback, "get_feedback_service", lambda: fakes.feedback) + monkeypatch.setattr(virustotal, "get_feedback_service", lambda: fakes.feedback) + + yield fakes + app.dependency_overrides.clear() + + +@pytest.fixture +def client(services): + return TestClient(app) diff --git a/backend/tests/test_chat.py b/backend/tests/test_chat.py new file mode 100644 index 0000000000000000000000000000000000000000..18779c601ed559d040b56497e1d658b6a7ac4208 --- /dev/null +++ b/backend/tests/test_chat.py @@ -0,0 +1,10 @@ +def test_chat_uses_fallback_when_gemini_unavailable(client): + response = client.post( + "/api/chat/", + json={"message": "How does malware detection work?"}, + ) + + assert response.status_code == 200 + body = response.json() + assert body["success"] is True + assert "MalwareGuard analyzes Windows PE files" in body["response"] diff --git a/backend/tests/test_feedback.py b/backend/tests/test_feedback.py new file mode 100644 index 0000000000000000000000000000000000000000..4810d5bf67e2d089b6d1f26625e065d401f3e217 --- /dev/null +++ b/backend/tests/test_feedback.py @@ -0,0 +1,23 @@ +def test_feedback_log_and_stats_happy_path(client, features, sha256): + log_response = client.post( + "/api/feedback/malware", + json={ + "features": features, + "sha256": sha256, + "predicted_label": "Malicious", + "predicted_probability": 0.91, + "vt_malicious_count": 5, + "vt_total_engines": 20, + "vt_detection_ratio": 0.25, + }, + ) + + assert log_response.status_code == 200 + assert log_response.json()["total_feedback_count"] == 1 + + stats_response = client.get("/api/feedback/stats") + + assert stats_response.status_code == 200 + stats = stats_response.json() + assert stats["malware_total"] == 1 + assert stats["malware_agree"] == 1 diff --git a/backend/tests/test_health.py b/backend/tests/test_health.py new file mode 100644 index 0000000000000000000000000000000000000000..135ae04135ad2fc51d8e6e7e17a2b48a1acb5417 --- /dev/null +++ b/backend/tests/test_health.py @@ -0,0 +1,24 @@ +def test_root_and_global_health(client): + root = client.get("/") + health = client.get("/health") + + assert root.status_code == 200 + assert root.json()["status"] == "running" + assert health.status_code == 200 + assert health.json()["status"] == "healthy" + + +def test_service_health_routes(client): + routes = [ + "/api/predict/health", + "/api/virustotal/health", + "/api/chat/health", + "/api/url/health", + "/api/feedback/health", + "/api/upload/health", + ] + + for route in routes: + response = client.get(route) + assert response.status_code == 200, route + assert "status" in response.json() diff --git a/backend/tests/test_predict.py b/backend/tests/test_predict.py new file mode 100644 index 0000000000000000000000000000000000000000..8f582d7b93504d61f087ad3a175e8903ff97401d --- /dev/null +++ b/backend/tests/test_predict.py @@ -0,0 +1,23 @@ +def test_predict_happy_path(client, features, sha256): + response = client.post("/api/predict", json={"features": features, "sha256": sha256}) + + assert response.status_code == 200 + body = response.json() + assert body["prediction"]["prediction"] == "Malicious" + assert body["prediction"]["probability"] == 0.91 + assert body["prediction"]["sha256"] == sha256 + + +def test_predict_rejects_wrong_feature_count(client): + response = client.post("/api/predict", json={"features": [0.0] * 10}) + + assert response.status_code == 422 + + +def test_predict_rejects_bad_threshold(client, features): + response = client.post( + "/api/predict", + json={"features": features, "threshold": 1.5}, + ) + + assert response.status_code == 422 diff --git a/backend/tests/test_upload.py b/backend/tests/test_upload.py new file mode 100644 index 0000000000000000000000000000000000000000..5c7be426017c0e1964a31e74334ccfa54b4a0e10 --- /dev/null +++ b/backend/tests/test_upload.py @@ -0,0 +1,45 @@ +import numpy as np + + +def test_upload_rejects_non_mz_file(client): + response = client.post( + "/api/upload/analyze", + files={"file": ("note.txt", b"hello", "text/plain")}, + ) + + assert response.status_code == 400 + assert "Invalid PE file" in response.json()["detail"] + + +def test_upload_rejects_size_limit(client): + oversized = b"MZ" + (b"0" * (50 * 1024 * 1024 + 1)) + + response = client.post( + "/api/upload/analyze", + files={"file": ("big.exe", oversized, "application/octet-stream")}, + ) + + assert response.status_code == 400 + assert "File too large" in response.json()["detail"] + + +def test_upload_analyze_happy_path_with_mocked_lief(client, monkeypatch): + from app.routers import upload + + monkeypatch.setattr(upload, "LIEF_AVAILABLE", True) + monkeypatch.setattr( + upload, + "extract_features_and_lief", + lambda content: (np.zeros(2381, dtype=float), "unused", object()), + ) + + response = client.post( + "/api/upload/analyze?include_explanation=false", + files={"file": ("sample.exe", b"MZfake-pe", "application/octet-stream")}, + ) + + assert response.status_code == 200 + body = response.json() + assert body["features_extracted"] is True + assert body["feature_count"] == 2381 + assert body["prediction"]["prediction"] == "Malicious" diff --git a/backend/tests/test_url.py b/backend/tests/test_url.py new file mode 100644 index 0000000000000000000000000000000000000000..8c30613e991f7e72cb9f77e32e9be5bbea1d1ec6 --- /dev/null +++ b/backend/tests/test_url.py @@ -0,0 +1,19 @@ +def test_url_analyze_happy_path(client): + response = client.post( + "/api/url/analyze", + json={"url": "https://example.com/login", "threshold": 0.4}, + ) + + assert response.status_code == 200 + body = response.json() + assert body["prediction"] == "Malicious" + assert body["threshold_used"] == 0.4 + + +def test_url_analyze_returns_503_when_model_not_loaded(client, services): + services.url.model_loaded = False + + response = client.post("/api/url/analyze", json={"url": "https://example.com"}) + + assert response.status_code == 503 + assert response.json()["detail"] == "URL model not loaded" diff --git a/backend/tests/test_virustotal.py b/backend/tests/test_virustotal.py new file mode 100644 index 0000000000000000000000000000000000000000..c50879f864485031223c66a63b008cd8e289cc48 --- /dev/null +++ b/backend/tests/test_virustotal.py @@ -0,0 +1,23 @@ +from app.models.virustotal import VirusTotalResponse + + +def test_virustotal_rejects_bad_hash(client): + response = client.get("/api/virustotal/not-a-hash") + + assert response.status_code == 422 + + +def test_virustotal_compare_returns_404_for_not_found(client, features, sha256, services): + services.virustotal.next_result = VirusTotalResponse( + sha256=sha256, + found=False, + error_message="Hash not found in VirusTotal database", + ) + + response = client.post( + "/api/virustotal/compare", + json={"features": features, "sha256": sha256}, + ) + + assert response.status_code == 404 + assert "Hash not found" in response.json()["detail"] diff --git a/urlmodel_info/case_study_results.csv b/urlmodel_info/case_study_results.csv new file mode 100644 index 0000000000000000000000000000000000000000..411cfba15e25cc37ac717ec9732a9c9ee94df99d --- /dev/null +++ b/urlmodel_info/case_study_results.csv @@ -0,0 +1,18 @@ +Description,True Label,XGB Score,LGB Score,TF-IDF Score,HyperModel,Prediction,Correct +Legitimate Google,Benign,0.999,0.999,1.0,1.0,Malicious,❌ +Legitimate Amazon,Benign,1.0,1.0,1.0,1.0,Malicious,❌ +Legitimate GitHub,Benign,0.998,0.998,1.0,1.0,Malicious,❌ +Legitimate Wikipedia,Benign,1.0,1.0,0.998,1.0,Malicious,❌ +Typosquatting Google,Malicious,0.986,0.997,0.999,1.0,Malicious,βœ… +Typosquatting Amazon,Malicious,0.993,0.99,0.995,1.0,Malicious,βœ… +Typosquatting PayPal,Malicious,0.981,0.988,0.991,1.0,Malicious,βœ… +Brand subdomain phishing,Malicious,0.982,0.996,1.0,1.0,Malicious,βœ… +Brand path phishing,Malicious,0.997,0.998,0.999,1.0,Malicious,βœ… +IP-based phishing,Malicious,1.0,0.999,0.992,1.0,Malicious,βœ… +IP-based phishing 2,Malicious,1.0,0.999,0.996,1.0,Malicious,βœ… +Punycode phishing,Malicious,0.982,0.974,0.999,1.0,Malicious,βœ… +URL shortener (suspicious),Malicious,0.998,0.997,1.0,1.0,Malicious,βœ… +Hex-encoded phishing,Malicious,0.903,0.971,0.947,1.0,Malicious,βœ… +Long suspicious URL,Malicious,0.877,0.805,0.831,1.0,Malicious,βœ… +Legit MS Security,Benign,1.0,1.0,0.999,1.0,Malicious,❌ +Legit Google OAuth,Benign,0.999,0.999,0.993,1.0,Malicious,❌ diff --git a/urlmodel_info/case_study_scores.png b/urlmodel_info/case_study_scores.png new file mode 100644 index 0000000000000000000000000000000000000000..f1081013ebfa56de9e4427c0f3302609063ffd04 --- /dev/null +++ b/urlmodel_info/case_study_scores.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04438f399bee753e19f4f9044b70081dcb66c3cb92be92fdb76a7add8b8bb1d4 +size 160243 diff --git a/urlmodel_info/char_bilstm_net.pt b/urlmodel_info/char_bilstm_net.pt new file mode 100644 index 0000000000000000000000000000000000000000..1610b341a1d988bab4a2b3083448b3becd8efb31 --- /dev/null +++ b/urlmodel_info/char_bilstm_net.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6abb849aa9d0ecbea8a58b817606fb3be9a8e9a45cc815ef3102c2e28368060d +size 2537781 diff --git a/urlmodel_info/char_cnn_net.pt b/urlmodel_info/char_cnn_net.pt new file mode 100644 index 0000000000000000000000000000000000000000..c4eb4d9e5e3fb6448cbf111ab347f75fbe1e58b5 --- /dev/null +++ b/urlmodel_info/char_cnn_net.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4dd4f4b78b8d6c34f331ab952846b65e579ecdae1ca4c811984d2e5ba00f3bb3 +size 865013 diff --git a/urlmodel_info/download_data.py b/urlmodel_info/download_data.py new file mode 100644 index 0000000000000000000000000000000000000000..56b847510b78ad2a7153b43aa4345a90add4e47f --- /dev/null +++ b/urlmodel_info/download_data.py @@ -0,0 +1,111 @@ +""" +Download the Malicious URLs dataset (~651K rows, 4 classes). + +Dataset: Manu Siddhartha β€” Malicious URLs Dataset +Source: https://www.kaggle.com/datasets/sid321axn/malicious-urls-dataset +Classes: benign (428,103) Β· defacement (96,457) Β· phishing (94,111) Β· malware (32,520) +""" + +import os +import sys +import pathlib +import shutil +import subprocess +import glob + +KAGGLE_SLUG = "sid321axn/malicious-urls-dataset" + +CSV_FILENAME = "malicious_phishing.csv" + + +def download_malicious_urls(data_dir) -> pathlib.Path: + """Download and return the path to the Malicious URLs CSV. + + Tries kagglehub first, then the kaggle CLI, then prints manual + download instructions. + + Parameters + ---------- + data_dir : str or pathlib.Path + Directory to store the downloaded CSV. + + Returns + ------- + pathlib.Path + Path to the CSV file. + """ + data_dir = pathlib.Path(data_dir) + data_dir.mkdir(parents=True, exist_ok=True) + csv_path = data_dir / CSV_FILENAME + + if csv_path.exists(): + print(f"βœ… Dataset already exists: {csv_path}") + return csv_path + + # ── Attempt 1: kagglehub ────────────────────────────────────────────── + try: + import kagglehub + except ImportError: + subprocess.check_call( + [sys.executable, "-m", "pip", "install", "kagglehub", "-q"] + ) + import kagglehub + + try: + print("Downloading via kagglehub …") + dl_path = kagglehub.dataset_download(KAGGLE_SLUG) + src = _find_csv(dl_path) + if src: + shutil.copy2(src, csv_path) + print(f"βœ… Dataset saved to {csv_path}") + return csv_path + except Exception as e: + print(f" kagglehub failed: {e}") + + # ── Attempt 2: kaggle CLI ──────────────────────────────────────────── + if shutil.which("kaggle"): + try: + print("Downloading via kaggle CLI …") + subprocess.check_call( + [ + "kaggle", "datasets", "download", + "-d", KAGGLE_SLUG, + "-p", str(data_dir), + "--unzip", + ], + timeout=300, + ) + src = _find_csv(str(data_dir)) + if src and pathlib.Path(src) != csv_path: + shutil.move(src, csv_path) + if csv_path.exists(): + print(f"βœ… Dataset saved to {csv_path}") + return csv_path + except Exception as e: + print(f" kaggle CLI failed: {e}") + + # ── Manual instructions ────────────────────────────────────────────── + print("\n" + "=" * 60) + print(" MANUAL DOWNLOAD REQUIRED") + print("=" * 60) + print(f" 1. Visit: https://www.kaggle.com/datasets/{KAGGLE_SLUG}") + print(f" 2. Click 'Download' and extract the ZIP") + print(f" 3. Place '{CSV_FILENAME}' in: {data_dir.resolve()}") + print("=" * 60) + raise FileNotFoundError( + f"Could not auto-download dataset. Place '{CSV_FILENAME}' in {data_dir}" + ) + + +def _find_csv(root_dir: str): + """Walk a directory tree and return the first CSV file path found.""" + for dirpath, _, filenames in os.walk(root_dir): + for fn in filenames: + if fn.endswith(".csv"): + return os.path.join(dirpath, fn) + return None + + +if __name__ == "__main__": + path = download_malicious_urls("data") + print(f"Dataset at: {path}") diff --git a/urlmodel_info/eda_class_distribution.png b/urlmodel_info/eda_class_distribution.png new file mode 100644 index 0000000000000000000000000000000000000000..946e9a5ab905ca5476d51984dbc773b7b56bf3c9 Binary files /dev/null and b/urlmodel_info/eda_class_distribution.png differ diff --git a/urlmodel_info/eda_feature_distributions.png b/urlmodel_info/eda_feature_distributions.png new file mode 100644 index 0000000000000000000000000000000000000000..313589d5d531a44b808e1b98abb67d72bf2514e2 --- /dev/null +++ b/urlmodel_info/eda_feature_distributions.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04ba0927a3439c1849d2a8b96626061cf3896d1c2104a3f1f1cc887acf4c7b3a +size 107012 diff --git a/urlmodel_info/eda_url_length_by_class.png b/urlmodel_info/eda_url_length_by_class.png new file mode 100644 index 0000000000000000000000000000000000000000..37c219e49dfa274fce162a205b592c27267e5224 Binary files /dev/null and b/urlmodel_info/eda_url_length_by_class.png differ diff --git a/urlmodel_info/evaluation.py b/urlmodel_info/evaluation.py new file mode 100644 index 0000000000000000000000000000000000000000..ca4f9e76498e2bb39e3643481796f8e8e874a201 --- /dev/null +++ b/urlmodel_info/evaluation.py @@ -0,0 +1,226 @@ +""" +Evaluation utilities β€” metrics, comparison tables, and publication-quality plots. +""" + +from __future__ import annotations + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import seaborn as sns +from sklearn.metrics import ( + accuracy_score, + precision_score, + recall_score, + f1_score, + roc_auc_score, + confusion_matrix, + classification_report, +) + + +# ═════════════════════════════════════════════════════════════════════════════ +# Core evaluation +# ═════════════════════════════════════════════════════════════════════════════ + +def evaluate_model( + name: str, + y_true: np.ndarray, + y_pred: np.ndarray, + y_proba: np.ndarray | None = None, + class_names: list[str] | None = None, + task: str = "binary", +) -> dict: + """Compute comprehensive classification metrics. + + Parameters + ---------- + name : str + Model name. + y_true, y_pred : array-like + Ground truth and predicted labels. + y_proba : array-like, optional + Class probability matrix (n_samples Γ— n_classes). + class_names : list[str] + Human-readable class names. + task : str + ``"binary"`` or ``"multiclass"``. + + Returns + ------- + dict with keys: name, accuracy, precision, recall, f1_macro, auc_roc, + confusion_matrix, classification_report. + """ + y_true = np.asarray(y_true) + y_pred = np.asarray(y_pred) + + acc = accuracy_score(y_true, y_pred) + prec = precision_score(y_true, y_pred, average="macro", zero_division=0) + rec = recall_score(y_true, y_pred, average="macro", zero_division=0) + f1 = f1_score(y_true, y_pred, average="macro", zero_division=0) + + auc = None + if y_proba is not None: + y_proba = np.asarray(y_proba) + try: + if task == "binary" and y_proba.ndim == 2: + auc = roc_auc_score(y_true, y_proba[:, 1]) + else: + auc = roc_auc_score(y_true, y_proba, multi_class="ovr", average="macro") + except Exception: + auc = None + + cm = confusion_matrix(y_true, y_pred) + target_names = class_names or [str(c) for c in sorted(np.unique(y_true))] + cr = classification_report(y_true, y_pred, target_names=target_names, zero_division=0) + + return { + "name": name, + "accuracy": acc, + "precision": prec, + "recall": rec, + "f1_macro": f1, + "auc_roc": auc, + "confusion_matrix": cm, + "classification_report": cr, + } + + +def print_results_banner(result: dict) -> None: + """Pretty-print a model's evaluation results.""" + print(f"\n{'─' * 50}") + print(f" {result['name']}") + print(f"{'─' * 50}") + print(f" Accuracy : {result['accuracy']:.4f}") + print(f" Precision : {result['precision']:.4f}") + print(f" Recall : {result['recall']:.4f}") + print(f" F1 (macro): {result['f1_macro']:.4f}") + if result["auc_roc"] is not None: + print(f" AUC-ROC : {result['auc_roc']:.4f}") + print(f"{'─' * 50}") + + +# ═════════════════════════════════════════════════════════════════════════════ +# Literature comparison table +# ═════════════════════════════════════════════════════════════════════════════ + +_LITERATURE_BASELINES = [ + {"Method": "RF on URL features (Sahingoz 2019)", "Accuracy": 0.9798, + "F1 (macro)": 0.9793, "AUC-ROC": None, "Source": "Literature"}, + {"Method": "XGBoost (Rao & Pais 2019)", "Accuracy": 0.9685, + "F1 (macro)": None, "AUC-ROC": 0.993, "Source": "Literature"}, + {"Method": "URLNet CharCNN (Le 2018)", "Accuracy": 0.985, + "F1 (macro)": None, "AUC-ROC": 0.986, "Source": "Literature"}, + {"Method": "LSTM (Bahnsen 2018)", "Accuracy": 0.987, + "F1 (macro)": None, "AUC-ROC": None, "Source": "Literature"}, + {"Method": "Stacking CNN+LSTM+GRU (Nguyen 2021)", "Accuracy": 0.975, + "F1 (macro)": 0.972, "AUC-ROC": None, "Source": "Literature"}, + {"Method": "Hybrid DNN+LSTM (Ozcan 2021)", "Accuracy": 0.964, + "F1 (macro)": None, "AUC-ROC": 0.973, "Source": "Literature"}, + {"Method": "CharCNN (Aljofey 2022)", "Accuracy": 0.9675, + "F1 (macro)": 0.9671, "AUC-ROC": 0.991, "Source": "Literature"}, +] + + +def build_comparison_table( + our_results: list[dict], + task: str = "binary", +) -> pd.DataFrame: + """Build a comparison table of our results vs. literature baselines. + + Parameters + ---------- + our_results : list[dict] + Each dict is the output of ``evaluate_model()``. + task : str + ``"binary"`` or ``"multiclass"``. + + Returns + ------- + pd.DataFrame + """ + rows = list(_LITERATURE_BASELINES) + for r in our_results: + rows.append({ + "Method": r["name"], + "Accuracy": r["accuracy"], + "F1 (macro)": r["f1_macro"], + "AUC-ROC": r["auc_roc"], + "Source": "Ours", + }) + df = pd.DataFrame(rows) + df = df.sort_values("Accuracy", ascending=False).reset_index(drop=True) + return df + + +# ═════════════════════════════════════════════════════════════════════════════ +# Plotting helpers +# ═════════════════════════════════════════════════════════════════════════════ + +def plot_accuracy_bar( + comparison_df: pd.DataFrame, + save_path: str | None = None, +) -> plt.Figure: + """Horizontal bar chart of accuracies, colour-coded by source.""" + fig, ax = plt.subplots(figsize=(10, max(5, len(comparison_df) * 0.45))) + colors = ["#1976D2" if s == "Ours" else "#BDBDBD" + for s in comparison_df["Source"]] + y = range(len(comparison_df)) + ax.barh(y, comparison_df["Accuracy"], color=colors, edgecolor="white", height=0.6) + ax.set_yticks(y) + ax.set_yticklabels(comparison_df["Method"], fontsize=9) + ax.set_xlabel("Accuracy") + ax.set_title("Model Accuracy β€” Ours vs Literature") + ax.invert_yaxis() + ax.set_xlim(0.85, 1.01) + for i, v in enumerate(comparison_df["Accuracy"]): + if pd.notna(v): + ax.text(v + 0.002, i, f"{v:.4f}", va="center", fontsize=8) + plt.tight_layout() + if save_path: + fig.savefig(save_path, dpi=150, bbox_inches="tight") + return fig + + +def plot_confusion_matrix( + cm: np.ndarray, + class_names: list[str], + title: str = "Confusion Matrix", + save_path: str | None = None, +) -> plt.Figure: + """Plot an annotated confusion matrix heatmap.""" + fig, ax = plt.subplots(figsize=(6, 5)) + sns.heatmap( + cm, annot=True, fmt="d", cmap="Blues", + xticklabels=class_names, yticklabels=class_names, ax=ax, + ) + ax.set_xlabel("Predicted") + ax.set_ylabel("True") + ax.set_title(title) + plt.tight_layout() + if save_path: + fig.savefig(save_path, dpi=150, bbox_inches="tight") + return fig + + +def plot_feature_importance( + feature_names: list[str], + importances: np.ndarray, + top_n: int = 25, + title: str = "Feature Importance", + save_path: str | None = None, +) -> plt.Figure: + """Horizontal bar chart of top-N feature importances.""" + idx = np.argsort(importances)[-top_n:] + fig, ax = plt.subplots(figsize=(8, max(4, top_n * 0.3))) + ax.barh( + [feature_names[i] for i in idx], + importances[idx], + color="#1976D2", edgecolor="white", + ) + ax.set_xlabel("Importance") + ax.set_title(title) + plt.tight_layout() + if save_path: + fig.savefig(save_path, dpi=150, bbox_inches="tight") + return fig diff --git a/urlmodel_info/feature_engineering.py b/urlmodel_info/feature_engineering.py new file mode 100644 index 0000000000000000000000000000000000000000..3ca56de8a4c8f903e024bfce4d65922529c0dce3 --- /dev/null +++ b/urlmodel_info/feature_engineering.py @@ -0,0 +1,347 @@ +""" +URL Feature Engineering β€” 50+ lexical features for malicious URL detection. + +Features are grouped into 8 categories: + 1. Length / structural (7 features) + 2. Character counts (14 features) + 3. Character ratios (5 features) + 4. Entropy / randomness (2 features) + 5. Boolean indicators (10 features) + 6. Domain / TLD signals (6 features) + 7. Suspicious-pattern scores (5 features) + 8. Path & query analysis (5 features) +""" + +from __future__ import annotations + +import math +import re +from collections import Counter +from urllib.parse import urlparse, parse_qs + +import numpy as np +import pandas as pd +from joblib import Parallel, delayed + +try: + import tldextract +except ImportError: + tldextract = None + +# ── Regex patterns (compiled once) ──────────────────────────────────────────── +_IP_RE = re.compile( + r"(?:^|[/@])(\d{1,3}\.){3}\d{1,3}(?:[:/]|$)" +) +_HEX_RE = re.compile(r"%[0-9a-fA-F]{2}") +_SHORTENERS = frozenset([ + "bit.ly", "goo.gl", "tinyurl.com", "ow.ly", "t.co", "is.gd", + "buff.ly", "adf.ly", "tiny.cc", "lnkd.in", "rb.gy", "cutt.ly", + "shorturl.at", "rebrand.ly", +]) +_SUSPICIOUS_TLDS = frozenset([ + "tk", "ml", "ga", "cf", "gq", "xyz", "top", "pw", "cc", + "club", "work", "date", "racing", "stream", "download", + "win", "bid", "icu", "buzz", "monster", +]) +_SUSPICIOUS_EXT = re.compile( + r"\.(exe|zip|rar|scr|bat|cmd|js|vbs|ps1|dll|msi|apk|dmg|iso|php|cgi)(\?|$)", + re.IGNORECASE, +) +_PHISHING_KW = re.compile( + r"(login|signin|verify|account|update|secure|bank|confirm|password|" + r"credential|suspend|alert|notification|wallet|paypal|apple|microsoft|" + r"amazon|netflix|facebook|instagram|whatsapp|dropbox|google|icloud)", + re.IGNORECASE, +) +_BRAND_NAMES = [ + "google", "facebook", "apple", "amazon", "microsoft", "netflix", + "paypal", "instagram", "whatsapp", "dropbox", "linkedin", "twitter", + "yahoo", "ebay", "chase", "wellsfargo", "bankofamerica", "citibank", + "hsbc", "dhl", "fedex", "usps", +] + + +# ═════════════════════════════════════════════════════════════════════════════ +# Feature extraction for a single URL +# ═════════════════════════════════════════════════════════════════════════════ + +def _entropy(s: str) -> float: + """Shannon entropy of a string.""" + if not s: + return 0.0 + cnt = Counter(s) + length = len(s) + return -sum((c / length) * math.log2(c / length) for c in cnt.values()) + + +def _extract_one(url: str) -> dict: + """Extract all features from a single URL string (fully exception-safe).""" + try: + return _extract_one_inner(url) + except Exception: + # Return a row of zeros for truly broken URLs + return {name: 0 for name in URLFeatureExtractor._NAMES} + + +def _extract_one_inner(url: str) -> dict: + """Core logic β€” may raise on malformed URLs.""" + url = str(url).strip() + + try: + parsed = urlparse(url if "://" in url else f"http://{url}") + except Exception: + try: + safe = url.replace("[", "").replace("]", "") + parsed = urlparse(safe if "://" in safe else f"http://{safe}") + except Exception: + parsed = urlparse("http://invalid") + + try: + hostname = parsed.hostname or "" + except Exception: + hostname = "" + path = parsed.path or "" + query = parsed.query or "" + fragment = parsed.fragment or "" + scheme = (parsed.scheme or "").lower() + + # TLD extraction + if tldextract is not None: + ext = tldextract.extract(url) + domain = ext.domain + tld = ext.suffix + subdomain = ext.subdomain + else: + domain = hostname.split(".")[-2] if hostname.count(".") >= 1 else hostname + tld = hostname.split(".")[-1] if "." in hostname else "" + subdomain = ".".join(hostname.split(".")[:-2]) if hostname.count(".") >= 2 else "" + + url_lower = url.lower() + + # ── 1. Length / structural ──────────────────────────────────────────── + url_length = len(url) + hostname_length = len(hostname) + domain_length = len(domain) + path_length = len(path) + query_length = len(query) + fragment_length = len(fragment) + tld_length = len(tld) + + # ── 2. Character counts ────────────────────────────────────────────── + num_dots = url.count(".") + num_hyphens = url.count("-") + num_underscores = url.count("_") + num_slashes = url.count("/") + num_at_signs = url.count("@") + num_ampersands = url.count("&") + num_equals = url.count("=") + num_question_marks = url.count("?") + num_percent = url.count("%") + num_tilde = url.count("~") + num_digits = sum(c.isdigit() for c in url) + num_letters = sum(c.isalpha() for c in url) + num_special = sum(not c.isalnum() and c not in ":/." for c in url) + num_params = len(parse_qs(query)) + + # ── 3. Character ratios ────────────────────────────────────────────── + safe_len = max(url_length, 1) + digit_ratio = num_digits / safe_len + letter_ratio = num_letters / safe_len + special_ratio = num_special / safe_len + uppercase_ratio = sum(c.isupper() for c in url) / safe_len + digit_letter_ratio = num_digits / max(num_letters, 1) + + # ── 4. Entropy ─────────────────────────────────────────────────────── + url_entropy = _entropy(url) + domain_entropy = _entropy(hostname) + + # ── 5. Boolean indicators ──────────────────────────────────────────── + + has_ip = int(bool(_IP_RE.search(url))) + has_https = int(scheme == "https") + has_http = int(scheme == "http") + has_www = int("www." in url_lower) + try: + _port = parsed.port + except (ValueError, TypeError): + _port = None + has_port = int(_port is not None and _port not in (80, 443)) + has_at_symbol = int("@" in url) + is_shortened = int(any(s in url_lower for s in _SHORTENERS)) + has_double_slash_redirect = int("//" in path) + has_punycode = int("xn--" in url_lower) + has_hex_encoding = int(bool(_HEX_RE.search(url))) + + # ── 6. Domain / TLD signals ────────────────────────────────────────── + num_subdomains = subdomain.count(".") + 1 if subdomain else 0 + subdomain_length = len(subdomain) + domain_token_count = len(re.split(r"[.\-_]", hostname)) + has_suspicious_tld = int(tld.lower() in _SUSPICIOUS_TLDS) + domain_has_digits = int(any(c.isdigit() for c in domain)) + domain_hyphen_count = domain.count("-") + + # ── 7. Suspicious-pattern scores ───────────────────────────────────── + phishing_keyword_count = len(_PHISHING_KW.findall(url_lower)) + brand_count = sum(1 for b in _BRAND_NAMES if b in url_lower) + has_suspicious_ext = int(bool(_SUSPICIOUS_EXT.search(url_lower))) + # Brand in subdomain but not in registered domain β†’ likely phishing + brand_in_subdomain = int( + any(b in subdomain.lower() for b in _BRAND_NAMES) and + not any(b in domain.lower() for b in _BRAND_NAMES) + ) if subdomain else 0 + suspicious_word_ratio = phishing_keyword_count / max( + len(re.findall(r"[a-zA-Z]+", url)), 1 + ) + + # ── 8. Path & query analysis ───────────────────────────────────────── + path_tokens = [t for t in path.split("/") if t] + path_depth = len(path_tokens) + longest_path_token = max((len(t) for t in path_tokens), default=0) + avg_path_token_len = ( + sum(len(t) for t in path_tokens) / len(path_tokens) if path_tokens else 0.0 + ) + max_consecutive_digits = max( + (len(m.group()) for m in re.finditer(r"\d+", url)), default=0 + ) + path_entropy = _entropy(path) + + return { + # 1. Length + "url_length": url_length, + "hostname_length": hostname_length, + "domain_length": domain_length, + "path_length": path_length, + "query_length": query_length, + "fragment_length": fragment_length, + "tld_length": tld_length, + # 2. Counts + "num_dots": num_dots, + "num_hyphens": num_hyphens, + "num_underscores": num_underscores, + "num_slashes": num_slashes, + "num_at_signs": num_at_signs, + "num_ampersands": num_ampersands, + "num_equals": num_equals, + "num_question_marks": num_question_marks, + "num_percent": num_percent, + "num_tilde": num_tilde, + "num_digits": num_digits, + "num_letters": num_letters, + "num_special": num_special, + "num_params": num_params, + # 3. Ratios + "digit_ratio": digit_ratio, + "letter_ratio": letter_ratio, + "special_ratio": special_ratio, + "uppercase_ratio": uppercase_ratio, + "digit_letter_ratio": digit_letter_ratio, + # 4. Entropy + "url_entropy": url_entropy, + "domain_entropy": domain_entropy, + # 5. Booleans + "has_ip": has_ip, + "has_https": has_https, + "has_http": has_http, + "has_www": has_www, + "has_port": has_port, + "has_at_symbol": has_at_symbol, + "is_shortened": is_shortened, + "has_double_slash_redirect": has_double_slash_redirect, + "has_punycode": has_punycode, + "has_hex_encoding": has_hex_encoding, + # 6. Domain + "num_subdomains": num_subdomains, + "subdomain_length": subdomain_length, + "domain_token_count": domain_token_count, + "has_suspicious_tld": has_suspicious_tld, + "domain_has_digits": domain_has_digits, + "domain_hyphen_count": domain_hyphen_count, + # 7. Suspicious + "phishing_keyword_count": phishing_keyword_count, + "brand_count": brand_count, + "has_suspicious_ext": has_suspicious_ext, + "brand_in_subdomain": brand_in_subdomain, + "suspicious_word_ratio": suspicious_word_ratio, + # 8. Path / query + "path_depth": path_depth, + "longest_path_token": longest_path_token, + "avg_path_token_len": avg_path_token_len, + "max_consecutive_digits": max_consecutive_digits, + "path_entropy": path_entropy, + } + + +# ═════════════════════════════════════════════════════════════════════════════ +# Public API +# ═════════════════════════════════════════════════════════════════════════════ + +class URLFeatureExtractor: + """Parallel URL feature extractor producing a DataFrame of 54 features.""" + + _NAMES = list(_extract_one("http://example.com").keys()) + + def __init__(self, n_jobs: int = -1): + self.n_jobs = n_jobs + + @staticmethod + def feature_names() -> list[str]: + return list(URLFeatureExtractor._NAMES) + + def transform( + self, + urls: pd.Series | list | np.ndarray, + verbose: bool = True, + ) -> pd.DataFrame: + """Extract features for a sequence of URLs. + + Parameters + ---------- + urls : array-like of str + verbose : bool + Print progress info. + + Returns + ------- + pd.DataFrame with len(urls) rows Γ— 54 feature columns. + """ + urls = list(urls) + if verbose: + print(f" Extracting features for {len(urls):,} URLs (n_jobs={self.n_jobs}) …") + + rows = Parallel(n_jobs=self.n_jobs, backend="loky", batch_size=2048)( + delayed(_extract_one)(u) for u in urls + ) + df = pd.DataFrame(rows, columns=self._NAMES) + # Ensure float32 for memory efficiency + df = df.astype(np.float32) + if verbose: + print(f" β†’ {df.shape[0]:,} rows Γ— {df.shape[1]} features") + return df + + +def featurize_dataset(csv_path: str, url_col: str = "url", label_col: str = "type", + n_jobs: int = -1) -> pd.DataFrame: + """Load a CSV, extract features, and attach URLs + labels. + + Parameters + ---------- + csv_path : str + Path to CSV with at least `url_col` and `label_col` columns. + url_col : str + Column containing URL strings. + label_col : str + Column containing class labels. + n_jobs : int + Parallelism for feature extraction. + + Returns + ------- + pd.DataFrame with columns: url, label, <54 features> + """ + df_raw = pd.read_csv(csv_path) + extractor = URLFeatureExtractor(n_jobs=n_jobs) + feat_df = extractor.transform(df_raw[url_col], verbose=True) + + feat_df.insert(0, "url", df_raw[url_col].values) + feat_df["label"] = df_raw[label_col].values + return feat_df diff --git a/urlmodel_info/feature_importance_xgb.png b/urlmodel_info/feature_importance_xgb.png new file mode 100644 index 0000000000000000000000000000000000000000..b635127e40b15a9664072902343321464f872c4f --- /dev/null +++ b/urlmodel_info/feature_importance_xgb.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c3eb5a62254c10922af4e40074b6e9952b9436522422c5b07dd3a6a725699b95 +size 111810 diff --git a/urlmodel_info/hypermodel_meta.joblib b/urlmodel_info/hypermodel_meta.joblib new file mode 100644 index 0000000000000000000000000000000000000000..ae2e3a586e29cc59eecbe527f0a1f0059b7ad521 --- /dev/null +++ b/urlmodel_info/hypermodel_meta.joblib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12c087bcc546be3c0cbf8ca3c35674bc157674ef1e197d3514fda9ab3e42a96c +size 275258 diff --git a/urlmodel_info/hypertuning.py b/urlmodel_info/hypertuning.py new file mode 100644 index 0000000000000000000000000000000000000000..8d22216ceb049f6a4564f689eb46743ff140f2d1 --- /dev/null +++ b/urlmodel_info/hypertuning.py @@ -0,0 +1,147 @@ +""" +Optuna hyperparameter tuning for XGBoost (GPU) and LightGBM (CPU). +""" + +from __future__ import annotations + +import numpy as np +import optuna +import torch +from sklearn.model_selection import StratifiedKFold, cross_val_score + +optuna.logging.set_verbosity(optuna.logging.WARNING) + +# GPU device detection (done once at import) +_XGB_DEVICE = "cuda" if torch.cuda.is_available() else "cpu" + + +# ═════════════════════════════════════════════════════════════════════════════ +# XGBoost tuning (GPU) +# ═════════════════════════════════════════════════════════════════════════════ + +def tune_xgb( + X: np.ndarray, + y: np.ndarray, + num_classes: int = 2, + n_trials: int = 50, + timeout: int = 300, + cv: int = 3, +) -> dict: + """Run Optuna search for XGBoost hyperparameters. + + Parameters + ---------- + X : np.ndarray + Feature matrix (float32). + y : np.ndarray + Labels. + num_classes : int + 2 for binary, >2 for multi-class. + n_trials : int + Max Optuna trials. + timeout : int + Time limit in seconds. + cv : int + Cross-validation folds. + + Returns + ------- + dict + Best hyperparameters. + """ + import xgboost as xgb + + objective = "binary:logistic" if num_classes == 2 else "multi:softprob" + + def _objective(trial): + params = { + "n_estimators": trial.suggest_int("n_estimators", 100, 800), + "max_depth": trial.suggest_int("max_depth", 3, 10), + "learning_rate": trial.suggest_float("learning_rate", 0.01, 0.3, log=True), + "subsample": trial.suggest_float("subsample", 0.6, 1.0), + "colsample_bytree": trial.suggest_float("colsample_bytree", 0.5, 1.0), + "min_child_weight": trial.suggest_int("min_child_weight", 1, 10), + "reg_alpha": trial.suggest_float("reg_alpha", 1e-5, 10.0, log=True), + "reg_lambda": trial.suggest_float("reg_lambda", 1e-5, 10.0, log=True), + "gamma": trial.suggest_float("gamma", 0.0, 5.0), + } + clf = xgb.XGBClassifier( + **params, + objective=objective, + tree_method="hist", + device=_XGB_DEVICE, + eval_metric="logloss" if num_classes == 2 else "mlogloss", + n_jobs=-1, + random_state=42, + verbosity=0, + ) + skf = StratifiedKFold(n_splits=cv, shuffle=True, random_state=42) + scores = cross_val_score(clf, X, y, cv=skf, scoring="accuracy", n_jobs=1) + return scores.mean() + + study = optuna.create_study(direction="maximize") + study.optimize(_objective, n_trials=n_trials, timeout=timeout, show_progress_bar=True) + + print(f" Best XGBoost accuracy: {study.best_value:.4f}") + print(f" Best params: {study.best_params}") + return study.best_params + + +# ═════════════════════════════════════════════════════════════════════════════ +# LightGBM tuning (CPU) +# ═════════════════════════════════════════════════════════════════════════════ + +def tune_lgbm( + X: np.ndarray, + y: np.ndarray, + num_classes: int = 2, + n_trials: int = 50, + timeout: int = 300, + cv: int = 3, +) -> dict: + """Run Optuna search for LightGBM hyperparameters. + + Parameters + ---------- + X, y, num_classes, n_trials, timeout, cv : same as ``tune_xgb``. + + Returns + ------- + dict + Best hyperparameters. + """ + import lightgbm as lgb + + objective = "binary" if num_classes == 2 else "multiclass" + + def _objective(trial): + params = { + "n_estimators": trial.suggest_int("n_estimators", 100, 800), + "max_depth": trial.suggest_int("max_depth", 3, 12), + "learning_rate": trial.suggest_float("learning_rate", 0.01, 0.3, log=True), + "num_leaves": trial.suggest_int("num_leaves", 20, 150), + "subsample": trial.suggest_float("subsample", 0.6, 1.0), + "colsample_bytree": trial.suggest_float("colsample_bytree", 0.5, 1.0), + "min_child_samples": trial.suggest_int("min_child_samples", 5, 50), + "reg_alpha": trial.suggest_float("reg_alpha", 1e-5, 10.0, log=True), + "reg_lambda": trial.suggest_float("reg_lambda", 1e-5, 10.0, log=True), + } + clf = lgb.LGBMClassifier( + **params, + objective=objective, + class_weight="balanced", + device_type="cpu", + n_jobs=-1, + random_state=42, + verbose=-1, + ) + skf = StratifiedKFold(n_splits=cv, shuffle=True, random_state=42) + scores = cross_val_score(clf, X, y, cv=skf, scoring="accuracy", n_jobs=1) + return scores.mean() + + study = optuna.create_study(direction="maximize") + study.optimize(_objective, n_trials=n_trials, timeout=timeout, show_progress_bar=True) + + print(f" Best LightGBM accuracy: {study.best_value:.4f}") + print(f" Best params: {study.best_params}") + return study.best_params diff --git a/urlmodel_info/lgbm_binary.joblib b/urlmodel_info/lgbm_binary.joblib new file mode 100644 index 0000000000000000000000000000000000000000..80788b2d29a764990cb17e68c7d88d40ec62a10a --- /dev/null +++ b/urlmodel_info/lgbm_binary.joblib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce344f6a15c6c9dd92b11b44b65c6636d81d19c73a0ce355cd3bf9f20a1e1a2f +size 3505476 diff --git a/urlmodel_info/main_notebook.ipynb b/urlmodel_info/main_notebook.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..db97fdece355d65a565b65e456c297f80b405b03 --- /dev/null +++ b/urlmodel_info/main_notebook.ipynb @@ -0,0 +1,1033 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# πŸ›‘οΈ Malicious URL HyperModel\n", + "\n", + "**Dataset:** [Malicious URLs](https://www.kaggle.com/datasets/sid321axn/malicious-urls-dataset) β€” 651K URLs Β· 4 classes (benign / phishing / defacement / malware)\n", + "\n", + "**Objective:** Build a GPU-accelerated stacking HyperModel that outperforms literature baselines:\n", + "\n", + "| Baseline | Accuracy | Source |\n", + "|---|---|---|\n", + "| RF on URL features | 97.98% | Sahingoz 2019 |\n", + "| URLNet (Char+Word CNN) | ~98.5% | Le 2018 |\n", + "| Stacking CNN+LSTM+GRU | 97.5% | Nguyen 2021 |\n", + "| CharCNN | 96.75% | Aljofey 2022 |\n", + "\n", + "**Architecture:**\n", + "```\n", + "Raw URLs (651K)\n", + " β”œβ”€β”€ Feature Engineering (54 lexical features)\n", + " β”‚ β”œβ”€β”€ XGBoost (GPU)\n", + " β”‚ └── LightGBM (CPU)\n", + " β”œβ”€β”€ TF-IDF char n-grams β†’ Logistic Regression\n", + " └── Character-level Deep Learning (GPU)\n", + " β”œβ”€β”€ CharCNN\n", + " β”œβ”€β”€ CharBiLSTM\n", + " └── CNN-BiLSTM Hybrid\n", + " β”‚\n", + " β–Ό\n", + "Stacking Meta-Learner (XGBoost GPU) β†’ Final Prediction\n", + "```\n", + "\n", + "See [LITERATURE_REVIEW.md](LITERATURE_REVIEW.md) for a full survey of 15+ research papers." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 0. Install & Setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Install Dependencies ─────────────────────────────────────────────────────────────\n", + "import subprocess, sys\n", + "\n", + "def pip_install(pkg):\n", + " subprocess.check_call([sys.executable, '-m', 'pip', 'install', pkg, '-q'])\n", + "\n", + "for pkg in [\n", + " 'xgboost>=2.0', 'lightgbm>=4.0',\n", + " 'optuna', 'kagglehub',\n", + " 'tldextract', 'imbalanced-learn',\n", + " 'seaborn', 'plotly', 'pyarrow',\n", + "]:\n", + " try:\n", + " pip_install(pkg)\n", + " except Exception as e:\n", + " print(f'Warning: {pkg}: {e}')\n", + "\n", + "# Verify PyTorch CUDA\n", + "import torch\n", + "print(f'PyTorch {torch.__version__} | CUDA available: {torch.cuda.is_available()}')\n", + "if torch.cuda.is_available():\n", + " print(f' GPU: {torch.cuda.get_device_name(0)}')\n", + " print(f' GPUs: {torch.cuda.device_count()}')\n", + "print('\\n\\u2705 Packages ready')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys, os, pathlib, warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "PROJECT_ROOT = pathlib.Path('.').resolve()\n", + "sys.path.insert(0, str(PROJECT_ROOT))\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "sns.set_theme(style='whitegrid', palette='muted')\n", + "pd.set_option('display.max_columns', 30)\n", + "pd.set_option('display.float_format', '{:.4f}'.format)\n", + "\n", + "SEED = 42\n", + "np.random.seed(SEED)\n", + "\n", + "DATA_DIR = PROJECT_ROOT / 'data'\n", + "OUTPUT_DIR = PROJECT_ROOT / 'outputs'\n", + "DATA_DIR.mkdir(parents=True, exist_ok=True)\n", + "OUTPUT_DIR.mkdir(parents=True, exist_ok=True)\n", + "\n", + "print(f'Project root : {PROJECT_ROOT}')\n", + "print(f'Data dir : {DATA_DIR}')\n", + "print(f'Output dir : {OUTPUT_DIR}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Download Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from download_data import download_malicious_urls\n", + "\n", + "csv_path = download_malicious_urls(DATA_DIR)\n", + "print(f'\\nDataset path: {csv_path}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Exploratory Data Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_raw = pd.read_csv(csv_path)\n", + "\n", + "print(f'Shape : {df_raw.shape}')\n", + "print(f'Columns : {list(df_raw.columns)}')\n", + "print(f'\\nClass distribution:')\n", + "print(df_raw['type'].value_counts())\n", + "df_raw.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Class distribution plot ─────────────────────────────────────────────────\n", + "fig, axes = plt.subplots(1, 2, figsize=(14, 4))\n", + "\n", + "# 4-class\n", + "vc = df_raw['type'].value_counts()\n", + "colors4 = ['#4CAF50', '#F44336', '#FF9800', '#9C27B0']\n", + "axes[0].bar(vc.index.astype(str), vc.values, color=colors4)\n", + "axes[0].set_title('4-Class Distribution')\n", + "axes[0].set_ylabel('Count')\n", + "for i, v in enumerate(vc.values):\n", + " axes[0].text(i, v + vc.max()*0.01, f'{v:,}', ha='center', fontsize=9)\n", + "\n", + "# Binary (benign vs malicious)\n", + "binary_counts = pd.Series({\n", + " 'benign': (df_raw['type'] == 'benign').sum(),\n", + " 'malicious': (df_raw['type'] != 'benign').sum(),\n", + "})\n", + "axes[1].bar(binary_counts.index, binary_counts.values, color=['#4CAF50', '#F44336'])\n", + "axes[1].set_title('Binary Distribution (benign vs malicious)')\n", + "axes[1].set_ylabel('Count')\n", + "for i, v in enumerate(binary_counts.values):\n", + " axes[1].text(i, v + binary_counts.max()*0.01, f'{v:,}', ha='center', fontsize=9)\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'eda_class_distribution.png', dpi=150)\n", + "plt.show()\n", + "\n", + "print(f'4-class imbalance ratio: {vc.min()/vc.max():.2%}')\n", + "print(f'Binary imbalance ratio: {binary_counts.min()/binary_counts.max():.2%}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── URL length distribution by class ───────────────────────────────────────\n", + "df_raw['url_len'] = df_raw['url'].astype(str).str.len()\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 4))\n", + "for cls, color in zip(['benign','phishing','defacement','malware'], colors4):\n", + " data = df_raw.loc[df_raw['type']==cls, 'url_len'].clip(0, 500)\n", + " ax.hist(data, bins=60, alpha=0.5, color=color, label=cls, density=True)\n", + "ax.set_xlabel('URL Length (chars)')\n", + "ax.set_title('URL Length Distribution by Class')\n", + "ax.legend()\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'eda_url_length_by_class.png', dpi=150)\n", + "plt.show()\n", + "\n", + "print(df_raw.groupby('type')['url_len'].describe()[['mean','50%','max']].round(1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Feature Engineering\n", + "\n", + "We extract **54 hand-crafted features** across 8 categories:\n", + "- Length & structural (7)\n", + "- Character counts (14)\n", + "- Character ratios (5)\n", + "- Entropy / randomness (2)\n", + "- Boolean indicators (10)\n", + "- Domain / TLD signals (6)\n", + "- Suspicious patterns (5)\n", + "- Path & query analysis (5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from feature_engineering import URLFeatureExtractor, featurize_dataset\n", + "\n", + "print('Extracting features from 651K URLs …')\n", + "df = featurize_dataset(str(csv_path), url_col='url', label_col='type')\n", + "print(f'\\n\\u2705 {df.shape[0]:,} rows \\u00d7 {df.shape[1]} cols')\n", + "df.head(3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "feat_names = URLFeatureExtractor.feature_names()\n", + "print(f'Total features: {len(feat_names)}')\n", + "print(feat_names)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Top features correlated with malicious label (binary) ──────────────\n", + "df['is_malicious'] = (df['label'] != 'benign').astype(int)\n", + "\n", + "feat_corr = df[feat_names].corrwith(df['is_malicious']).abs().sort_values(ascending=False)\n", + "print('Top 15 features correlated with maliciousness:')\n", + "print(feat_corr.head(15).to_string())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Feature distributions: benign vs malicious ─────────────────────────\n", + "top_feats = feat_corr.head(8).index.tolist()\n", + "fig, axes = plt.subplots(2, 4, figsize=(16, 7))\n", + "axes = axes.flatten()\n", + "\n", + "for ax, feat in zip(axes, top_feats):\n", + " for lbl, color, name in [(0, '#4CAF50', 'Benign'), (1, '#F44336', 'Malicious')]:\n", + " data = df.loc[df['is_malicious']==lbl, feat].clip(\n", + " df[feat].quantile(0.01), df[feat].quantile(0.99)\n", + " )\n", + " ax.hist(data, bins=40, alpha=0.6, color=color, label=name, density=True)\n", + " ax.set_title(feat, fontsize=9)\n", + " ax.legend(fontsize=7)\n", + "\n", + "plt.suptitle('Feature Distributions: Benign vs Malicious', y=1.02)\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'eda_feature_distributions.png', dpi=150, bbox_inches='tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Data Preparation\n", + "\n", + "We prepare two tasks:\n", + "- **Binary**: benign (0) vs malicious (1)\n", + "- **Multi-class**: benign (0) / phishing (1) / defacement (2) / malware (3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.model_selection import train_test_split\n", + "from sklearn.preprocessing import StandardScaler, LabelEncoder\n", + "\n", + "# ─── Encode labels ─────────────────────────────────────────────────────\n", + "label_map_4 = {'benign': 0, 'phishing': 1, 'defacement': 2, 'malware': 3}\n", + "df['label_4'] = df['label'].map(label_map_4)\n", + "df['label_2'] = (df['label'] != 'benign').astype(int) # binary\n", + "\n", + "CLASS_NAMES_4 = ['benign', 'phishing', 'defacement', 'malware']\n", + "CLASS_NAMES_2 = ['Benign', 'Malicious']\n", + "\n", + "X = df[feat_names].values.astype(np.float32)\n", + "y_4 = df['label_4'].values\n", + "y_2 = df['label_2'].values\n", + "urls = df['url'].values\n", + "\n", + "# ─── Binary split ──────────────────────────────────────────────────────\n", + "X_train, X_test, y2_train, y2_test, y4_train, y4_test, u_train, u_test = \\\n", + " train_test_split(X, y_2, y_4, urls, test_size=0.20, stratify=y_4, random_state=SEED)\n", + "\n", + "print(f'Train: {len(y2_train):,} | Test: {len(y2_test):,}')\n", + "print(f'Binary train dist : {dict(zip(*np.unique(y2_train, return_counts=True)))}')\n", + "print(f'4-class train dist : {dict(zip(*np.unique(y4_train, return_counts=True)))}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Feature scaling ───────────────────────────────────────────────────────\n", + "scaler = StandardScaler()\n", + "X_train_sc = scaler.fit_transform(X_train).astype(np.float32)\n", + "X_test_sc = scaler.transform(X_test).astype(np.float32)\n", + "\n", + "print(f'\\u2705 Scaled (dtype={X_train_sc.dtype}, shape={X_train_sc.shape})')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Classical ML Models (GPU where possible)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from models import build_xgb, build_lgbm\n", + "from evaluation import evaluate_model, print_results_banner\n", + "\n", + "all_results_bin = [] # binary results\n", + "all_results_mc = [] # 4-class results\n", + "\n", + "# ─── Binary Classification ──────────────────────────────────────────────\n", + "print('\\n' + '='*55)\n", + "print(' BINARY: Benign vs Malicious')\n", + "print('='*55)\n", + "\n", + "clf_models_bin = {\n", + " 'XGBoost (GPU)': build_xgb(num_classes=2),\n", + " 'LightGBM (CPU)': build_lgbm(num_classes=2),\n", + "}\n", + "\n", + "for name, model in clf_models_bin.items():\n", + " print(f'\\nTraining {name} …')\n", + " model.fit(X_train_sc, y2_train)\n", + " preds = model.predict(X_test_sc)\n", + " proba = model.predict_proba(X_test_sc)\n", + " result = evaluate_model(name, y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + " all_results_bin.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── 4-Class Classification ─────────────────────────────────────────────\n", + "print('\\n' + '='*55)\n", + "print(' MULTI-CLASS: benign / phishing / defacement / malware')\n", + "print('='*55)\n", + "\n", + "clf_models_mc = {\n", + " 'XGBoost (GPU, 4c)': build_xgb(num_classes=4),\n", + " 'LightGBM (CPU, 4c)': build_lgbm(num_classes=4),\n", + "}\n", + "\n", + "for name, model in clf_models_mc.items():\n", + " print(f'\\nTraining {name} …')\n", + " model.fit(X_train_sc, y4_train)\n", + " preds = model.predict(X_test_sc)\n", + " proba = model.predict_proba(X_test_sc)\n", + " result = evaluate_model(name, y4_test, preds, proba,\n", + " class_names=CLASS_NAMES_4, task='multiclass')\n", + " all_results_mc.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. TF-IDF String Model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from models import build_tfidf_lr_pipeline\n", + "\n", + "# Binary\n", + "print('Training TF-IDF + LR (binary) …')\n", + "tfidf_bin = build_tfidf_lr_pipeline(num_classes=2)\n", + "tfidf_bin.fit(u_train, y2_train)\n", + "preds = tfidf_bin.predict(u_test)\n", + "proba = tfidf_bin.predict_proba(u_test)\n", + "result = evaluate_model('TF-IDF + LR', y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + "all_results_bin.append(result)\n", + "print_results_banner(result)\n", + "\n", + "# 4-class\n", + "print('\\nTraining TF-IDF + LR (4-class) …')\n", + "tfidf_mc = build_tfidf_lr_pipeline(num_classes=4)\n", + "tfidf_mc.fit(u_train, y4_train)\n", + "preds = tfidf_mc.predict(u_test)\n", + "proba = tfidf_mc.predict_proba(u_test)\n", + "result = evaluate_model('TF-IDF + LR (4c)', y4_test, preds, proba,\n", + " class_names=CLASS_NAMES_4, task='multiclass')\n", + "all_results_mc.append(result)\n", + "print_results_banner(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Deep Learning Models (CharCNN Β· BiLSTM Β· Hybrid) β€” GPU" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from models import DeepURLClassifier\n", + "\n", + "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", + "print(f'DL device: {device}')\n", + "\n", + "dl_configs = [\n", + " dict(name='CharCNN', arch='cnn', epochs=20, batch_size=2048, lr=1e-3),\n", + " dict(name='CharBiLSTM', arch='bilstm', epochs=15, batch_size=2048, lr=5e-4),\n", + " dict(name='CNN-BiLSTM', arch='cnn_bilstm',epochs=15, batch_size=2048, lr=7e-4),\n", + "]\n", + "\n", + "# ─── Binary ───────────────────────────────────────────────────────────────\n", + "print('\\n\\u2500\\u2500 Binary: Deep Learning Models \\u2500\\u2500')\n", + "for cfg in dl_configs:\n", + " print(f\"\\nTraining {cfg['name']} (binary) …\")\n", + " model = DeepURLClassifier(\n", + " arch=cfg['arch'], num_classes=2,\n", + " epochs=cfg['epochs'], batch_size=cfg['batch_size'],\n", + " lr=cfg['lr'], device='auto',\n", + " )\n", + " model.fit(list(u_train), y2_train, class_weight='balanced')\n", + " preds = model.predict(list(u_test))\n", + " proba = model.predict_proba(list(u_test))\n", + " result = evaluate_model(cfg['name'], y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + " all_results_bin.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── 4-Class ──────────────────────────────────────────────────────────────\n", + "print('\\n\\u2500\\u2500 4-Class: Deep Learning Models \\u2500\\u2500')\n", + "for cfg in dl_configs:\n", + " print(f\"\\nTraining {cfg['name']} (4-class) …\")\n", + " model = DeepURLClassifier(\n", + " arch=cfg['arch'], num_classes=4,\n", + " epochs=cfg['epochs'], batch_size=cfg['batch_size'],\n", + " lr=cfg['lr'], device='auto',\n", + " )\n", + " model.fit(list(u_train), y4_train, class_weight='balanced')\n", + " preds = model.predict(list(u_test))\n", + " proba = model.predict_proba(list(u_test))\n", + " result = evaluate_model(cfg['name']+' (4c)', y4_test, preds, proba,\n", + " class_names=CLASS_NAMES_4, task='multiclass')\n", + " all_results_mc.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Optuna Hyperparameter Tuning" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from hypertuning import tune_xgb, tune_lgbm\n", + "\n", + "print('Tuning XGBoost (GPU, binary) …')\n", + "best_xgb_params = tune_xgb(\n", + " X_train_sc, y2_train,\n", + " num_classes=2, n_trials=60, timeout=300,\n", + ")\n", + "\n", + "print('\\nTuning LightGBM (CPU, binary) …')\n", + "best_lgbm_params = tune_lgbm(\n", + " X_train_sc, y2_train,\n", + " num_classes=2, n_trials=60, timeout=300,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import xgboost as xgb_lib\n", + "import lightgbm as lgb_lib\n", + "\n", + "# ── Tuned XGBoost (GPU) ─────────────────────────────────────────────────\n", + "_xgb_dev = 'cuda' if torch.cuda.is_available() else 'cpu'\n", + "\n", + "tuned_xgb = xgb_lib.XGBClassifier(\n", + " **best_xgb_params,\n", + " objective='binary:logistic', tree_method='hist',\n", + " device=_xgb_dev, eval_metric='logloss',\n", + " n_jobs=-1, random_state=42,\n", + ")\n", + "tuned_xgb.fit(X_train_sc, y2_train)\n", + "preds = tuned_xgb.predict(X_test_sc)\n", + "proba = tuned_xgb.predict_proba(X_test_sc)\n", + "result = evaluate_model('XGBoost (Optuna-tuned)', y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + "all_results_bin.append(result)\n", + "print_results_banner(result)\n", + "\n", + "# ── Tuned LightGBM (CPU) ────────────────────────────────────────────────\n", + "tuned_lgbm = lgb_lib.LGBMClassifier(\n", + " **best_lgbm_params,\n", + " objective='binary', class_weight='balanced',\n", + " device_type='cpu', n_jobs=-1, random_state=42, verbose=-1,\n", + ")\n", + "tuned_lgbm.fit(X_train_sc, y2_train)\n", + "preds = tuned_lgbm.predict(X_test_sc)\n", + "proba = tuned_lgbm.predict_proba(X_test_sc)\n", + "result = evaluate_model('LightGBM (Optuna-tuned)', y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + "all_results_bin.append(result)\n", + "print_results_banner(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. HyperModel β€” Stacking Ensemble\n", + "\n", + "Combines feature-based models (XGBoost GPU, LightGBM CPU) and character-level DL\n", + "(CharCNN, BiLSTM) via out-of-fold (OOF) stacking with an XGBoost GPU meta-learner." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from models import build_stacking_hypermodel, ManualStackingEnsemble\n", + "\n", + "# ── Binary HyperModel ───────────────────────────────────────────────────\n", + "arch = build_stacking_hypermodel(num_classes=2, use_deep=True, cv=5)\n", + "\n", + "hypermodel = ManualStackingEnsemble(\n", + " level0 = arch['level0'],\n", + " meta = arch['meta'],\n", + " cv = 5,\n", + " num_classes = 2,\n", + ")\n", + "\n", + "print('Training HyperModel (binary) …')\n", + "hypermodel.fit(\n", + " X_feat = X_train_sc,\n", + " X_url = u_train,\n", + " y = y2_train,\n", + ")\n", + "print('\\n\\u2705 HyperModel trained')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "hyper_preds = hypermodel.predict(X_test_sc, u_test)\n", + "hyper_proba = hypermodel.predict_proba(X_test_sc, u_test)\n", + "\n", + "result_hyper = evaluate_model(\n", + " 'HyperModel (Stacking Ensemble)',\n", + " y2_test, hyper_preds, hyper_proba,\n", + " class_names=CLASS_NAMES_2, task='binary',\n", + ")\n", + "all_results_bin.append(result_hyper)\n", + "print_results_banner(result_hyper)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 10. Results Comparison vs Literature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from evaluation import build_comparison_table, plot_accuracy_bar\n", + "\n", + "print('\\n\\ud83d\\udcca Binary Classification \\u2014 Final Comparison')\n", + "comparison_bin = build_comparison_table(all_results_bin, task='binary')\n", + "print(comparison_bin[['Method','Accuracy','F1 (macro)','AUC-ROC','Source']].to_string(index=False))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('\\n\\ud83d\\udcca 4-Class Classification \\u2014 Final Comparison')\n", + "comparison_mc = build_comparison_table(all_results_mc, task='multiclass')\n", + "print(comparison_mc[['Method','Accuracy','F1 (macro)','AUC-ROC','Source']].to_string(index=False))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Accuracy bar chart ───────────────────────────────────────────────────\n", + "fig_bar = plot_accuracy_bar(\n", + " comparison_bin,\n", + " save_path=str(OUTPUT_DIR / 'results_accuracy_bar.png'),\n", + ")\n", + "plt.show()\n", + "\n", + "# ─── ROC curves (binary) ─────────────────────────────────────────────────\n", + "from sklearn.metrics import roc_curve, auc\n", + "\n", + "fig_roc, ax_roc = plt.subplots(figsize=(9, 7))\n", + "ax_roc.plot([0,1],[0,1], 'k--', lw=1, label='Random')\n", + "\n", + "roc_models = {\n", + " 'XGBoost (GPU)': ('feat', clf_models_bin['XGBoost (GPU)']),\n", + " 'LightGBM (CPU)': ('feat', clf_models_bin['LightGBM (CPU)']),\n", + " 'TF-IDF + LR': ('url', tfidf_bin),\n", + " 'XGBoost (tuned)': ('feat', tuned_xgb),\n", + " 'LightGBM (tuned)': ('feat', tuned_lgbm),\n", + "}\n", + "\n", + "for name, (src, mdl) in roc_models.items():\n", + " try:\n", + " X_in = u_test if src == 'url' else X_test_sc\n", + " prob = mdl.predict_proba(X_in)[:, 1]\n", + " fpr, tpr, _ = roc_curve(y2_test, prob)\n", + " roc_auc = auc(fpr, tpr)\n", + " ax_roc.plot(fpr, tpr, lw=1.5, label=f'{name} (AUC={roc_auc:.3f})')\n", + " except Exception as e:\n", + " print(f' Skip {name}: {e}')\n", + "\n", + "# HyperModel\n", + "try:\n", + " fpr, tpr, _ = roc_curve(y2_test, hyper_proba[:, 1])\n", + " roc_auc = auc(fpr, tpr)\n", + " ax_roc.plot(fpr, tpr, lw=2.5, color='crimson', linestyle='--',\n", + " label=f'HyperModel (AUC={roc_auc:.3f})')\n", + "except Exception as e:\n", + " print(f' HyperModel ROC skip: {e}')\n", + "\n", + "ax_roc.set_xlabel('False Positive Rate')\n", + "ax_roc.set_ylabel('True Positive Rate')\n", + "ax_roc.set_title('ROC Curves \\u2014 Binary Classification (Benign vs Malicious)')\n", + "ax_roc.legend(loc='lower right', fontsize=8)\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'results_roc_curves.png', dpi=150)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Confusion matrix for HyperModel ──────────────────────────────────────\n", + "from evaluation import plot_confusion_matrix\n", + "\n", + "fig_cm = plot_confusion_matrix(\n", + " result_hyper['confusion_matrix'],\n", + " class_names=CLASS_NAMES_2,\n", + " title='HyperModel Confusion Matrix (Binary)',\n", + " save_path=str(OUTPUT_DIR / 'results_confusion_matrix_hypermodel.png'),\n", + ")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 11. Feature Importance Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from evaluation import plot_feature_importance\n", + "\n", + "xgb_model = clf_models_bin['XGBoost (GPU)']\n", + "importances = xgb_model.feature_importances_\n", + "\n", + "fig_fi = plot_feature_importance(\n", + " feat_names, importances, top_n=25,\n", + " title='XGBoost Feature Importance (Binary)',\n", + " save_path=str(OUTPUT_DIR / 'feature_importance_xgb.png'),\n", + ")\n", + "plt.show()\n", + "\n", + "feat_imp_df = pd.DataFrame({'feature': feat_names, 'importance': importances})\n", + "print(feat_imp_df.sort_values('importance', ascending=False).head(15).to_string(index=False))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 12. Case Study β€” Adversarial URL Analysis\n", + "\n", + "Testing the HyperModel on hand-crafted adversarial examples: typosquatting,\n", + "brand impersonation, IP-based phishing, and obfuscated URLs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "CASE_STUDY_URLS = [\n", + " # Clearly benign\n", + " ('https://www.google.com', 0, 'Legitimate Google'),\n", + " ('https://www.amazon.com/dp/B08L5TNJHG', 0, 'Legitimate Amazon'),\n", + " ('https://github.com/openai/gpt-4', 0, 'Legitimate GitHub'),\n", + " ('https://en.wikipedia.org/wiki/Machine_learning', 0, 'Legitimate Wikipedia'),\n", + " # Typosquatting\n", + " ('http://googlΠ΅.com.login-verify.xyz/account', 1, 'Typosquatting Google'),\n", + " ('http://amaz0n-security-alert.com/verify', 1, 'Typosquatting Amazon'),\n", + " ('http://paypa1.com-secure.update-account.ru/login', 1, 'Typosquatting PayPal'),\n", + " # Brand in subdomain\n", + " ('http://apple-id.apple.com-signin.net/verify', 1, 'Brand subdomain phishing'),\n", + " ('http://microsoft.com.update-account.xyz/login.php', 1, 'Brand path phishing'),\n", + " # IP-based\n", + " ('http://192.168.1.234/paypal/login', 1, 'IP-based phishing'),\n", + " ('http://45.77.123.45/amazon-account/verify.html', 1, 'IP-based phishing 2'),\n", + " # Obfuscated\n", + " ('http://xn--pypal-4ve.com/account-login', 1, 'Punycode phishing'),\n", + " ('http://bit.ly/3xK7pQr', 1, 'URL shortener (suspicious)'),\n", + " ('http://secure-update%2Ebank%2Ecom.evil.tk/login', 1, 'Hex-encoded phishing'),\n", + " # Long suspicious\n", + " ('http://login-account-update-security-bank-verify.info/account/login/confirm/id=12345&token=abc',\n", + " 1, 'Long suspicious URL'),\n", + " # Legit with suspicious paths\n", + " ('https://security.microsoft.com/informationprotection/label', 0, 'Legit MS Security'),\n", + " ('https://accounts.google.com/o/oauth2/auth?client_id=abc123', 0, 'Legit Google OAuth'),\n", + "]\n", + "\n", + "case_urls = [u for u, _, _ in CASE_STUDY_URLS]\n", + "case_labels = [l for _, l, _ in CASE_STUDY_URLS]\n", + "case_descs = [d for _, _, d in CASE_STUDY_URLS]\n", + "\n", + "extractor = URLFeatureExtractor()\n", + "case_feat = extractor.transform(pd.Series(case_urls), verbose=False)\n", + "case_feat = case_feat[feat_names]\n", + "X_case = scaler.transform(case_feat.values.astype(np.float32)).astype(np.float32)\n", + "u_case = np.array(case_urls)\n", + "\n", + "pred_xgb = clf_models_bin['XGBoost (GPU)'].predict_proba(X_case)[:, 1]\n", + "pred_lgb = clf_models_bin['LightGBM (CPU)'].predict_proba(X_case)[:, 1]\n", + "pred_tfidf = tfidf_bin.predict_proba(u_case)[:, 1]\n", + "pred_hyper = hypermodel.predict_proba(X_case, u_case)[:, 1]\n", + "\n", + "case_results = pd.DataFrame({\n", + " 'Description': case_descs,\n", + " 'True Label': ['Malicious' if l else 'Benign' for l in case_labels],\n", + " 'XGB Score': pred_xgb.round(3),\n", + " 'LGB Score': pred_lgb.round(3),\n", + " 'TF-IDF Score':pred_tfidf.round(3),\n", + " 'HyperModel': pred_hyper.round(3),\n", + " 'Prediction': ['Malicious' if p > 0.5 else 'Benign' for p in pred_hyper],\n", + " 'Correct': ['\\u2705' if (p>0.5)==bool(l) else '\\u274c'\n", + " for p, l in zip(pred_hyper, case_labels)],\n", + "})\n", + "\n", + "print('\\n\\ud83d\\udccb Case Study Results:')\n", + "print(case_results.to_string(index=False))\n", + "accuracy_case = (case_results['Correct'] == '\\u2705').sum() / len(case_results)\n", + "print(f'\\nCase study accuracy: {accuracy_case:.1%}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Visualise case study ─────────────────────────────────────────────────\n", + "fig, ax = plt.subplots(figsize=(14, 7))\n", + "cs_colors = ['#F44336' if l else '#4CAF50' for l in case_labels]\n", + "x = range(len(case_results))\n", + "\n", + "ax.bar(x, pred_hyper, color=cs_colors, alpha=0.8, edgecolor='white', width=0.6)\n", + "ax.axhline(0.5, color='black', linestyle='--', lw=1.5, label='Decision threshold')\n", + "ax.set_xticks(x)\n", + "ax.set_xticklabels(case_descs, rotation=45, ha='right', fontsize=8)\n", + "ax.set_ylabel('Malicious Probability (HyperModel)')\n", + "ax.set_title('Case Study: HyperModel Scores on Adversarial URLs')\n", + "ax.set_ylim(0, 1.1)\n", + "\n", + "from matplotlib.patches import Patch\n", + "legend_els = [\n", + " Patch(facecolor='#F44336', alpha=0.8, label='True: Malicious'),\n", + " Patch(facecolor='#4CAF50', alpha=0.8, label='True: Benign'),\n", + "]\n", + "ax.legend(handles=legend_els + [\n", + " plt.Line2D([0],[0], color='black', linestyle='--', label='Threshold')],\n", + " loc='upper left')\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'case_study_scores.png', dpi=150, bbox_inches='tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 13. Save Models & Final Summary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import joblib\n", + "\n", + "MODELS_DIR = OUTPUT_DIR / 'models'\n", + "MODELS_DIR.mkdir(exist_ok=True)\n", + "\n", + "# Classical\n", + "joblib.dump(clf_models_bin['XGBoost (GPU)'], MODELS_DIR / 'xgb_binary.joblib')\n", + "joblib.dump(clf_models_bin['LightGBM (CPU)'], MODELS_DIR / 'lgbm_binary.joblib')\n", + "joblib.dump(tuned_xgb, MODELS_DIR / 'xgb_tuned_binary.joblib')\n", + "joblib.dump(tuned_lgbm, MODELS_DIR / 'lgbm_tuned_binary.joblib')\n", + "joblib.dump(tfidf_bin, MODELS_DIR / 'tfidf_lr_binary.joblib')\n", + "joblib.dump(scaler, MODELS_DIR / 'scaler.joblib')\n", + "\n", + "# DL models from stacking\n", + "import torch\n", + "for name, mdl in hypermodel.fitted_l0_.items():\n", + " if hasattr(mdl, 'net_'):\n", + " state = mdl.net_.state_dict() if not hasattr(mdl.net_, 'module') \\\n", + " else mdl.net_.module.state_dict()\n", + " torch.save(state, MODELS_DIR / f'{name}_net.pt')\n", + "\n", + "# Meta-learner\n", + "joblib.dump(hypermodel.meta, MODELS_DIR / 'hypermodel_meta.joblib')\n", + "\n", + "# Results tables\n", + "comparison_bin.to_csv(OUTPUT_DIR / 'results_binary.csv', index=False)\n", + "comparison_mc.to_csv(OUTPUT_DIR / 'results_multiclass.csv', index=False)\n", + "case_results.to_csv(OUTPUT_DIR / 'case_study_results.csv', index=False)\n", + "\n", + "print(f'\\n\\u2705 All models and results saved to: {OUTPUT_DIR.resolve()}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Final Summary ───────────────────────────────────────────────────────\n", + "print('\\n' + '='*60)\n", + "print(' FINAL RESULTS SUMMARY')\n", + "print('='*60)\n", + "\n", + "print('\\n\\ud83d\\udccc Binary (Benign vs Malicious):')\n", + "ours_bin = comparison_bin[comparison_bin['Source']=='Ours']\n", + "print(ours_bin[['Method','Accuracy','F1 (macro)','AUC-ROC']].to_string(index=False))\n", + "\n", + "print('\\n\\ud83d\\udccc 4-Class (benign / phishing / defacement / malware):')\n", + "ours_mc = comparison_mc[comparison_mc['Source']=='Ours']\n", + "print(ours_mc[['Method','Accuracy','F1 (macro)','AUC-ROC']].to_string(index=False))\n", + "\n", + "print('\\n\\ud83d\\udccc Key Literature Baselines:')\n", + "print(' Sahingoz 2019 (RF): 97.98% acc')\n", + "print(' Le 2018 (URLNet): ~98.5% acc')\n", + "print(' Nguyen 2021 (Stacking): 97.5% acc')\n", + "print(' Aljofey 2022 (CharCNN): 96.75% acc')\n", + "\n", + "best_ours = ours_bin['Accuracy'].max()\n", + "best_lit = 0.985 # URLNet\n", + "delta = best_ours - best_lit\n", + "print(f'\\n Our best binary : {best_ours:.4f}')\n", + "print(f' \\u0394 vs literature : {delta:+.4f} ({\"\\u2705 BEAT\" if delta > 0 else \"\\u274c BELOW\"} URLNet baseline)')\n", + "print('='*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 14. Inference on New URLs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def predict_url(url: str, threshold: float = 0.5) -> dict:\n", + " \"\"\"Predict whether a URL is malicious.\"\"\"\n", + " ext = URLFeatureExtractor()\n", + " feat_df = ext.transform(pd.Series([url]), verbose=False)\n", + " feat_df = feat_df[feat_names]\n", + " X_sc = scaler.transform(feat_df.values.astype(np.float32)).astype(np.float32)\n", + "\n", + " proba = hypermodel.predict_proba(X_sc, np.array([url]))\n", + " score = proba[0, 1]\n", + " label = 'Malicious' if score > threshold else 'Benign'\n", + "\n", + " top = feat_imp_df.sort_values('importance', ascending=False).head(5)\n", + " top_signals = {row['feature']: round(float(feat_df.iloc[0].get(row['feature'], 0)), 3)\n", + " for _, row in top.iterrows()}\n", + "\n", + " return {\n", + " 'url': url,\n", + " 'prediction': label,\n", + " 'malicious_score': round(float(score), 4),\n", + " 'confidence': f\"{abs(score - 0.5) * 200:.1f}%\",\n", + " 'top_signals': top_signals,\n", + " }\n", + "\n", + "\n", + "test_urls = [\n", + " 'https://www.google.com/search?q=machine+learning',\n", + " 'http://secure-paypal-login.xyz/verify-account?user=victim@email.com',\n", + " 'https://github.com/anthropics/anthropic-sdk-python',\n", + " 'http://192.168.10.45/banking/login.php?redirect=true',\n", + " 'http://free-iphone-giveaway.tk/claim?id=abc123',\n", + "]\n", + "\n", + "for url in test_urls:\n", + " r = predict_url(url)\n", + " icon = '\\ud83d\\udd34' if r['prediction'] == 'Malicious' else '\\ud83d\\udfe2'\n", + " print(f\"{icon} [{r['prediction']:9s}] score={r['malicious_score']:.4f} | {url[:70]}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/urlmodel_info/main_notebook_url.ipynb b/urlmodel_info/main_notebook_url.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..71f1c69bf0bdf38cd5b725c741db24d432ed9a4d --- /dev/null +++ b/urlmodel_info/main_notebook_url.ipynb @@ -0,0 +1,2411 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# πŸ›‘οΈ Malicious URL HyperModel\n", + "\n", + "**Dataset:** [Malicious URLs](https://www.kaggle.com/datasets/sid321axn/malicious-urls-dataset) β€” 651K URLs Β· 4 classes (benign / phishing / defacement / malware)\n", + "\n", + "**Objective:** Build a GPU-accelerated stacking HyperModel that outperforms literature baselines:\n", + "\n", + "| Baseline | Accuracy | Source |\n", + "|---|---|---|\n", + "| RF on URL features | 97.98% | Sahingoz 2019 |\n", + "| URLNet (Char+Word CNN) | ~98.5% | Le 2018 |\n", + "| Stacking CNN+LSTM+GRU | 97.5% | Nguyen 2021 |\n", + "| CharCNN | 96.75% | Aljofey 2022 |\n", + "\n", + "**Architecture:**\n", + "```\n", + "Raw URLs (651K)\n", + " β”œβ”€β”€ Feature Engineering (54 lexical features)\n", + " β”‚ β”œβ”€β”€ XGBoost (GPU)\n", + " β”‚ └── LightGBM (CPU)\n", + " β”œβ”€β”€ TF-IDF char n-grams β†’ Logistic Regression\n", + " └── Character-level Deep Learning (GPU)\n", + " β”œβ”€β”€ CharCNN\n", + " β”œβ”€β”€ CharBiLSTM\n", + " └── CNN-BiLSTM Hybrid\n", + " β”‚\n", + " β–Ό\n", + "Stacking Meta-Learner (XGBoost GPU) β†’ Final Prediction\n", + "```\n", + "\n", + "See [LITERATURE_REVIEW.md](LITERATURE_REVIEW.md) for a full survey of 15+ research papers." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 0. Install & Setup" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PyTorch 2.10.0+cu128 | CUDA available: True\n", + " GPU: NVIDIA L4\n", + " GPUs: 1\n", + "\n", + "βœ… Packages ready\n" + ] + } + ], + "source": [ + "# ─── Install Dependencies ─────────────────────────────────────────────────────────────\n", + "import subprocess, sys\n", + "\n", + "def pip_install(pkg):\n", + " subprocess.check_call([sys.executable, '-m', 'pip', 'install', pkg, '-q'])\n", + "\n", + "for pkg in [\n", + " 'xgboost>=2.0', 'lightgbm>=4.0',\n", + " 'optuna', 'kagglehub',\n", + " 'tldextract', 'imbalanced-learn',\n", + " 'seaborn', 'plotly', 'pyarrow',\n", + "]:\n", + " try:\n", + " pip_install(pkg)\n", + " except Exception as e:\n", + " print(f'Warning: {pkg}: {e}')\n", + "\n", + "# Verify PyTorch CUDA\n", + "import torch\n", + "print(f'PyTorch {torch.__version__} | CUDA available: {torch.cuda.is_available()}')\n", + "if torch.cuda.is_available():\n", + " print(f' GPU: {torch.cuda.get_device_name(0)}')\n", + " print(f' GPUs: {torch.cuda.device_count()}')\n", + "print('\\n\\u2705 Packages ready')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Project root : /teamspace/studios/this_studio/urlproject\n", + "Data dir : /teamspace/studios/this_studio/urlproject/data\n", + "Output dir : /teamspace/studios/this_studio/urlproject/outputs\n" + ] + } + ], + "source": [ + "import sys, os, pathlib, warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "PROJECT_ROOT = pathlib.Path('.').resolve()\n", + "sys.path.insert(0, str(PROJECT_ROOT))\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "sns.set_theme(style='whitegrid', palette='muted')\n", + "pd.set_option('display.max_columns', 30)\n", + "pd.set_option('display.float_format', '{:.4f}'.format)\n", + "\n", + "SEED = 42\n", + "np.random.seed(SEED)\n", + "\n", + "DATA_DIR = PROJECT_ROOT / 'data'\n", + "OUTPUT_DIR = PROJECT_ROOT / 'outputs'\n", + "DATA_DIR.mkdir(parents=True, exist_ok=True)\n", + "OUTPUT_DIR.mkdir(parents=True, exist_ok=True)\n", + "\n", + "print(f'Project root : {PROJECT_ROOT}')\n", + "print(f'Data dir : {DATA_DIR}')\n", + "print(f'Output dir : {OUTPUT_DIR}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Download Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "βœ… Dataset already exists: /teamspace/studios/this_studio/urlproject/data/malicious_phishing.csv\n", + "\n", + "Dataset path: /teamspace/studios/this_studio/urlproject/data/malicious_phishing.csv\n" + ] + } + ], + "source": [ + "from download_data import download_malicious_urls\n", + "\n", + "csv_path = download_malicious_urls(DATA_DIR)\n", + "print(f'\\nDataset path: {csv_path}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Exploratory Data Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Shape : (651191, 2)\n", + "Columns : ['url', 'type']\n", + "\n", + "Class distribution:\n", + "type\n", + "benign 428103\n", + "defacement 96457\n", + "phishing 94111\n", + "malware 32520\n", + "Name: count, dtype: int64\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
urltype
0br-icloud.com.brphishing
1mp3raid.com/music/krizz_kaliko.htmlbenign
2bopsecrets.org/rexroth/cr/1.htmbenign
3http://www.garage-pirenne.be/index.php?option=...defacement
4http://adventure-nicaragua.net/index.php?optio...defacement
\n", + "
" + ], + "text/plain": [ + " url type\n", + "0 br-icloud.com.br phishing\n", + "1 mp3raid.com/music/krizz_kaliko.html benign\n", + "2 bopsecrets.org/rexroth/cr/1.htm benign\n", + "3 http://www.garage-pirenne.be/index.php?option=... defacement\n", + "4 http://adventure-nicaragua.net/index.php?optio... defacement" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_raw = pd.read_csv(csv_path)\n", + "\n", + "print(f'Shape : {df_raw.shape}')\n", + "print(f'Columns : {list(df_raw.columns)}')\n", + "print(f'\\nClass distribution:')\n", + "print(df_raw['type'].value_counts())\n", + "df_raw.head(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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sJ577jnt27fPKiY7b9uzZ48mT56spk2bKigoSC+99JLOnz9/y/2/Z88e/f3333rkkUdyXH/16lW9/fbbCgsLU1BQkAYOHKg//vjDJu6nn35SdHS0GjVqpIceekg9e/bUnj17rGLyc7zmNAftoUOH1LNnTwUGBioiIkJz587VunXrcr0fww8//KCuXbsqICBArVu31ieffHLTfWE2m9WkSRObcwhJSktLU0BAgN58801j2fvvv68OHTrooYceUuPGjfXEE09o48aNN91G9vESFxenOXPmqFmzZgoODtaQIUOUmpqqzMxM/fvf/1ZoaKiCg4P1yiuv2My5mtf38o1yO86PHz+uoUOHqmnTpgoMDFS7du2sBtHkdr6xYsUKdejQwTi3mThxolJSUqxicptL+Mb5caW87c8GDRqoQoUK2rp16y1fL+4ejKAFcFfIysrSG2+8oa5du+b7Bl5fffWVJNmMlMiPlStX6oEHHlCrVq3k5OSkbdu2aeLEibJYLHrmmWckSefOnVN0dLTuuece9e/fXx4eHvrtt9+0ZcsWo51du3ZpxIgRCg0N1ahRoyRJCQkJ+vHHH/Xcc88VuH9Vq1ZV48aN9d133yktLU3lypXLMW7w4ME6duyYevbsqWrVqun8+fPatWuX/vjjD1WvXl1jx47VG2+8IXd3dw0cOFCSdN9991m1MXHiRHl5eemll15Senr6TfuVlJSk4cOHq3v37nr88ce1bt06DR06VIsWLcr3HG956dv1sufTCwgI0IgRI3Tu3Dm99957+vHHH/XJJ5/Iw8PDiM3KylJ0dLQCAwP18ssvKz4+XosXL5a3t7eefvrpfPUTAICSKi0tzSimnTt3Tu+//77S09NzLYjeaNiwYapevbpGjBihX375RR9++KG8vLysRqPmJafKlpiYqJEjR6pbt2566qmn5OPjo7Jly2rcuHE6cuSI6tata8Tu379fSUlJeuGFFwr8+h0dHdWhQwe988472rNnj1q0aJFj3Jw5c7RgwQI9+eSTCgwMVFpamg4cOKD//ve/CgsLU7du3XT27Fnt2rVLU6dOzbGNjz76SJcvX9ZTTz0lFxcXeXp66urVqznGZmVlqW/fvnrooYf0z3/+U998841mz56trKwsDR06NF+vMS99u97Ro0f1zDPPqGzZsurbt6+cnJy0evVq9erVS8uXL9dDDz1kFT9p0iR5eHho0KBB+v3337Vs2TL961//0syZM2+6nb1798pkMql+/fo5rp83b55MJpP69eunc+fOadmyZerdu7fWr19vjKqOj49Xv3791KBBAw0aNEgmk0kfffSRnnvuOX3wwQcKDAy0ajMvx+uNzpw5Y+Ts/fv3l7u7uz788MNcR9qeOHFCQ4cOVdeuXY1ceMyYMXrwwQf1wAMP5PgcZ2dnPfroo9qyZYsmTpxo1faXX36pzMxMRUVFSZLWrFmjSZMmqV27dnr22Wd1+fJlHT58WD/99JMee+yxXF9HtoULF6pMmTLq37+/Tpw4oeXLl8vJyUkmk0kpKSkaNGiQfvrpJ3300UeqVq2aBg0aZDw3P+/lWzl06JCeeeYZOTk5qVu3bqpWrZp+/fVXffXVVxo+fHiuz5s9e7bmzJmjRx55RD169FBiYqJWrlypn3/+WStXrsz39Gf52Z/169fXjz/+mK/2UbpRoAVwV1i1apVOnTqlpUuX5vu5x48flySrJD6/li9fbnVJXc+ePRUdHa0lS5YYCcjevXuVnJys2NhYq8sDr08qvv76a5UrV06xsbGFfonOAw88oPj4eP3222+qV6+ezfqUlBTt3btXL7/8stXokgEDBhj/f/TRRzVz5kzdc889uRa0PT09tXTp0jz1PykpSbNnz1bbtm0lXbtUsn379po2bVq+C7R56Vs2s9msadOmqW7dulqxYoVxGVWjRo00YMAALV26VEOGDDHiL1++rMjISL300kuSpB49eujxxx/X2rVrKdACAO4avXv3tnrs4uKi//znP3n+m+3v76///Oc/xuMLFy5o7dq1VgWvvORU2U6cOKFFixapWbNmxrL69evrjTfe0IYNG4wvuyVpw4YNcnd3N3KOgsrOF3/99ddcY77++ms1b95cb7zxRo7rg4ODVatWLe3atSvXnOX06dPasmWLvLy8jGW53Z3+8uXLatasmcaNGydJevrppzVw4EDFxMSoV69eVm3cSl76dr2ZM2fKbDZr5cqV8vb2liR16dJF7du311tvvaXly5dbxVeoUEGLFy825uW8evWq3n//faWmpqp8+fK5bichIUGenp65DjJITk5WXFycsb5+/foaNmyY1qxZo2effVYWi0UTJkxQSEiIFi1aZGy/e/fu6tChg2bOnKnFixdbtZmX4/VGMTExSk5O1scffyx/f39J124aldNVetK1LxlWrFihhx9+WNK1S+ObN2+ujz766KZX8EVFRWndunXatWuX1fQicXFx8vb2Ns41vv76az3wwAOaNWtWrm3dTFZWlt5//32jkPn333/rs88+U7NmzRQTEyNJeuaZZ/Trr7/qo48+sirQ5ue9fCuTJk2SxWLRxx9/rKpVqxrLr3+P3+j8+fNasGCBwsPDFRMTIweHaxeY+/r66l//+pc2bNigf/zjH/nqR372p7e3NwVaWGGKAwCl3t9//61Zs2bpxRdfzFcCmi0tLU2SVLZs2QL34frkIzU1VefPn1eTJk108uRJ4xK47KTz66+/ltlszrEdDw8PZWRkGJfAFabsG6ddvHgxx/VlypSRs7Ozdu/ereTk5AJv56mnnspzcfn+++9XmzZtjMflypVTly5d9Msvv+jPP/8scB9u5cCBAzp37px69OhhNcdVixYt5Ovrq6+//trmOT169LB63KhRo1xPlAAAKI3Gjx+vJUuWaMmSJXrrrbcUEhKicePG2UxPlJsb5w99+OGHdeHCBSMXk/KWU2WrXr26VXFWupZvtW7dWp999plxiX9WVpY+//xztW7dOt83kr3RrfIp6Vo+d/ToUSUlJRV4O23bts1XXnt9wctkMumZZ56R2WxWfHx8gftwK1lZWdq1a5ceffRRozgrXcvvOnbsqD179lj9bqVreeL1N016+OGHlZWVpd9///2m27pw4YI8PT1zXd+lSxer4m379u1VsWJFbd++XZJ08OBBJSUl6bHHHtPff/+t8+fP6/z580pPT1doaKi+//57mxHKeTleb/TNN98oKCjIKM5K14rSuY1WrVOnjlGclSQvLy/5+Pjo5MmTuW5Dkpo2bap77rlHcXFxxrLk5GR9++23xuhZ6dqxePr0ae3fv/+m7eWmc+fOVqNMAwMDZbFYbAqbgYGB+uOPP3TlyhVjWX7eyzdz/vx5ff/99/rHP/5hVZyVdNMbcH377bcym8169tlnjeKsJD355JMqV66ccWzkR372p4eHhy5dumQzLQbuXoygBVDqzZw5U56enurZs+dN4y5cuGBVGC1TpozKly9vJHMXL160uqw9P/bs2aPZs2dr3759Nn+Es0cENGnSRO3atdOcOXO0dOlSNWnSRI8++qgee+wx49Kkp59+Wp9//rn69eunSpUqKSwsTJGRkYqIiChQv66XPd1AboVoFxcXjRo1Sm+++abCwsL00EMPqUWLFurSpYsqVqyY5+1Ur149z7E1a9a0Saxq1aolSfr999/ztd38OHXqlCTJx8fHZp2vr6/NXGSurq42J0menp63VcgGAKCkCQwMtLoKqGPHjurSpYv+9a9/qUWLFre8YdKNxZXsvCs5OdnIx/KSU2XLLefo0qWL4uLi9MMPP6hx48b69ttv9ddff93WdFbZbpVPSdKQIUP04osvql27dqpbt67Cw8PVuXPnHK9gyk1+8ikHBwerAqn0vxznVoXP23H+/HllZGTkmE/Vrl1bV69e1R9//GF1qX5ux8CNc4Lm5Po5dW9Us2ZNq8cmk0k1a9Y0Xn92sfxmo1JTU1OtisB5OV5v9PvvvysoKMhmeY0aNXKMr1Klis2yvOSYTk5Oatu2rT799FNlZmbKxcVFmzdvltlstirQ9uvXT99++62efPJJ1axZU2FhYerYsaMaNWp00/az3bgPst9/N/a7fPnyunr1qlJTU3XPPfdIyt97+Wayi9X5vdoxO9/39fW1Wu7i4iJvb+8CvTfysz+zj9ebFZFxd6FAC6BUS0pK0po1azR27FidPXvWWH758mWZzWb99ttvKleunCpUqKDBgwdr9+7dRszjjz+uKVOmGH+0jxw5YvUNdl79+uuv6t27t3x9fTVmzBhVqVJFzs7O2r59u5YuXWp8G28ymTRr1izt27dP27Zt0zfffKOxY8dqyZIlWr16tcqWLat7771Xn3zyiXbu3KkdO3Zox44d+uijj9SlSxeryf4L4ujRo3J0dLxpwt+7d2+1atVKX375pXbu3Kl33nlHCxcu1LJly3Kd8+tGhX1339ySmjt5g67ickdYAACKEwcHB4WEhOi9997TiRMncp0z8/r4nGQXMvKaU2W7foTe9cLDw3Xfffdpw4YNaty4sTZs2KCKFSvmeoOp/Dhy5Igk24Lg9Ro3bqwtW7Zo69at2rVrl9auXatly5Zp4sSJevLJJ/O0ndxeW0Hllk/lNq9tUbnVMZCbChUq5KmIm5vs9l9++WWr0a3Xu3F0dUH7mh+3k2N26NBBq1ev1o4dO/Too49q06ZN8vX1tfoioHbt2tq0aZO+/vprffPNN9q8ebM++OADvfTSS1bTeeUmt31Q2O/l4iorK8vqd5Sf/ZmSkiI3N7dCfy+j5KJAC6BUO3PmjK5evapJkyZp0qRJNutbt26tZ599Vq+++qpGjx5tldjdf//9kqSWLVtqwYIF2rBhQ4EKtF999ZUyMzM1b948q2+Zb7xLbragoCAFBQVp+PDh2rhxo0aNGqW4uDgjYXdxcVGrVq3UqlUrXb16VRMmTNDq1av14osv3vRk4GZOnTql77//XkFBQbl+45+tRo0a6tOnj/r06aOkpCR16dJFixcv1rRp0yQV7rfAJ06ckMVisWoze4RDtWrVJFmPrLh+hHP2t+LXy2vfsn9PiYmJCg0NtVqXmJhoM1oAAADkLPsL01vdGDQv8ptT5cbR0VEdO3bUxx9/rFGjRunLL7/M1xRMucnKytKnn34qNze3W45ArFChgv7xj3/oH//4hy5evKiePXtq9uzZRr5XmPnU1atXdfLkSauRrImJiZJs86kbLy3PaRRhXvvm5eUlNzc3Y1vXS0hIkIODQ44jRAvC19dXGzduzHXk5YkTJ6weWywWnThxwrh5cPYI43LlyhVKoT431apVs+mLdPM5iwuqcePGqlixouLi4tSwYUP93//9n3Gj3Ou5u7srKipKUVFRyszM1ODBgzV//nwNGDCg0AdWZCus97L0v99d9pcjeZW93YSEBKsR5pmZmfrtt9+sjgNPT88cvwA4deqUzej0vO7P3377zWb0Lu5uzEELoFR74IEH9O6779r8e+CBB1S1alW9++676tq1qySpQYMGeuSRR4x/derUkXTtZgjNmjXThx9+qC+//NJmG5mZmTcdvZqd7F//bXpqaqrWrVtnFZecnGzzjXv2N/iZmZmSrs2nez0HBwcjscyOya8LFy5oxIgRysrKyjFpy5aRkaHLly9bLatRo4bKli1rtW03N7fbGsFwvbNnz2rLli3G47S0NH3yySfy9/c3pjfIviTs+++/N+LS09P1ySef2LSX1741aNBA9957r1atWmX12rZv367jx4/neldmAADwP2azWbt27ZKzs7Nq16592+3lNafKi86dOys5OVnjx49Xenq6OnXqdFt9y8rK0qRJk3T8+HH16tXrpl9435jPlS1bVjVq1LDJp6S8XdqfFytWrDD+b7FYtGLFCjk7OxtfRFerVk2Ojo5W+ZQkrVy50qatvPbN0dFRYWFh2rp1q9W8/H/99Zc+/fRTNWrU6JYDA/IqKChIFotFBw4cyHH9J598YjU37KZNm/Tnn38a04Q1aNBANWrU0OLFi3OcP/j8+fOF0s/w8HDt27dPBw8eNJZduHBBGzduLJT2r+fg4KD27dtr27Zt2rBhg65cuWI1vYFkeyy6uLiodu3aslgsud4TozAU5nvZy8tLjRs31rp162wGaNxsNPMjjzwiZ2dnvf/++1Zxa9euVWpqqpo3b24s8/b21k8//WT1Ht22bZv++OMPqzbzsz9/+eUXNWzYMO8vFKUeI2gBlGpeXl569NFHbZYvW7ZMknJcl5OpU6eqT58+GjRokFq2bKnQ0FC5ubnpxIkTiouL09mzZ3OdsyosLEzOzs4aOHCgunfvrosXL+rDDz/Uvffea3Wjq48//lgrV67Uo48+qho1aujixYtas2aNypUrZySP48aNU3Jyspo2bapKlSrp1KlTWr58ufz9/fN04pOUlKT169fLYrHo4sWLOnTokDZt2qT09HSNGTPmpnPZJiUlqXfv3mrfvr3q1KkjR0dHffnll/rrr7/UoUMHI+7BBx/UypUrNXfuXNWsWVNeXl42o1DzqlatWnr11Vf1888/695779W6det07tw5TZ482YgJCwtT1apV9eqrryohIUGOjo5at26d7rnnHpskLa99c3Z21qhRo/TKK6+oZ8+e6tChg86dO6f33ntP1apVs7lLNQAAkHbs2KGEhARJ1wpaGzduVFJSkvr3718ohbi85lR5Ub9+fdWtW1ebNm1S7dq19eCDD+b5uampqVq/fr0k6dKlSzpx4oS2bNmiX3/9VR06dNDQoUNv+vwOHTqoSZMmevDBB1WhQgX9/PPP+uKLL6zul5Ddn0mTJik8PFyOjo5W+VZ+uLq66ptvvtHo0aMVGBiob775Rl9//bUGDhxozKFfvnx5tW/fXsuXL5fJZJK3t7e+/vprnTt3zqa9/PRt2LBh+vbbb/X000/r6aeflqOjo1avXq3MzEz985//LNDryUmjRo1UoUIFxcfH55jbeXp66umnn9YTTzyhc+fOadmyZapZs6aeeuopSdeKmZMmTVK/fv3UsWNHPfHEE6pUqZLOnDmj7777TuXKldP8+fNvu599+/bVhg0b9Pzzz6tnz55yd3fXhx9+qCpVqujChQuFPh9pZGSk3n//fc2aNUt169a1OV+Ijo7Wfffdp4YNG+ree+9VQkKCli9frubNmxda8Twnhflelq6dI/Xo0UOPP/64unXrpurVq+v333/X119/bbxXb+Tl5aUBAwZozpw56tu3r1q1aqXExER98MEHCggIsPrS5sknn9QXX3yhvn37KjIyUr/++qs2btxoM3dwXvfngQMHdOHCBbVu3TrfrxWlFwVaAMgDLy8vrVq1Sh988IHi4uI0Y8YMmc1mVatWTa1atdKzzz6b63N9fX01a9YszZw5U2+++abuu+8+9ejRQ15eXho7dqwR16RJE/3888+Ki4vTX3/9pfLlyyswMFDTpk0zLp3p1KmT1qxZow8++EApKSmqWLGiIiMjNXjw4Fznerrerl27tGvXLjk4OKhcuXKqXr26unTpom7duhkjhnNTuXJldejQQfHx8dqwYYMcHR3l6+urmTNnql27dkbcSy+9pFOnTmnRokW6ePGimjRpclsF2tdee01Tp05VYmKiqlevrhkzZljdkdnZ2Vlz5szRxIkT9c4776hixYp67rnn5OHhoVdeecWqvfz07YknnlCZMmUUExOjadOmyd3dXY8++qj++c9/FvhmcQAAlGazZs0y/u/q6ipfX19NmDDB5m73BZXXnCqvOnfurLfeeivfNwc7ffq0Xn75ZUnXLme+//77FRQUpAkTJigsLOyWz+/Vq5e++uor7dq1S5mZmapataqGDRum6OhoI6Zt27bq1auXPvvsM23YsEEWi6XABVpHR0ctWrRIEyZM0FtvvaWyZctq0KBBeumll6zixo0bpytXrmjVqlVycXFR+/bt9fLLL6tjx45Wcfnp2wMPPKAVK1Zo+vTpWrBggSwWiwIDA/XWW2/poYceKtDryYmLi4see+wxbdq0SSNGjLBZP3DgQB0+fFgLFy7UxYsXFRoaqtdff90YDSxJISEhWr16tebOnavly5crPT1dFStWVGBgoLp161Yo/axSpYree+89TZo0SQsWLJCXl5eeeeYZubm5adKkSYU+pUDDhg1VpUoV/fHHHzajZyWpW7du2rhxo5YsWaL09HRVrlxZvXr10osvvlio/bhRYb+X69WrpzVr1uidd97RypUrdfnyZVWtWlWRkZE3fd7gwYPl5eWl5cuXa/LkyfL09NRTTz2lESNGyNnZ2Yhr1qyZxowZoyVLlug///mPGjRooPnz59tcRZnX/blp0yZVrVpVTZs2zfdrRellshTmDNYAAAAAAJQAy5Yt0+TJk/XVV18xv3wpcPLkSUVGRiomJqbAgwPs5d///rdWr16tvXv3cvPZUi4zM1OtWrVSv3799Nxzz9m7OyhGmIMWAAAAAHBXsVgsWrt2rRo3bkxxtpTw9vbWP/7xDy1cuNDeXbmpS5cuWT3++++/tWHDBjVq1Iji7F1g3bp1cnJyUo8ePezdFRQzjKAFAAAAANwV0tPT9dVXX+m7777TmjVrNHfuXOaBxB3VuXNnNWnSRLVr19Zff/2ldevW6ezZs1q6dKkaN25s7+4BsBMKtAAAAACAu8Jvv/2m1q1by8PDQ08//bSGDx9u7y7hLvP222/riy++0OnTp2UymVS/fn0NGjRIjzzyiL27BsCOKNACAAAAAAAAgJ0wBy0AAAAAAAAA2AkFWgAAAAAAAACwEyd7dwA3t3fvXlksFjk7O9u7KwAAAHeU2WyWyWRScHCwvbuCAiKXBQAAd6v85LKMoC3mLBaLmCb49lgsFmVmZrIfcUscK8gLjhPkBcdJ4SAPKvn4HaKg+BwFUFzweYSCyk8exAjaYi57tEFAQICde1Jypaen6+DBg6pTp47c3d3t3R0UYxwryAuOE+QFx0nh+Pnnn+3dBdwmclkUFJ+jAIoLPo9QUPnJZRlBCwAAAAAAAAB2QoEWxcqlS5fUpk0bPfzww5Kkc+fOaeTIkYqIiFDDhg3VpUsXbd261eo5P/zwg5566ik1atRIzZo10/Tp03X16tVct/Haa6+pXbt2qlevnpYuXWqz/vjx4+revbseeughtWvXzmp7p0+fVvfu3RUSEqJGjRqpc+fO2rJlS+G8eAAAAKAEIocHAOD2UKBFsfLOO++oatWqxuP09HTVr19fa9as0Q8//KAhQ4Zo5MiROnbsmCQpKytLL730klq3bq3du3dr5cqV+uyzz7RmzZpct1GvXj1NmDBBgYGBNuvMZrMGDhyo0NBQ7d69W2PGjNGoUaN04sQJSZKHh4cmT56s+Ph47dmzR6+//rr++c9/6uTJk4W8JwAAAICSgRweAIDbQ4EWxcaBAwe0c+dO9evXz1jm7e2t6OhoVa5cWQ4ODmrVqpV8fHy0b98+SVJqaqouXLigLl26yNHRUdWrV9cjjzyiI0eO5LqdZ555RqGhoXJ1dbVZ98MPP+jChQt68cUX5erqqpYtW6px48Zav369JMnd3V0+Pj5ycHCQxWKRg4ODsrKy9PvvvxfuzgAAAABKAHJ4AABuHwVaFAtXrlzRa6+9pvHjxxs3k8jJuXPndPz4cfn5+UmSKlSooH/84x9au3atzGazfv31V3377bdq3rx5gfpx+PBh1alTx6oP/v7+Onz4sFXcY489poCAAHXr1k0NGzY0LucCAAAA7hbk8AAAFA4ne3cAkKTY2Fj5+/urcePG+u6773KMyczM1PDhwxUZGWl1J+DIyEiNGzdO7777rrKystSzZ09FREQUqB8XL16Uh4eH1bLy5cvr4sWLVss2btyozMxM7dq1SwkJCXJ0dCzQ9gAAAICSihweAIDCwQha2N2JEye0atUqvfzyy7nGZGZmasiQIXJzc9Mbb7xhLE9ISNCLL76oV155Rfv379c333yj48ePa9q0aQXqS9myZZWammq1LDU1VWXLlrWJdXFxUcuWLfXdd99pw4YNBdoeAAAAUBKRwwMAUHgo0MLu9uzZo7/++kvt2rVTSEiIXnzxRaWlpSkkJEQ//fSTMjMzNXToUJnNZs2ePVsuLi7Gc48cOaLKlSurffv2cnJy0v33368uXbpo+/btBeqLn5+fjh07JrPZbCw7dOiQ6tatm+tzrly5YtyAAAAAALgbkMMDAFB4KNDC7iIjI7VlyxatX79e69ev16RJk1S2bFmtX79e/v7+GjZsmDIyMjR37lyrxE6SHnzwQZ09e1Zffvmlrl69qvPnz2vDhg3y9/c3Yvr27au1a9cajzMzM3X58mVdvXpVWVlZunz5sq5cuSJJevjhh+Xp6an58+crMzNT27dv1+7du9WlSxdJ0u7du7V3715lZmYqMzNTH330kb777js98sgjRb+jAAAAgGKCHB4AgMLDHLSwOzc3N7m5uRmPvby8ZDKZVLlyZe3evVtbt26Vq6urmjZtasQMGDBAAwcOlLe3t95++23NmTNHo0ePlqurqx555BG98sorRuzp06fVtm1b43F0dLR2794t6dodX6dOnapBgwZp8ODBcnZ21rx58zRu3DjFxMSocuXKeuutt1SzZk1JUkZGht544w399ttvcnJyUq1atfT2229zgwEAAADcVcjhAQAoPCaLxWKxdyeQu59//lmSrCbUR979/vvvGjp0qF555RX5+/vL3d3d3l1CMZaenq6DBw9yrOCmOE6QFxwnhYM8qOTjd4iCIIcHUJyQ16Gg8pMHMcUBSrVq1arpvffes3c3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jRuxc+dO3Lx5ExYWFhgwYAD8/f3bZT+MGjUKMpkMGzZswNdffw0A6NevH4YOHaoxJ29zBAQEICcnBytXrkRxcTEmTJiA+Pj4dinnk6apuqM1lEolPv/8c+zfvx/l5eXo27cvZs6cibCwsHYsecNYJ+mfiYkJUlJSsGLFCkREROC5555DWFgYTp06pfWjfnWZm5vDzs4Oubm5Gk9KuLu74/LlyxrzzwJAYmIiYmNjER0dDSsrK0ybNg0VFRXYvHlzs8q5bds2pKSkYMOGDSgsLISVlRXs7e0xZcqU1r15IqIWYBueiDqbtrTj6po9ezasra2xdetW7NmzB927d4eLi0u988wCj0aQbty4EWvWrEFCQgIqKirg4OCAzZs3w9HRUVovMDAQ169fx86dO7F161aMHj0aH3zwgcbNdRcXF6SmpuIf//gHKisr8cILLyAmJkbjOpqeLgZCCKHvQhB1NidPnsSMGTOwfft2eHh46Ls4RFSP6OhonD9/Ht98842+i9LhWCcRERE1jd+XRET0pOITtEQAli9fjsGDB8PKygqXLl3C3//+d9jb28PNzU3fRSOiZxDrJCIioqbx+5KIiJ4W7KAlAlBaWioNFzc3N8fQoUOxaNEiGBryd/SISPdYJxERETWN35dERPS04BQHRERERERERERERHrCW4tEREREREREREREesIOWiIiIiIiIiIiIiI9YQctERERERERERERkZ6wg5aIiIiIiIiIiIhIT9hBS0RERERERERERKQn7KAlIiIiIiIiIiIi0hN20BIRERERERERERHpCTtoiYiIiIiIiIiIiPSEHbREREREREREREREevL/AD/frMlS0eCqAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4-class imbalance ratio: 7.60%\n", + "Binary imbalance ratio: 52.11%\n" + ] + } + ], + "source": [ + "# ─── Class distribution plot ─────────────────────────────────────────────────\n", + "fig, axes = plt.subplots(1, 2, figsize=(14, 4))\n", + "\n", + "# 4-class\n", + "vc = df_raw['type'].value_counts()\n", + "colors4 = ['#4CAF50', '#F44336', '#FF9800', '#9C27B0']\n", + "axes[0].bar(vc.index.astype(str), vc.values, color=colors4)\n", + "axes[0].set_title('4-Class Distribution')\n", + "axes[0].set_ylabel('Count')\n", + "for i, v in enumerate(vc.values):\n", + " axes[0].text(i, v + vc.max()*0.01, f'{v:,}', ha='center', fontsize=9)\n", + "\n", + "# Binary (benign vs malicious)\n", + "binary_counts = pd.Series({\n", + " 'benign': (df_raw['type'] == 'benign').sum(),\n", + " 'malicious': (df_raw['type'] != 'benign').sum(),\n", + "})\n", + "axes[1].bar(binary_counts.index, binary_counts.values, color=['#4CAF50', '#F44336'])\n", + "axes[1].set_title('Binary Distribution (benign vs malicious)')\n", + "axes[1].set_ylabel('Count')\n", + "for i, v in enumerate(binary_counts.values):\n", + " axes[1].text(i, v + binary_counts.max()*0.01, f'{v:,}', ha='center', fontsize=9)\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'eda_class_distribution.png', dpi=150)\n", + "plt.show()\n", + "\n", + "print(f'4-class imbalance ratio: {vc.min()/vc.max():.2%}')\n", + "print(f'Binary imbalance ratio: {binary_counts.min()/binary_counts.max():.2%}')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9gAAAGACAYAAABWaMrCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAACet0lEQVR4nOzdeXxU1f3/8de9c2cmG0kIAoKASNCIAiKgCFFE/VqJWrWUCl2UTY2KqLT0K2p/CGq/UtyQUBUpKlIEabV1qYJaqygu1YK7tUIAkUikxOyZ9d7fHyFDhklCBgKZhPfz8cgjzLnnnHvuzIEHnzmb4TiOg4iIiIiIiIgcELO1GyAiIiIiIiLSHijAFhEREREREWkBCrBFREREREREWoACbBEREREREZEWoABbREREREREpAUowBYRERERERFpAQqwRURERERERFqAAmwRERERERGRFqAAW0RERERERKQFKMAWERFpQc888ww5OTl88sknh+yeM2fO5Oyzzz4k9zr77LOZOXNm5PWhft7LLruMyy677JDcq77W+Fz35ZtvviEnJ4dnnnmmtZsiIiK7KcAWETmMFRQUkJOTQ0lJSYPXL7zwwqhgpu4/9HU/xx9/PKeeeipXXHEFGzZsiLv+puTk5HD77bfHXe5QWb58+UEJbOres7qfk046iVGjRnH11Vfz9NNPEwgEWuQ+GzdupKCggG+++aZF6mtJidy2Q+W9997juuuuIzc3l/79+zN8+HCuvvpqXn755dZumoiINMFq7QaIiEjbc+GFFzJy5Ehs22bLli08+eSTXH755fz5z38mJyentZt3SKxYsYKOHTsyZsyYg1L/7NmzSUlJIRAIUFxczFtvvcUtt9zC0qVLWbRoEd26dYvkveOOO3AcJ676N27cyMKFCzn11FPp0aNHs8utXr0awzDiule8mmrbkiVLDuq9E8GCBQv4/e9/T+/evRk3bhzdu3entLSUN954g2nTpnHPPffwwx/+sLWbKSIiDVCALSIicTvhhBO4+OKLI6+HDBnClVdeyYoVK5g9e3brNawdOe+888jKyoq8vu6663juuee46aabuOGGG1i1alXkmtvtPqhtcRwHv99PUlISHo/noN5rX1r7/gfb6tWr+f3vf895553HvffeG/XZXnHFFbz55puEQqFWbKGIiDRFU8RFROSADR06FIBt27Yd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nDlN1l0X1Db15cm+lJaWsnDhQl588cWYvwP1107PmDGDmTNnMmrUKE488UTOPPNMLrnkksgXAD179mTSpEk89thjPP/88wwdOpSzzz6biy66SNPDRUSaoABbROQw5vV6gdqRrobU1NRw5JFHxqQfffTRjBgxAoCzzjoL0zS59957GTZsGAMGDDh4Da7Htm06derEPffc0+D1+jtwAw1OlT6Y9g746sR7nNbe/vOf/wBNB/2dOnWKrANeu3Yta9eu5ZlnnuGSSy7hd7/7XbPuU38k9GA7lF/ONNYPDvRzqa9v376ceOKJPPfcc1xyySU899xzuN1u8vLymixXt9687jPeHzfeeCMbNmxgypQp9OvXj5SUFGzb5oorroh6xvPPP5+hQ4fyyiuvsG7dOpYsWcLixYspKCjgzDPPBGo3z/vRj37E3//+d9atW8edd97JokWLWLVqVYP/LoiIiKaIi4gc1upGWTdv3hxzraamhh07dsSMxDbkmmuuITU19YA38IpHr169KC0tZfDgwYwYMSLm5/jjj4+7zqOOOoqtW7fGpH/99dcxaQf7LOjGPPfccwD7nL7t8Xg4++yzmT17Nq+++irjxo3jr3/9a+T5Wrr9e79vVVVV7Ny5k6OOOiqSlpGRETNSHAgE2LlzZ1RaPG2r+8xs245KLywsBGJnEhyo5jwn1I5iv/vuu3z33Xe88MILjBo1KmpqekOOOeYYjjnmGP7+97/v1yh2WVkZ77zzDldeeSXXX3895557Lrm5uY1OS+/SpQs///nPefDBB/n73/9OZmYmDz/8cFSenJwcrr32WpYvX87y5cspLi5mxYoVcbdNRORwoQBbROQwNnz4cNxuNytWrIgJUJ566ilCoVCzphWnp6czbtw43nrrLb744ouD1dwoeXl5hMNhHnzwwZhroVBov6Zin3766Xz44YdRz1BaWsrzzz8fkzc5OfmAp3vH6/nnn+dPf/oTJ598cqNT44GYI5lM0yQnJweoDWihtv1Aix259NRTT0UdTbVixYqY/tOzZ08++OCDqHKrVq2KGcGOp20jR45k586dvPjii5G0UCjEsmXLSElJ4ZRTTtmv52lMc54T4MILL8QwDH7729+ybdu2Jjc3q+/666+ntLSU3/zmNw2ed/3WW2/xj3/8o8GyjY3O1x3PViccDse8t506daJLly6R/lFZWRlz/+OOOw7TNCN5REQklqaIi4gcxjp16sTUqVOZP38+P//5zzn77LNJTk5mw4YNvPDCC5x++ukx5ys35vLLL2fp0qU88sgj3H///VHXHn/88Zgpx6ZpRo64asynn37aYAB96qmncuqppzJu3DgWLVrEF198QW5uLm63my1btrB69WpuvfXWuDddu+KKK3juueeYNGkSv/jFLyLHdHXr1o3S0tKokdUTTzyRFStW8OCDD3L00UeTlZXVZNAbrzVr1pCSkkIwGKS4uJi33nqL9evXc/zxx/PAAw80WfY3v/kNZWVlnHbaaXTt2pWioiL++Mc/0q9fv8ja5H79+uFyuVi8eDEVFRV4PB5OO+00OnXqtF/tDQaDTJw4kby8PDZv3syTTz7JkCFDonYQ/8lPfsJtt93GtGnTGDFiBP/+979566236NixY1Rd8bRt3LhxPPXUU8ycOZPPPvuMo446ijVr1rB+/XpuueWW/T7u6kCeE2qXKJxxxhmsXr2a9PR0Ro0a1az6zz//fL788ksefvhhPv/8cy688EK6d+9OaWkpb775Ju+88w733ntvg2XT0tI45ZRT+MMf/kAwGKRr166sW7cucn57naqqKs4880zOO+88jj/+eFJSUnj77bf55JNPIruKv/vuu9x+++2MHj2a3r17Ew6HefbZZ3G5XIf0tAARkbZGAbaIyGHummuu4aijjmL58uU8+OCDhEIhevTowbRp07jqqqsaXUu8t65du/LDH/6QZ599lq+//jpqjfCiRYti8rtcrn0G2B999BEfffRRTPoNN9zA0KFDuf322+nfvz8rV67k/vvvx+VycdRRR3HRRRcxePDgZrW7vm7duvHEE09E1ppmZWXx85//nOTkZO68887ImnWAqVOnUlRUxB/+8Aeqqqo49dRTWzTAnj17NlC7Tr5jx47069eP//u//+OHP/xhzLnce7voootYtWoVTz75JOXl5XTu3Jm8vDymTZsW+Tw7d+7MnDlzWLRoEbfeeivhcJgnnnhivwPsWbNm8fzzz7NgwQKCwSAXXHABv/nNb6K+lLj00kv55ptv+POf/8ybb77JkCFDeOyxx5g4cWJUXfG0LSkpiWXLlnHPPffwl7/8hcrKSo455hjuuusuxowZs1/PcqDPWefiiy/mH//4B3l5efv8zOqbPn06p512GsuWLWPFihWUlZWRnp7OSSedxIMPPtjksWf33nsvd9xxB08++SSO45Cbm8vixYujlhQkJSXx05/+lHXr1vHyyy/jOA69evXitttu42c/+xlQOzX89NNP5x//+AfFxcUkJyeTk5PD4sWLG9wIUEREahlOS+7qISIi0g799re/5amnnmLDhg2HfLM0abteffVVpk6dGnX+uoiItG9agy0iIlKPz+eLev3999/z3HPPMWTIEAXXEpc//elP9OzZkyFDhrR2U0RE5BDRFHEREZF6xo0bx6mnnkp2djb//e9/efrpp6msrOTaa69t7aZJG/G3v/2NL7/8ktdff51bb7211XacFxGRQ09TxEVEROq57777WLNmDTt27MAwDE444QSuu+66yLnfIvuSk5NDSkoK559/PnPmzMGyNJ4hInK4UIAtIiIiIiIi0gK0BltERERERESkBSjAFhEREREREWkBWhS024YNG3AcB7fb3dpNERERERERkQQRDAYxDIOTTz55n3k1gr2b4zgk6nJ0x3EIBAIJ2z45PKlfSqJRn5REoz4piUZ9UhJRW+iX8cSKGsHerW7kesCAAa3ckljV1dV88cUX9O3bl5SUlNZujgigfimJR31SEo36pCQa9UlJRG2hX37yySfNzqsRbBEREREREZEWoABbREREREREpAUowBYRERERERFpAQqwRURERERERFqAAmwRERERERGRFqBdxEVEREREpE0Lh8MEg8HWbobsB7/fH/ltmod+/NftduNyuVqsvrgD7E2bNnHnnXeyYcMGUlNTufjii7nxxhvxeDxNlnMch8WLF/Pkk09SUlJCv379uPnmmxk0aFCD+W3bZuzYsXz22Wc88MADjB49Our6a6+9xvz589m8eTPdu3fnqquu4sc//nG8jyMiIiIiIm2U4zjs2LGD0tLS1m6K7CfbtrEsi6KiolYJsAEyMzM58sgjMQzjgOuKK8AuKytjwoQJ9O7dm4KCAoqLi5k7dy4+n49Zs2Y1WXbx4sUsWLCAGTNmkJOTw/Lly5k8eTLPPvssPXv2jMm/cuVKiouLG6zrgw8+4LrrrmPs2LHccsstvPvuu9x6662kpqbGBOIiIiIiItI+1QXXXbp0ISUlpUUCJDm0wuEwfr8fr9fboiPJzeE4DtXV1Xz33XcAdOvW7YDrjCvAXrlyJVVVVSxcuJDMzEyg9g2ZM2cO+fn5dO3atcFy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v/yywWvnnHMO55xzTrPrEhERERERSWQdOnSIBNd1r0eMGMFHH33Ehg0bqK6uZvTo0YRCezYJHjFiBD6fj6+++opTTz01kn766adH/pySkkL37t3ZsWNHo/f+5JNP+J//+Z9IcA00Gm8df/zxkeAaiGwUrQA7wY7pEhEREREROVzVD1rrdOrUiU2bNvH9998D8KMf/ajBst9++23U6w4dojdac7vdDU73rrNz586Y+6elpTW4q3Z6enpM3dC6R20lCgXYIiIiIiIiCaCkpCQmbdeuXXTu3DlyHPHChQsbHCU+0M2eO3fuHHP/yspKBc1ximsXcRERERERETk4KioqeOedd6Jev/3225x00kmcfPLJJCcns2PHDgYMGBDzU3/99f4YMGAAr7/+OrZtR9JeffXVA6rzcKQRbBERERERkQSQmZnJrbfeyvXXX0+HDh1YvHgxjuMwYcIE0tPTuf7667n77rvZsWMHp556Ki6Xi23btvH3v/+dgoICkpOT9/ve+fn5jB07lmnTpnHppZdSVFTEo48+itfrjesc6MOdAmwREREREWl3klyxa4cT/Z6dO3dmxowZzJs3j6+//ppjjz2WJUuWcMQRRwAwefJkunbtymOPPcYf//hHLMuiV69ejBo1KrIOen+dcMIJzJ8/n3vvvZfrrruOY489lrlz53L55ZfHrOeWxinAFhERERGRdiXVncKQrkNa7d77Y+7cuZE/jxo1qtF8F1xwARdccEGj18eMGcOYMWNi0p999tmo1w2d/PSDH/yAH/zgB5HX77zzDqFQiH79+jVZrl+/fo2e/nS4UYAtIiIiIiLtSponjTRPWms3o82ZPXs2w4cPJzMzk40bN/Lggw9ywgknMHTo0NZuWpuhAFtEREREREQoLy/njjvuoLS0lLS0NM444wxuuummqLOxpWkKsEVERERERIT77ruvtZvQ5umrCBEREREREZEWoABbREREREREpAUowBYRERERERFpAQqwRURERERERFqAAmwRERERERGRFqAAW0RERERERKQFKMAWERERERERaQEKsEVERERERNqAs88+m9tvv73JPO+99x45OTl88sknza43JyeHJUuWNJnnmWeeIScnh5KSkmbXeziyWrsBIiIiIiIiLcmuKIeqyta5eWoaZof01rk3cOKJJ/LUU0+RnZ3dovWOGjWKp556ivT01nu2tkABtoiIiIiItC9VlYT/+Q6Or+aQ3tZISsZ16nBoxQA7LS2NQYMGtXi9WVlZZGVltXi97Y2miIuIiIiISLvj+Gqg5tD+HEhAP3PmTC688ELeeOMNLrzwQgYMGMCYMWP48MMPY/IuX76cs846iyFDhnDttddGTdtuaIr4n//8Zy644AIGDhzIsGHD+OlPf8rHH38cVadt2xQUFDBixAiGDRvGzTffTHV1deT63lPEv/nmG3Jycnj22We5/fbbOeWUUzj99NP53e9+RygUiqr7lVde4bzzzmPAgAFceumlfPbZZwwdOpSCgoL9fr8SlQJsERERERGRBLBz507mzJnDlClTmD9/Ph6PhylTprBr165Intdee43XXnuNWbNmceutt/L+++9zxx13NFrn+++/z6233srIkSN55JFH+N3vfsfw4cOpqKiIyrd8+XK2bNnC3LlzmTp1Ks8//zwPPvjgPts8f/58TNNk/vz5jB8/nkcffZQ//elPkeuff/45N9xwA3379mXhwoVccsklTJ8+nUAgsB/vUOLTFHEREREREZEEUFpayvz58xk+fDgAp556KmeeeSaPP/44v/rVrwBwHIeHHnoIj8cDwPbt21m0aBG2bWOaseOnH3/8MZmZmdx0002RtFGjRsXk69y5M/feey8AI0eO5PPPP2fNmjXMmDGjyTYPHDiQ3/zmNwDk5uby3nvvsWbNGn76058CsGjRInr06EFBQUGkfampqfzv//5vPG9NmxH3CPamTZuYNGkSgwYNIjc3l3nz5jXr2wfHcXjkkUcYNWoUAwcOZNy4cTHTHT7++GMmTZpEbm4u/fv3Z9SoUdxyyy0UFxdH5SsoKCAnJyfmZ8WKFfE+joiIiIiISELo0KFDJLiuez1ixAg++uijSNopp5wSCa4BsrOzCQaDUaPc9Z1wwgmUlpYyc+ZM1q1bR01Nw9PYR4wYEfU6OzubHTt27LPNp59+epPlPvnkE0aNGhUV/J9zzjn7rLetimsEu6ysjAkTJtC7d28KCgooLi5m7ty5+Hw+Zs2a1WTZxYsXs2DBAmbMmEFOTg7Lly9n8uTJPPvss/Ts2ROA8vJy+vTpw09+8hM6derEtm3bePDBB/nkk094+umnozpSUlISS5cujbpHXT0iIiIiIiJtTUObiHXq1IlNmzZFXu+9i3ddjOT3+xusc/jw4cybN48nnniCKVOm4PV6Oe+887jlllvIzMxstF63292sgdQOHTo0WW7nzp0xz5WWlobX691n3W1RXAH2ypUrqaqqYuHChZEPIxwOM2fOHPLz8+natWuD5fx+P4sWLWLy5MlMnDgRgCFDhjB69GiWLFnC7NmzgdpvP+p/AzJs2DC6devG5MmT+fTTTxk8eHDkmmmaB2V3PBERERERkdbQ0BnTu3btonPnzgdU78UXX8zFF19MSUkJf//737nrrruwLIv/+7//O6B6m6Nz584xz1VZWdnoFwJtXVxTxNeuXcvw4cOjvunIy8vDtm3WrVvXaLn169dTWVlJXl5eJM3j8XDuueeydu3aJu9Zd69gMBhPU0VERERERNqUiooK3nnnnajXb7/9NieddFKL1J+VlcVPfvITcnNzKSwsbJE692XAgAG8/vrr2LYdSXv11VcPyb1bQ1wj2IWFhfz4xz+OSktPT6dz585NfkB11/r06ROVnp2dzdKlS/H5fCQlJUXSw+Ew4XCYbdu2cffdd3PiiScyZMiQqLI+n4/TTjuN8vJyevfuzcSJE7n00kvjeRwREREREZGEkZmZya233sr1119Phw4dWLx4MY7jMGHChP2uc8GCBZSWlnLqqafSqVMn/vOf//Dmm29GZhYfbPn5+YwdO5Zp06Zx6aWXUlRUxKOPPorX68UwjEPShkMprgC7vLw8Zm4+QEZGBmVlZU2W83g8MfPs09PTcRyHsrKyqAD7F7/4BevXrwegf//+PPLII1jWnqb26tWLGTNmcMIJJ+D3+3n++ef5f//v/1FRUcGUKVPieaQojuNEnfWWKOo2ImhsQ4K2KhQOEQqFCAZDTWRyCIVDCfm5HO7aa7+Utkt9UhKN+qQkmvbWJ/1+P7ZtRwbnojgOjteL4ziHtE3G7nvGtKcZHMfhiCOO4Fe/+hV3330327Zto2/fvixevJiOHTsSDodxHCem/ro/170XdSPFda9PPPFEnnjiCV566SUqKyvp2rUrkyZN4uqrr46qpy5//fbsXX9T96lfrn4bc3JyuO+++7j//vu57rrrOPbYY/m///s/Jk6cSFpaWuQ++/u+tYS656mpqYkaaa/jOE6zvwwwnDh63YknnsgNN9zAVVddFZV+4YUXcvLJJzd6/tpDDz0U2aysvtWrV3PDDTewdu3aqPXbhYWFVFRUsHXrVhYvXgzAihUrSEtLa7Rt119/PW+//TbvvPMObre7uY8U8cknn7Tbs9gSkWVZZNCRr178Gn9F4++7t4OHY8/vRRnfxxxYLyIiIiKHN8uy6NmzZ8xAntvvg+qq1mlUSipBb9K+8+3ltttu4/PPP486Q7q9eu+997jmmmtYvHhxzEzl1uD3+9m2bVuT8YbH42HAgAH7rCuuEez09PSYA8mhdnfxjIyMJssFAgH8fn9U5y8vL8cwjJiydVPJTzrpJEaMGMFZZ53FU0891eTodF5eHmvWrOHrr78mOzs7nseKcLvd9O3bd7/KHkw1NTVs2bKF3r17k5yc3NrNaTH+nSE6ZVUR9Dbekd2pFhmZmXTpfMQhbJk0R3vtl9J2qU9KolGflETT3vqk3++nqKgIr9cbNRsWgKQkyMhslXYBuPanjMuFYRixz9IO3H777Zx22mlkZmayceNGHnroIfr168fw4cMxDCMSJ7bmlHHLsujVq1eDu5tv3Lix+fXEc9M+ffrErLWuqKhg586dMeur9y4HsHnzZo4//vhIemFhId27d2+yEx1xxBEceeSRbN26NZ6m7hfDMEhJSTno99lfycnJCd2+eIVd1bVT/92N/0WyLBeWy2pXz93etLd+KW2f+qQkGvVJSTTtpU+apolpmrhcLlyu/QlpE4thGBiG0S6eZW8VFRX89re/pbS0lLS0NM444wxuuukm3G53ZFp4az67y+XCNE2Sk5MbjE3jCfzjCrBHjhzJww8/HLUWe/Xq1ZimSW5ubqPlBg8eTFpaGi+99FIkwA4Gg7z88suMHDmyyXt+++23FBUV7fOM6xdffJH09HR69eoVzyOJiIiIiIi0urlz57Z2Ew6a++67r7WbcMjEFWCPHz+eZcuWMXXqVPLz8ykuLmbevHmMHz8+ag31hAkTKCoq4pVXXgHA6/WSn59PQUEBWVlZHHfccaxYsYLS0tKoad+zZs2iY8eODBgwgLS0NDZv3sxjjz1Gp06dGDt2bCTfmDFjuOSSS+jTpw8+n4/nn3+el19+mVtuuWW/1l+LiIiIiIiIHKi4AuyMjAyWLl3KHXfcwdSpU0lNTWXs2LFMnz49Kt/eO8kBXHnllTiOw6OPPkpJSQn9+vVjyZIlUSPTAwcOZNWqVTz55JMEAgG6devGyJEjufrqq+nYsWMkX69evXj88cf573//i2EYHHfccdx9991cdNFF+/MeiIiIiIiIiBywuAJsqD27+vHHH28yz7Jly2LSDMMgPz+f/Pz8RsuNHTs2aqS6MfPnz99nHhEREREREZFDyWztBoiIiIiIiIi0BwqwRURERERERFqAAmwRERERERGRFqAAW0REREREJAGVl5eTk5PDM888E1e5devW8cMf/pD+/fszdOjQg9S6xPfqq6+yfPnyQ3pPBdgiIiIiIiLtyM0338yRRx7J448/zmOPPdbazWk1r776KitWrDik94x7F3EREREREZGE5v8eAmWtc29PBng77jvfQVJVVUVxcTHXX3/9YT163VoUYIuIiIiISPsSKIOvX4JQ1aG9r5UKvfL2O8BetWoVDz/8MLt27WLQoEHMmDEjJs8zzzzDY489xpYtW8jMzGTMmDFcf/31uFwunnnmGW6++WYAbr31Vm699VZ+9KMfMXfuXB599FH+9re/sWXLFjweDwMHDmTmzJkcc8wxUfVv2LCBgoICPvzwQxzHoW/fvtx4443k5uYCEAgEWLhwIc8//zw7d+6kZ8+eXHvttfzwhz+M1DFz5kw+/fRTbrnlFu666y62bt3KwIEDmTt3Lmlpadx22228+eabZGVlceONN3LWWWdFteH111/n97//PV9++SUpKSmcd9553HTTTaSkpADw3nvvcfnll/Poo4/yzDPP8Nprr5GZmcnPfvYzrrzyykgb/vKXvwCQk5MDEHkvDiYF2CIiIiIi0v6EqiBY2dqtaLZ//OMf/L//9/8YM2YM559/Pp999hk33HBDVJ7HHnuMu+++mwkTJjBz5kw2bdrE/fffTzgcZsaMGYwaNYrHHnuMSZMmcc011zBq1CiysrIA2LFjB7/4xS/o3r07lZWVrFy5kvHjx7NmzRoyMzMB+Ne//sWECRMYNGgQd955J+np6Xz66acUFRVF2nDDDTewfv16pk6dSnZ2Nm+88Qa//vWvSU9P58wzz4zk27lzJ3PnzuWaa67BsizuvPNOZsyYQXJyMkOHDuXSSy9l1apV3HTTTfz1r3+lT58+AKxevZrp06czZswYpk2bxs6dO7n33nspLy/n/vvvj3o/brvtNi6++GJ+//vf8+qrr3LPPfeQk5PDyJEjufbaaykpKaGwsJB77rkHIPJeHEwKsEVERERERFrZQw89xNChQ7nrrrsAOOOMM/D7/Tz44IMAVFZWsmDBAq644gp++ctfApCbm4vb7Wbu3LlMmTKFrKws+vfvD0CvXr0YNGhQpP5bbrkl8udwOExubi7Dhw9nzZo1jBs3DoC7776bo48+mqVLl+JyuQA4/fTTI+XeffddXnvtNZYsWRJJz83NZefOnRQUFEQF2GVlZfzxj3/k2GOPBeC7777jjjvu4Morr2Tq1KkADBgwgFdeeYXXX3+dPn364DgO8+bN4/zzz+e3v/1tpK7OnTtz1VVXce2110bqA/jBD37AtGnTABg+fDivv/46a9asYeTIkfTq1YusrCyKioqi3oeDTZuciYiIiIiItKJwOMxnn33GueeeG5V+3nnnRf68YcMGqqurGT16NKFQKPIzYsQIfD4fX331VZP3+PDDD5k0aRLDhg3jhBNO4KSTTqK6upotW7YAUFNTw0cffcQll1wSCa73tm7dOjIzMznttNNi2vDFF18QDocjebt06RIVDPfu3RuAESNGRNLS09PJysqiuLgYgM2bN7N9+3by8vKi6j/11FMxTZNPP/00qj31g3/DMMjOzmbHjh1Nvg8Hm0awRUREREREWlFJSQmhUChmCvMRRxwR+fP3338P1K4jbsi3337baP1FRUVMnjyZ/v37M2fOHLp06YLb7SY/Px+/3w/UHglm2zZdunRptJ7vv/+e0tJSTjzxxAav79y5kyOPPBKoDZ7rc7vdAHTo0CEmva4Ndc9YN8K9r2dsqK6KiopG238oKMAWERERERFpRVlZWViWRUlJSVT6f//738ifMzIyAFi4cGEkiK2vR48ejdb/5ptvUl1dzcKFCyOBbygUoqxsz07rHTp0wDRNvvvuu0brycjIICsri0ceeaTR5zgQdWvBZ82axcCBA2OuNxX8JwoF2CIiIiIiIq3I5XJxwgkn8MorrzBx4sRI+po1ayJ/Pvnkk0lOTmbHjh0xU8n3xefzYRgGlrUn/HvppZcIhUKR1ykpKQwaNIhnn32WyZMnNzhNfMSIEfzhD3/A7XZz/PHHx9WG5ujTpw9HHnkk27Zt4+c///kB11d/dPxQUYAtIiIiIiLSyq6++mquvfZabr755sgu4s8++2zkenp6Otdffz133303O3bs4NRTT8XlcrFt2zb+/ve/U1BQQHJycoN1n3baaQDcfPPNjB8/nq+++orHHnssZhr3r371KyZOnMjEiRP52c9+RkZGBp999hkdO3Zk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+eabZGVl8ctf/pLzzz8fgNdff52lS5fy73//G7/fT3Z2NtOmTWPkyJGRuk3TjPx2uVxMmDCBLl26cPfddwPw6aef8uMf/5jzzjuPBQsWALWxWl5eHn/6058YOHAgGzZsYNGiRXz66adUVlZy9NFHM2nSJC655JLIfd577z0uv/xyFi1axDPPPMNbb73FKaecwqJFiygvL+e+++7j1VdfpbS0lOOOO45f/vKXDB8+PPLe7c/71hJcLhemaZKcnNxgbBpP4B9XgD1y5EgefvjhqLXYq1evxjRNcnNzGy03ePBg0tLSeOmllyIBdjAY5OWXX4764Bvy7bffUlRUFDkru64df//73/n1r38d+TbmxRdfJD09nZNPPjmeRxIREREREUkIO3fuZO7cuVxzzTVYlsWdd97JjBkzSE5OZujQoVx66aWsWrWKX//615x00kkcddRRfPPNN5x11llMnjwZ0zRZu3YtV111FUuXLmXYsGEN3ueUU07h6aefjrx+//338Xq9/Otf/4pKS0lJ4cQTTwSgqKiIwYMH89Of/hSPx8P69ev5zW9+g+M4/OhHP4qq///9v//HRRddxO9//3tM0yQQCDBp0iR27drFjTfeSNeuXXnuuefIz8/nz3/+M7169ToI72briCvAHj9+PMuWLWPq1Knk5+dTXFzMvHnzGD9+fNQZ2BMmTKCoqIhXXnkFAK/XS35+PgUFBWRlZXHcccexYsUKSktLmTJlSqTcrFmz6NixIwMGDCAtLY3Nmzfz2GOP0alTJ8aOHRvJN2XKFJ5//nl+9atf8dOf/pT//Oc/LFmyhOnTp+sM7ARgV5RDVWXTmUwTp8bCqarCqdp9BJvHg+GJnZIhIiIiInI4KCsr449//CPHHnssAN999x133HEHV155JVOnTgVgwIABvPLKK7z66qtMmDCBX/ziF5Hytm0zbNgwNm7cyKpVqxoNsIcOHUpBQQHbt2/nqKOO4v333+fHP/4xK1euZNOmTWRnZ/P+++8zePDgyKjyBRdcECnvOA6nnHIKxcXFPPXUUzEB9tlnn82vf/3ryOunn36af//73zz77LORJblnnHEGW7du5aGHHuKuu+5qgXcvMcQVYGdkZLB06VLuuOMOpk6dSmpqKmPHjmX69OlR+ep286vvyiuvxHEcHn30UUpKSujXrx9LliyJGpkeOHAgq1at4sknnyQQCNCtWzdGjhzJ1VdfHbXb3dFHH82SJUuYO3cuV111FVlZWVx//fVMnjx5f94DaWlVlYT/+Q6Or4kdKpOScbKOw/nma+xyH1huzKN6gAJsERERETlMdenSJRJcA/Tu3RuAESNGRNLS09PJyspix44dAOzYsYP777+ft99+m507d0Z25a4beW7IoEGDcLvdvP/++3Tv3p1//etf3HvvvWzYsIH333+f7Oxs/vWvf3HppZdGypSVlVFQUMDf//53iouLI/FeZmZmTP2jRo2Ker1u3TqOO+44evfuHbVx8YgRI3juueea9+a0EXHvIp6dnc3jjz/eZJ5ly5bFpBmGQX5+Pvn5+Y2WGzt2bNRIdVMGDx7MqlWrmpVXDj3HVwP7OgIiHIZwCLQ7uIiIiIhIzFHEdcth6zZ6ruPxeCLHlF1zzTVUVFRw/fXXc/TRR5OcnMyCBQv49ttvG71PUlISAwYM4IMPPuCEE06gsrKSk08+maFDh/L+++9z+umnU1RUxCmnnBIpM3PmTDZs2MDUqVPp27cvaWlprFixgpdeeimm/k6dOkW9/v777/n8888bDPpba931wZKQx3SJiIiIiIhI07Zu3crnn3/O73//e/7nf/4nkt6co7hOOeUU1qxZQ79+/ejXrx+pqamccsop/Pa3v+WDDz7A4/EwcOBAoHbH9tdff52ZM2dy2WWXRep48sknG6x7703BMjIyyMnJ4be//W1M3obOnW7LFGCLiIiIiIi0QXVnR9eNdANs376dDRs2RKaXN2bo0KEsWrSI1atXR0aq69ZVP/300wwcODCyv1UgEMC27aj7VFZW8tprrzWrnSNGjOCNN96gS5cuUXt3AYTD4YQ9m3t/KMAWERERERFpg/r06cORRx7Jvffei23bVFdXs2DBArp06bLPsnUbmP3zn/9k0qRJAGRlZZGdnc0///lPrr766kjeDh06MGDAABYvXkxWVhaWZfHII4+QlpZGSUnJPu91ySWXsHLlSi6//HImT55M7969qaio4PPPP8fv93Pttdfu/5uQYBRgi4iIiIhIu+NOPvShzqG+p8fjoaCggNtvv50bbriBbt26cc011/Duu+/y6aefNlk2LS2Nfv368fnnnzNkyJBI+imnnMKmTZui1l8D3HvvvcyaNYuZM2eSmZnJZZddRnV1NY8++miz2vnEE09QUFDAww8/zM6dO8nMzOSEE05g/Pjx+/fwCcpw6raZO8x98sknQO2294mmurqaL774gn79+pGSktLazdkne0cRobWvNb3JWXIyNV37s/m5QoJlPrAszKOPwUiL3sDBSnFxzHlH0aFH4j/34aat9Utp/9QnJdGoT0qiaW990ufzsXnzZo455hiSkpKirvnLAgQqWmcjXU8HC2+Gjg5urrop4klJSa224VlTfQniixU1gi0iIiIiIu2KN8OjIFdahdnaDRARERERERFpDxRgi4iIiIiIiLQABdgiIiIiIiIiLUABtoiIiIiIiEgLUIAtIiIiIiJtlg5FkgPVkn1IAbaIiIiIiLQ5brcbqD1+TORA1PWhuj51IHRMl4iIiIiItDkul4vMzEy+++47AFJSUjAMo5VbJfEKh8P4/X6AQ34OtuM4VFdX891335GZmdki91eALSIiIiIibdKRRx4JEAmype2xbZtQKIRlWZhm60ywzszMjPSlA6UAW0RERERE2iTDMOjWrRtdunQhGAy2dnNkP9TU1FBYWEivXr1ITk4+5Pd3u90tOnKuAFtERERERNo0l8t1yKcXS8uwbRsAr9dLUlJSK7fmwGmTMxEREREREZEWoABbREREREREpAUowBYRERERERFpAQqwRURERERERFqAAmwRERERERGRFqAAW0RERERERKQFxB1gb9q0iUmTJjFo0CByc3OZN28egUBgn+Ucx+GRRx5h1KhRDBw4kHHjxvHhhx9G5Xn77beZPn06Z599NieddBLnn38+f/jDH2LOtJs5cyY5OTkxP2vXro33cURERERERERaRFznYJeVlTFhwgR69+5NQUEBxcXFzJ07F5/Px6xZs5osu3jxYhYsWMCMGTPIyclh+fLlTJ48mWeffZaePXsCsHLlSnw+H9dffz3dunXjo48+oqCggE2bNnHXXXdF1dezZ0/uueeeqLTs7Ox4HkdERERERESkxcQVYK9cuZKqqioWLlxIZmYmAOFwmDlz5pCfn0/Xrl0bLOf3+1m0aBGTJ09m4sSJAAwZMoTRo0ezZMkSZs+eDcDs2bPJysqKlBs2bBi2bTN//nx+/etfR11LSkpi0KBB8TRfRERERERE5KCJa4r42rVrGT58eCS4BsjLy8O2bdatW9doufXr11NZWUleXl4kzePxcO6550ZN664fQNfp168fjuOwc+fOeJoqIiIiIiIickjFFWAXFhbSp0+fqLT09HQ6d+5MYWFhk+WAmLLZ2dkUFRXh8/kaLbt+/Xo8Hg89evSISt+6dStDhgyhf//+jBkzhldffTWeRxERERERERFpUXFNES8vLyc9PT0mPSMjg7KysibLeTwevF5vVHp6ejqO41BWVkZSUlJMuS1btvDEE08wfvx4UlNTI+n9+vVjwIAB9O3bl4qKClasWMHUqVN54IEHGD16dDyPFMVxHKqrq/e7/MFSU1MT9TvRWaEwoWAIZ6/N6eozLDe2bRMO24TDYQzTBNvG3rtMyCEUDiXk53K4a2v9Uto/9UlJNOqTkmjUJyURtYV+6TgOhmE0K29cAfahVFlZybRp0+jRowfTp0+PujZhwoSo12effTbjx49nwYIFBxRgB4NBvvjii/0uf7Bt2bKltZuwT5Zl0d0y8ZfsIlxV2Wg+V2oariwfNTU1BKqrMT0eXH4fFTU12LYdyef1e8gqTaWs9HtCodCheASJU1vol3J4UZ+URKM+KYlGfVISUaL3S4/H06x8cQXY6enpVFRUxKSXlZWRkZHRZLlAIIDf748axS4vL8cwjJiygUCAqVOnUlZWxlNPPUVKSkqT7TJNkx/84Afcfffd+Hy+BkfDm8PtdtO3b9/9Knsw1dTUsGXLFnr37k1ycnJrN2efrJJdhLI64TTRViM5BX9SEsnJyVgBMNxuTG8SnuToz9qdapGRmUmXzkcc7GZLnNpav5T2T31SEo36pCQa9UlJRG2hX27cuLHZeeMKsPv06ROz1rqiooKdO3fGrK/euxzA5s2bOf744yPphYWFdO/ePSogtm2bGTNm8Nlnn7F8+XK6desWTxMPiGEY+wzmW1NycnJCt6+OXV4KbgtC7sYzuS2CponLZWK7XGCamKaJyx1dxrJcWC6rTTz34aqt9Es5fKhPSqJRn5REoz4piSiR+2Vzp4dDnJucjRw5krfffpvy8vJI2urVqzFNk9zc3EbLDR48mLS0NF566aVIWjAY5OWXX2bkyJFReefMmcM//vEPHnzwQXJycprVLtu2Wb16Nccee+x+j16LiIiIiIiIHIi4RrDHjx/PsmXLmDp1Kvn5+RQXFzNv3jzGjx8fdQb2hAkTKCoq4pVXXgHA6/WSn59PQUEBWVlZHHfccaxYsYLS0lKmTJkSKffwww+zcuVKpkyZgsfj4cMPP4xc69u3L2lpaWzfvp2ZM2dywQUXcPTRR1NWVsaKFSv49NNPKSgoOMC3Q0RERERERGT/xBVgZ2RksHTpUu644w6mTp1KamoqY8eOjdmErHZ36HBU2pVXXonjODz66KOUlJTQr18/lixZQs+ePSN56s7SXrJkCUuWLIkq/8QTTzBs2DBSU1NJS0vjoYceYteuXbjdbvr378/ixYs544wz4np4ERERERERkZYS9y7i2dnZPP74403mWbZsWUyaYRjk5+eTn58fV7m9ZWZm8tBDD+0zn4iIiIiIiMihFNcabBERERERERFpmAJsERERERERkRagAFtERERERESkBSjAFhEREREREWkBCrBFREREREREWoACbBEREREREZEWoABbREREREREpAUowBYRERERERFpAQqwRURERERERFqAAmwRERERERGRFqAAW0RERERERKQFKMAWERERERERaQEKsEVERERERERagAJsERERERERkRagAFtERERERESkBSjAFhEREREREWkBCrBFREREREREWoACbBEREREREZEWoABbREREREREpAUowBYRERERERFpAQqwRURERERERFpA3AH2pk2bmDRpEoMGDSI3N5d58+YRCAT2Wc5xHB555BFGjRrFwIEDGTduHB9++GFUnrfffpvp06dz9tlnc9JJJ3H++efzhz/8gWAwGFPfa6+9xkUXXcSAAQM477zzePrpp+N9FBEREREREZEWE1eAXVZWxoQJEwgGgxQUFDB9+nRWrVrF3Llz91l28eLFLFiwgIkTJ7Jo0SI6d+7M5MmT2bZtWyTPypUrqaqq4vrrr+eRRx7hkksuoaCggFmzZkXV9cEHH3DdddcxaNAgFi9eTF5eHrfeeiurV6+O53FEREREREREWowVT+a6AHjhwoVkZmYCEA6HmTNnDvn5+XTt2rXBcn6/n0WLFjF58mQmTpwIwJAhQxg9ejRLlixh9uzZAMyePZusrKxIuWHDhmHbNvPnz+fXv/515NpDDz3EwIEDuf322wE47bTT2LZtGwsWLGD06NHxPJKIiIiIiIhIi4hrBHvt2rUMHz48ElwD5OXlYds269ata7Tc+vXrqaysJC8vL5Lm8Xg499xzWbt2bSStfnBdp1+/fjiOw86dOwEIBAK89957MYH0+eefz6ZNm/jmm2/ieSQRERERERGRFhFXgF1Y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iIiItA8KsOWgCFb48JdWx6SHDReW24AUu4FSIiIiIiIibZe57ywiIiIiIiIisi8KsEVERERERERagAJsERERERERkRagAFtERERERESkBSjAFhEREREREWkBCrBFREREREREWoACbBEREREREZEWoABbREREREREpAUowBYRERERERFpAQqwRURERERERFqA1doNEDlQhmFiGeAyXSS5vJH0JJcXl+GqfeH/HgJljVfiyQBvx4PcUvCXBQhUhJrMY5gQDoYPeltERERERKRlKcCWNs1wuUhyJeGxbbIcL6l2J8J2EAA3blJKyqgurcRjluNsfRGClQA4lkXIZeAAhjsNo1celeEwtmMDkOpOIc2T1uLtDVSE+GZtMcGaxoPs5I5eOvXPPIC7GAdQVkRERERE9pcCbGnTDNOFEQoR3vEtwW9dVG9/i1B1bRCdZHqoTu5EKX469TuG8H/ew64uwbQ8uHr04r9mDSE7jOXJxNN5KJ+VbsEX9pPk8jKk65CDEmADBGtChKobH6EOJjc9wt0k0wM4ULGl6XyHaMReRERERORwogBb2gUnGMQJBQhVVxKqKgcg5PJik4SfKsIhP6GADztQg+nYmI5NyA4TskPghHDZYXxhP76Qr5Wf5ACZ7tpR+m/fhFBVw3msVOiVpwBbRERERKSFKcAWaY9CVZHp8CIiIiIicmgowBZpAdq8TEREREREFGAfJuyKcqiKY0TTNHGCwYPXoHbm0GxeJiIiIiIiiUwB9uGiqpLwP9/B8dU0K7uR0RHzuOMPcqNaiGFguN0YlgcrZc/GZJbpwUxOxcLAMF0HvRkHdfMyERERERFJeHEH2Js2beLOO+9kw4YNpKamcvHFF3PjjTfi8XiaLOc4DosXL+bJJ5+kpKSEfv36cfPNNzNo0KBInpKSEh588EE++ugjvvjiC9xuNxs2bGiwvtdee4358+ezefNmunfvzlVXXcWPf/zjeB/nsOL4aqCmeQG2k5R8kFvTMgyXC8vjwsrKJDUrk7TM43GCtRuVuYzaI7xchkNSRgfKXfo+SUREREREDh4znsxlZWVMmDCBYDBIQUEB06dPZ9WqVcydO3efZRcvXsyCBQuYOHEiixYtonPnzkyePJlt27ZF8hQXF/Piiy/SqVMn+vfv32hdH3zwAddddx2DBg1i8eLF5OXlceutt7J69ep4HkfaAcM0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iOpl586d0Ov1+Pbbb2+rnLfffhuTJ0+u1z45OTnQ6/X44IMPbuvYDem5557DihUrmroaRETUDDDAJiKiFi0xMRF6vR55eXkO00eOHImJEyfKr20BnO2na9euCA0NxdSpU5GRkVHv8m9Fr9fj3Xffrfd+jWXz5s3YuXPnHSn78uXL+PjjjzFjxow7Un5jmjZtGrZs2YLr1683dVWIiKiJMcAmIiJyYOTIkVixYgWWLVuG559/HmfPnkVsbCx+/vnnpq5ao0lNTcUnn3xyR8retGkTOnbsiD59+tyR8hvTwIED4ebmhi1btjR1VYiIqIkxwCYiInKgW7duiImJwdNPP424uDisWrUKRqMRqampTV21u57JZMJnn32G6Ojopq5KjcrKyuqcV6VSYejQodi9ezckSbqDtSIiouaOATYREVEdPPbYYwCsQ5sbkyiK2LBhA0aMGIHg4GD07dsXS5YsQWFhoSLfgAEDMGPGDJw6dQpjxoxBcHAwBg4ciF27dtmV+dNPP2HChAl4+OGHERUVhaSkJOzYsQN6vR45OTlyeb/++iu+/vprebh81aH0AGA0GrFs2TL06dMHISEhmDVrVp2Gyp8+fRr5+fno27evXVpFRQUSExMxdOhQBAcHIzIyErNnz0Z2drZd3q1bt2LQoEHo0aMHnnnmGZw7d87uPBcuXIiBAwciODgYERERWLRoEfLz8xX5bMP8z58/j9deew29e/fGCy+8AAC4fv06Fi1ahKioKPTo0QORkZGYOXOmfJ1s+vbti9zcXPz444+1nj8REbVcmqauABER0d0gNzcXAODu7t6ox12yZAk++eQTjB49GhMnTkROTg42b96MH374AampqdBqtXLeS5cuYe7cuRgzZgyefvpp7NixAwsXLkT37t3x0EMPAQCuXbuGF198EQAwffp0uLq6Yvv27dDpdIrjLl68GEuXLoWrqytefvllAMB9992nyBMfHw93d3fMnj0bubm52LhxI959910kJCTc8pwyMjIgCAK6deum2G6xWDBjxgykp6djxIgRiI2NRWlpKY4fP45ffvkFfn5+ct49e/agtLQUY8eOhSAIWLduHebMmYODBw/K1+TEiRO4fPkyRo8eDW9vb/z666/Ytm0bzp8/j23btkEQBMXx586di86dOyMuLk7uiZ4zZw7Onz+PCRMmoGPHjsjLy8Px48fx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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " mean 50% max\n", + "type \n", + "benign 57.7000 46.0000 2175.0000\n", + "defacement 86.3000 81.0000 327.0000\n", + "malware 56.5000 49.0000 378.0000\n", + "phishing 45.9000 35.0000 1779.0000\n" + ] + } + ], + "source": [ + "# ─── URL length distribution by class ───────────────────────────────────────\n", + "df_raw['url_len'] = df_raw['url'].astype(str).str.len()\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 4))\n", + "for cls, color in zip(['benign','phishing','defacement','malware'], colors4):\n", + " data = df_raw.loc[df_raw['type']==cls, 'url_len'].clip(0, 500)\n", + " ax.hist(data, bins=60, alpha=0.5, color=color, label=cls, density=True)\n", + "ax.set_xlabel('URL Length (chars)')\n", + "ax.set_title('URL Length Distribution by Class')\n", + "ax.legend()\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'eda_url_length_by_class.png', dpi=150)\n", + "plt.show()\n", + "\n", + "print(df_raw.groupby('type')['url_len'].describe()[['mean','50%','max']].round(1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Feature Engineering\n", + "\n", + "We extract **54 hand-crafted features** across 8 categories:\n", + "- Length & structural (7)\n", + "- Character counts (14)\n", + "- Character ratios (5)\n", + "- Entropy / randomness (2)\n", + "- Boolean indicators (10)\n", + "- Domain / TLD signals (6)\n", + "- Suspicious patterns (5)\n", + "- Path & query analysis (5)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Extracting features from 651K URLs …\n", + " Extracting features for 651,191 URLs (n_jobs=-1) …\n", + " β†’ 651,191 rows Γ— 54 features\n", + "\n", + "βœ… 651,191 rows Γ— 56 cols\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
urlurl_lengthhostname_lengthdomain_lengthpath_lengthquery_lengthfragment_lengthtld_lengthnum_dotsnum_hyphensnum_underscoresnum_slashesnum_at_signsnum_ampersandsnum_equals...domain_token_counthas_suspicious_tlddomain_has_digitsdomain_hyphen_countphishing_keyword_countbrand_counthas_suspicious_extbrand_in_subdomainsuspicious_word_ratiopath_depthlongest_path_tokenavg_path_token_lenmax_consecutive_digitspath_entropylabel
0br-icloud.com.br16.000016.00009.00000.00000.00000.00006.00002.00001.00000.00000.00000.00000.00000.0000...4.00000.00000.00001.00001.00000.00000.00000.00000.25000.00000.00000.00000.00000.0000phishing
1mp3raid.com/music/krizz_kaliko.html35.000011.00007.000024.00000.00000.00003.00002.00000.00001.00002.00000.00000.00000.0000...2.00000.00001.00000.00000.00000.00000.00000.00000.00002.000017.000011.00001.00003.8554benign
2bopsecrets.org/rexroth/cr/1.htm31.000014.000010.000017.00000.00000.00003.00002.00000.00000.00003.00000.00000.00000.0000...2.00000.00000.00000.00000.00000.00000.00000.00000.00003.00007.00004.66671.00003.2928benign
\n", + "

3 rows Γ— 56 columns

\n", + "
" + ], + "text/plain": [ + " url url_length hostname_length \\\n", + "0 br-icloud.com.br 16.0000 16.0000 \n", + "1 mp3raid.com/music/krizz_kaliko.html 35.0000 11.0000 \n", + "2 bopsecrets.org/rexroth/cr/1.htm 31.0000 14.0000 \n", + "\n", + " domain_length path_length query_length fragment_length tld_length \\\n", + "0 9.0000 0.0000 0.0000 0.0000 6.0000 \n", + "1 7.0000 24.0000 0.0000 0.0000 3.0000 \n", + "2 10.0000 17.0000 0.0000 0.0000 3.0000 \n", + "\n", + " num_dots num_hyphens num_underscores num_slashes num_at_signs \\\n", + "0 2.0000 1.0000 0.0000 0.0000 0.0000 \n", + "1 2.0000 0.0000 1.0000 2.0000 0.0000 \n", + "2 2.0000 0.0000 0.0000 3.0000 0.0000 \n", + "\n", + " num_ampersands num_equals ... domain_token_count has_suspicious_tld \\\n", + "0 0.0000 0.0000 ... 4.0000 0.0000 \n", + "1 0.0000 0.0000 ... 2.0000 0.0000 \n", + "2 0.0000 0.0000 ... 2.0000 0.0000 \n", + "\n", + " domain_has_digits domain_hyphen_count phishing_keyword_count \\\n", + "0 0.0000 1.0000 1.0000 \n", + "1 1.0000 0.0000 0.0000 \n", + "2 0.0000 0.0000 0.0000 \n", + "\n", + " brand_count has_suspicious_ext brand_in_subdomain suspicious_word_ratio \\\n", + "0 0.0000 0.0000 0.0000 0.2500 \n", + "1 0.0000 0.0000 0.0000 0.0000 \n", + "2 0.0000 0.0000 0.0000 0.0000 \n", + "\n", + " path_depth longest_path_token avg_path_token_len max_consecutive_digits \\\n", + "0 0.0000 0.0000 0.0000 0.0000 \n", + "1 2.0000 17.0000 11.0000 1.0000 \n", + "2 3.0000 7.0000 4.6667 1.0000 \n", + "\n", + " path_entropy label \n", + "0 0.0000 phishing \n", + "1 3.8554 benign \n", + "2 3.2928 benign \n", + "\n", + "[3 rows x 56 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from feature_engineering import URLFeatureExtractor, featurize_dataset\n", + "\n", + "print('Extracting features from 651K URLs …')\n", + "df = featurize_dataset(str(csv_path), url_col='url', label_col='type')\n", + "print(f'\\n\\u2705 {df.shape[0]:,} rows \\u00d7 {df.shape[1]} cols')\n", + "df.head(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Total features: 54\n", + "['url_length', 'hostname_length', 'domain_length', 'path_length', 'query_length', 'fragment_length', 'tld_length', 'num_dots', 'num_hyphens', 'num_underscores', 'num_slashes', 'num_at_signs', 'num_ampersands', 'num_equals', 'num_question_marks', 'num_percent', 'num_tilde', 'num_digits', 'num_letters', 'num_special', 'num_params', 'digit_ratio', 'letter_ratio', 'special_ratio', 'uppercase_ratio', 'digit_letter_ratio', 'url_entropy', 'domain_entropy', 'has_ip', 'has_https', 'has_http', 'has_www', 'has_port', 'has_at_symbol', 'is_shortened', 'has_double_slash_redirect', 'has_punycode', 'has_hex_encoding', 'num_subdomains', 'subdomain_length', 'domain_token_count', 'has_suspicious_tld', 'domain_has_digits', 'domain_hyphen_count', 'phishing_keyword_count', 'brand_count', 'has_suspicious_ext', 'brand_in_subdomain', 'suspicious_word_ratio', 'path_depth', 'longest_path_token', 'avg_path_token_len', 'max_consecutive_digits', 'path_entropy']\n" + ] + } + ], + "source": [ + "feat_names = URLFeatureExtractor.feature_names()\n", + "print(f'Total features: {len(feat_names)}')\n", + "print(feat_names)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Top 15 features correlated with maliciousness:\n", + "has_www 0.5390\n", + "has_suspicious_ext 0.2746\n", + "num_params 0.2723\n", + "num_ampersands 0.2635\n", + "num_equals 0.2568\n", + "num_dots 0.2388\n", + "domain_token_count 0.2276\n", + "has_ip 0.1897\n", + "has_https 0.1764\n", + "has_http 0.1763\n", + "path_length 0.1741\n", + "longest_path_token 0.1697\n", + "num_subdomains 0.1614\n", + "domain_has_digits 0.1576\n", + "query_length 0.1567\n" + ] + } + ], + "source": [ + "# ─── Top features correlated with malicious label (binary) ──────────────\n", + "df['is_malicious'] = (df['label'] != 'benign').astype(int)\n", + "\n", + "feat_corr = df[feat_names].corrwith(df['is_malicious']).abs().sort_values(ascending=False)\n", + "print('Top 15 features correlated with maliciousness:')\n", + "print(feat_corr.head(15).to_string())" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABisAAALMCAYAAACVNoGQAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3hUZdrH8d/UZFKoYhSCEkBDkRJagBWVgNIXFVFUQHdRRAx2VtQX2+LqqtgAWUFEUXRFwQYRVERUFBBUFI1KgCAEKSIJ6dPO+wdmljEBMpOQyUy+n+vyinPqfZ8w58k59znPYzIMwxAAAAAAAAAAAECImEMdAAAAAAAAAAAAqNsoVgAAAAAAAAAAgJCiWAEAAAAAAAAAAEKKYgUAAAAAAAAAAAgpihUAAAAAAAAAACCkKFYAAAAAAAAAAICQolgBAAAAAAAAAABCimIFAAAAAAAAAAAIKYoVAAAAAAAAAAAgpChWAAAAoNZZsmSJkpOTtWTJkpDsf926dUpOTtaMGTP8po8ZM0bJyckhialMqI9NXTRjxgwlJydr3bp1oQ6lTqroe3e072hVtwsAAIDQsYY6AAAAgNrmeDevHnroIV188cU1FkuPHj300ksv1cj+qtOUKVP05ptv+j6bzWbFxMSoYcOGOvPMM9W7d28NGTJEDRs2rPZ9z5gxQzNnztSCBQuUmppa7ds/kdatW6exY8cqPT1dkyZNCnU4NaYs7z+Ljo5WYmKi+vbtq2uuuUYNGjSo+eAg6XCh7M4775QkdevWTQsXLqxwuV27dql///4yDEOS9NNPP9VYjAAAAAhfFCsAAACOIj09vcLpbdu2reFIwlu/fv18x6ywsFC//vqrNm7cqJUrV+qJJ57Q3XffXa74c/7556tTp046+eSTQxGyOnbsqIyMjBNSSKmqUB+bE61Zs2a66KKLJEmGYejgwYP69NNPNXfuXH3wwQdasmSJYmNjazSmK6+8UoMHD1bTpk1rdL+1ldVq1YYNG7Rt2za1bNmy3PzXX39dhmHIarXK7XafkBiq4zv673//W8XFxdUYFQAAAKqCYgUAAMBR1KWn2k+k/v37lytGuN1uLV68WA8++KDuvPNO2e12DR061Dc/Pj5e8fHxNR2qj8PhUKtWrUK2/2MJ9bE50Zo1a1buu+d0OjVq1Ch9//33WrFiRY292VSmUaNGatSoUY3uszY777zz9OGHH+r111/XHXfc4TfP4/FoyZIl6tChg/bt26e9e/eekBiq4ztK8QkAAKB2YcwKAACAKsjNzdX06dM1aNAgdezYUV27dtVVV12lzz77rNyy+fn5eu655zR27Fidc845Ouuss9SzZ09NmDBBX3/9td+yZeMSSNL69euVnJzs+6+sj/bj9dmelpamtLS0Cre7ZMkSffLJJxozZoy6du3q1/WV2+3WwoULdemll6pLly7q1KmTLrzwQr388svyer1VOl5lrFarLrvsMt17772SpIcfflglJSUVxnmkH3/8UbfeeqvS0tJ8x++iiy7Sgw8+KJfL5ct75syZkqSxY8f6HbsyU6ZMUXJysnbu3KmXXnpJw4YNU8eOHTVmzBhJxz+2TqdTTzzxhC+O/v37a+bMmXI6nX7L7dq1S8nJyZoyZUqF2/lzn/lTpkzxdYU0c+ZMv9jLxks41pgVmzdv1qRJk9SrVy+dddZZ6tu3r+677z7t27ev3LJlx2DXrl3673//q2HDhqlDhw7q3bu3pk6dqvz8/HLrVOb4nwh2u109evSQJP3+++/l5hcXF+vZZ5/V8OHD1blzZ6WkpOiyyy7T0qVLyy175O82MzNT48ePV7du3dSpUyeNHj1aX331Vbl1jjVmxTvvvKOLLrpIHTt2VK9evTR58mTt3bv3uOMsVHbfFfnmm2+UnJysG2644ajLDBo0SGeddZZyc3MlHX5L5c0339SoUaPUs2dPdejQQeeee67GjRunjIyMSu23TOvWrZWSkqK33nqr3O/9448/1r59+3TppZcedf0lS5Zo0qRJ6tevnzp27KguXbpo1KhRevvttysdw7G+o7m5uXriiSc0dOhQderUSV27dtVf//pXPfbYYyoqKvItd7QxK7xer1599VWNGDFCKSkp6ty5s0aMGKFXXnml3Dkw0O+4VL2/CwAAgEjCmxUAAABBysnJ0ZgxY5STk6Nu3bqpT58+Ki4u1qpVq3TNNdfogQce8Ltht3XrVj355JPq1q2bzjvvPNWrV0+//vqrPvroI3366aeaPXu2zjnnHEmHu5pKT0/XzJkz/brFkeS7aVsVK1as0KeffqpzzjlHo0aN0u7duyVJLpdLEyZM0GeffaakpCQNHTpUUVFRWrdunf75z39q06ZNevTRR6u8/zIXXXSRZs2apZycHK1du1bnnXfeUZf98ccfdemll8pkMiktLU2JiYkqKCjQL7/8oldffVU333yzbDabxo4dq5UrV2r9+vW66KKL1KxZs6Nu88EHH9SGDRt07rnn6txzz5XFYqlU3DfddJO+++47DRw4UFarVStXrtSMGTO0efNmzZ49WyaTKdBDIenwWyiS9Oabb6pHjx5+v+tj5SFJq1at8r2RMGDAADVt2lTff/+9Xn31Va1cuVKvvPKKmjdvXm69Rx99VJ999pn69u2rv/zlL1q3bp0WLVqkHTt2aMGCBb7lKnv8y5TdoK2O8QpcLpfWr18vSTrrrLP85h06dEhXXXWVfvjhB7Vv314jRoyQ1+vVZ599pttuu01btmzRLbfcUm6bmzdv1nPPPafOnTtr5MiR2r17t95//31dffXVeuuttyrs3ujP5s6dq8cee0z169fXhRdeqPj4eH3++ee6/PLLj/n2S1X33blzZyUlJWn16tU6ePBgua6Qvv32W23btk0DBgzwjfHxxBNP6Nlnn1ViYqIGDRqk+Ph47d+/X999952WL1+uwYMHHzffI40cOVJ33XWXVq5cqYEDB/qmv/7664qJidGQIUN8RcM/u++++9S6dWt1795dTZo0UW5urlavXq1//OMf2r59u26++eaAYjnSzp07ddVVVyknJ0ft27fX5ZdfLq/Xq+zsbL3wwgsaNWqUYmJijrmNyZMna+nSpTr11FN1ySWXyGQy6cMPP9T999+vjRs3avr06UHHJ1X/7wIAACBSUKwAAAA4ioqe2G3WrJmvC5opU6Zo9+7devzxxzVkyBDfMocOHdKYMWM0bdo0paWl6aSTTpIktWrVSp988km57mT27NmjSy65RA899JBfsaJt27a+YkV1d0m1evVqzZkzx7e/Mv/5z3/02WefafTo0brrrrt8N+89Ho+mTp2qxYsXa8CAAb6b6lVlNpvVtWtX5eTk6Ntvvz1mseKtt95SaWmpZs2aVW7/eXl5cjgckqSrr75a+fn5vmLFsQbY/v777/Xmm29WeBP/WLZt26Zly5apfv36kqRbbrlFY8eO1apVq/T222/rwgsvDGh7Zfr376/4+HhfsaKyv/fCwkJNmTJFHo9HL730krp16+abN2fOHE2fPl333nuvnn/++XLrbtq0Se+++66vSxy3262rrrpK69at07fffquOHTtKqvzxr6qcnBzfd88w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0vTp03XVVVfp7rvv1ksvvaROnTopPj5ee/bs0c8//6yff/5Zr732mho3bizpcFc19957ry666CJdcMEFslqt+uqrr7R161b17dtXq1atKrePXr16admyZZowYYLatWvnGyy5e/fustlsGjt2rJ555hldeOGFOv/88+V2u/X555/r5JNP1sknnxxwThMnTtSPP/6o//73v1q1apV69uyphIQEHThwQDt27NBXX32lW265xTeYb2V8+OGHvr77i4qK9Ouvv2rDhg3av3+/4uPj9cADD2jw4MHH3c5zzz2ntWvXqlu3bkpMTFRMTIyysrL0ySefqH79+rrssst8y/bs2VNms1mPP/64tmzZ4nv6eeLEiQEekYq1bNlSQ4YM0cCBA2W1WrVy5Ur98ssvOu+88zR8+HC/ZceNG6e7775bl19+uQYOHKioqCitW7dOLpdLbdq00Y8//ui3fFJSkhISErRs2TJZrVY1bdpUJpNJw4cP993o/bPY2Fg9+OCDuvnmmzV69GgNHDhQTZs21ffff6/PPvtMTZo00QMPPFClnAM5/pJ8v9NjDVRfkZycHL/BsvPy8vTVV1/p+++/V3R0tO655x6/5e+55x7t2LFDTz/9tN555x116dJFJ510kvbt26etW7fqu+++0+OPP67mzZsHmXnFTjvtNN144416/PHHNXz4cA0aNEjx8fH6/PPPlZubqzZt2gScezC6du2q008/XStWrJDL5VLfvn1955wyJSUluuKKK3T66aerffv2atq0qUpLS/X5559r69atSktLC3pAdEnq1q1bpZe94oortGTJEt10000aMGCATj75ZG3ZskWffvqpBg0apIyMjKDjkKRHH31UY8eO1eOPP64VK1YoNTVVhmEoOztba9as0XvvvafExMSjrj9s2DCtXLlS7733noYMGaL+/fvLZDLpww8/1K5duzR48OByXV0F8h0/0b8LAACAcEaxAgAAIEinnHKKFi9erJdfflnvv/++3n33XXk8Hp100klq3bq1Ro8erTPPPNO3/KhRo2S32/Xiiy/qrbfeUlRUlLp166aHHnpI77//foXFirvvvlsmk0lffPGFVq9eLa/Xq/T0dHXv3l2SdOONN8rhcGjRokVatGiRTjrpJA0ePFiTJk3SkCFDAs7JZrPpmWee0dtvv60333xTH3/8sYqKitSwYUMlJibqpptuKvfU9vGsXLlSK1eulNlslsPhUKNGjdSxY0f17t1bQ4cO9b1JcDxXXHGF6tevr02bNvm6XEpISNAVV1yhv/3tb3438lu1aqWHH35Yzz//vF555RXf09TVVax46qmnNGvWLL377rvat2+fEhISNGnSJI0fP77cOBiXXHKJDMPQCy+8oDfffFP169dXv379dMstt+jGG28st22LxaKZM2dq+vTpWr58uQoLC2UYhrp27XrUYoV0+O2KV155Rc8++6w+++wzFRQU6KSTTtKoUaM0ceLEKg06LAV2/KsiJyfHb8wUm82mhIQEXXLJJRo3bpxatmzpt3xcXJxeeuklLVq0SEuXLtX777+v0tJSnXTSSTr99NN15513nrCxNK677jolJCTohRde0JIlSxQbG6uzzz5bkydP1rhx4/zGNjiRLrzwQj311FOSyg+sLR1+Uv/222/XunXr9PXXX+vDDz9UbGysTjvtNN13331+bwOdaG3atNGCBQv05JNPavXq1XK73WrTpo1mzpyp+Pj4KhcrmjdvriVLlui5557Thx9+qJdffllRUVFq1qyZ/v73v5cr5FTk8ccfV/fu3bV48WK99tprkg6fU/7+97/r8ssvL7d8IN/x2vS7AAAAqG1MhmEYoQ4CAAAAACJFQUGBevfurbZt2/pudgMAAAA4NsasAAAAAIAg/P777+UGo3e73Xr44YdVWlqq/v37hygyAAAAIPzQDRQAAAAABGHFihV6+umn1bt3b51yyinKy8vTl19+qezsbLVt21ZjxowJdYgAAABA2KBYAQAAAABB6NSpk7p27aovv/xSubm5kqTExERNmDBB1157raKjo0MbIAAAABBGGLMCAAAAAAAAAACEFGNWAAAAAAAAAACAkKJYAQAAAAAAAAAAQopiBQAAAAAAAAAACCmKFQAAAAAAAAAAIKQoVgAAAAAAAAAAgJCiWAEAAAAAAAAAAEKKYgUAAAAAAAAAAAgpihUAAAAAAAAAACCkKFYAAAAAAAAAAICQolgBAAAAAAAAAABCimIFAAAAAAAAAAAIKYoVAAAAAAAAAAAgpChWAAAAAAAAAACAkKJYAQAAAAAAAAAAQopiBQAAAAAAAAAACCmKFQAAAAAAAAAAIKQoVgAAAAAAAAAAgJCiWAEAAAAAAAAAAEKKYgUAAAAAAAAAAAgpihUAAAAAAAAAACCkKFYAAAAAAAAAAICQolgBAAAAAAAAAABCimIFAAAAAAAAAAAIKYoVAAAAAAAAAAAgpChWAAAAAAAAAACAkKJYAQAAAAAAAAAAQopiBQAAAAAAAAAACCmKFQAAAAAAAAAAIKQoVgAAAAAAAAAAgJCiWAEAAAAAAAAAAEKKYgUAAAAAAAAAAAgpihUAAAAAAAAAACCkKFYAAAAAAAAAAICQolgBAAAAAAAAAABCimIFAAAAAAAAAAAIKYoVAAAAAAAAAAAgpChWAAAAAAAAAACAkKJYAQAAAAAAAAAAQopiBQAAAAAAAAAACCmKFQAAAAAAAAAAIKQoVgAAAAAAAAAAgJCiWAEAAAAAAAAAAEKKYgUAAAAAAAAAAAgpihUAAAAAAAAAACCkKFYAAAAAAAAAAICQolgBAAAAAAAAAABCimIFAAAAAAAAAAAIKYoVAAAAAAAAAAAgpChWAAAAAAAAAACAkKJYAQAAao20tDR9+OGHoQ7jhLnmmmu0cOHC4y63YcMGnXPOOTUQEQAAAADUvBdeeEFjxowJdRioZShWIKJF+k0vAEB4ee6553TllVced7lu3brpk08+qYGIqt+UKVP04IMPhjoMAAAAAECYoVgBAAAAAEAEcLlcoQ4BABCmaENQG1CsAAAAtcr27dt16aWXKiUlRaNHj9avv/4qSXrkkUfUt29fpaSkaPDgwXrvvfd86+Tm5uqGG25Q9+7d1a1bN1188cXKyck55n6+//57XXrpperSpYtSU1M1YcIESdKuXbuUnJysQ4cO+ZZ98MEHNWXKFEmS0+nUnXfeqdTUVHXt2lVDhw7Vt99+K+nwWwV33nmnJk6cqJSUFA0bNkwbNmzwbWfMmDF64YUXfJ83b96ssWPHqkePHurZs6f++c9/SpLWrVunbt26+ZYrKCjQ1KlTdfbZZ+vss8/WPffco6KiogqXlaSJEydqxowZQR8bSVq2bJmGDRumbt26acSIEfrqq698x61r1676+eefJUl5eXk677zz9Oabb2rBggV699139eqrryolJUVDhgw57n4AIJTS0tI0d+7ccu3O8dqCsvlvvPGG+vXrp5SUFD3yyCPat2+f/va3v6lLly4aPXq09u/ff9wYxowZo3//+98aM2aMUlJSdNlll2nr1q2++fPnz9cFF1yglJQU9e/fXy+//LJvXlkcixcv1vnnn69zzz1X0rHbzLJ2Y+HCherTp4+6d++uF154QVu3btXIkSPVpUsXTZw40dfOHKvdA4BwUhvO+W+//baGDh2qlJQUnXfeeXryySdlGIZvfnJysl5++WUNHjxYnTt31uTJk5WXl6ebb75ZXbp00YUXXujXRqSlpWn27Nm66KKL1KVLF40bN0579+71zT9w4IBuu+0233XEgw8+KKfTKel/7cErr7yi8847T6NGjTrmOf+zzz7TxRdfrK5du+rss8/Wfffdp5KSkuMe3zJbtmzxzRszZoz27dvnm2cYhh599FH95S9/UZcuXTRgwACtWrWq0r9bRA6KFYh4NXHTy+12KyUlxddgfPTRR0pOTvZ14fHTTz+pW7du8ng8uuaaa/Tqq69KkvLz89WuXTs99thjkg6fnHv27KnNmzdrzpw5uuWWW3z7uPjii3XppZf6Pk+aNEnPP/98NR0lAKg93nnnHU2fPl1r166Vw+HQU089JUlq06aN3njjDW3YsEE33HCD/vGPf2jnzp2SpOeff14ej0effPKJ1q1bpwcffFCxsbHH3M8///lP9e3bVxs2bNCnn36qcePGVSq+N998Uz/99JM++OADbdiwQTNmzFCTJk1885cuXapLLrlEX375pa644gpNnDjR78KnzN69e3XVVVdpwIAB+vTTT7Vq1SoNGjSown0++OCD2rFjh959912988472r59ux566KFKxRvMsVm9erX+/e9/6+GHH9b69et13XXX6frrr9fBgwfVvn17paen69Zbb1VJSYnuvvtude3aVRdddJHGjh2rYcOG6fLLL9fXX3+tZcuWVSpGAAilo7U7lbFu3Tq9++67ev3117VgwQLdfPPNuuuuu7R27VrZbDY9++yzldrO4sWLdeutt2rdunXq2bOnJk6cKLfbLUlq2rSpXnzxRX311VeaNm2aHnnkEW3cuNFv/Y8++kiLFy/WypUrJR27zZSkwsJC5eTkaOXKlXrqqaf0yCOP6JFHHtHTTz+t1atX65dfftFrr70m6fjtHgCEk1Cf8xs0aKAZM2boq6++0uzZs7Vo0SK9++67fsusXLlSr7zyilasWKE1a9Zo9OjRGj16tNavX6+2bdvq0Ucf9Vv+9ddf12OPPaY1a9bopJNO0uTJkyUdvsd0/fXXq0mTJvrggw/07rvv6scff9QzzzzjW7ewsFA//vij3nvvPb388svHPOdHR0dr2rRpWr9+vV599VWtW7dO8+fPr9Txdbvduv7669WrVy+tW7dOt956q9544w3femvWrNHSpUu1ZMkSffXVV5o/f75atGhR6d8NIgfFCkS8mrjpZbVa1a1bN61bt06StHbtWp122ml+n7t37y6LxaLU1FTf9HXr1qlZs2a+zz/99JO8Xq/atWunnj17av369ZIOP7W6d+9e7dixQwUFBTIMQ+vXr1fPnj1PzEEDgBC64oor1Lx5c0VFRWnYsGH6/vvvJUl//etf1bhxY1ksFg0ZMkQtW7bU119/LenweTg3N1c7duyQxWJR27Zt1aBBg2Pux2q1avfu3dq3b5/sdru6d+9eqfisVqsKCwu1detWGYahpKQknXrqqb75PXv2VFpamqxWqy6//HI1bty4wqeC3n77bbVv315XXnmloqKi5HA4yr0hIUler1fvvvuubrvtNjVs2FCNGjXSLbfcorfeekter7dS8QZ6bBYuXKhx48apffv2MpvNuuCCC5SUlKTVq1dLkq6++mqdcsopuvTSS/Xjjz/q/vvvP24cAFBbHa3dqYzrr79eMTExat26tdq0aaOuXbvqjDPOkN1uV//+/Su9rcGDByslJUV2u13p6en67bff9M0330iSBgwYoFNPPVUmk0k9e/bU2Wef7btOKJOenq569erJ4XBIOnabWebGG2+U3W5X7969Vb9+ffXt21ennnqq4uPjdc455/hiP167BwDhJNTn/HPPPVdJSUkymUxq27athgwZUu6c/ve//10NGjRQQkKCunfvrjPOOEPdunWT1WrVwIED9cMPP/gtf/nll6tVq1ZyOByaPHmy1q1bpz179ui7777Tjh079I9//EMOh0MNGzbUhAkTtHTpUt+6Xq9Xt99+uxwOhxwOxzHP+d26dVO7du1ksVjUvHlzXXbZZeViP9rx/eabb3Tw4EGlp6fLbrcrJSXF70Etq9Wq0tJSZWVlyeVyqWnTpkpKSqr07waRwxrqAIATrexEKUnDhg3T3LlzJR3+A77MkCFDNGfOHH399ddq3ry5342dNm3aqG3btsfdT1kR4oorrtDatWt1ww03+F7RXrt2ra+wkJqa6qs8r127VmPHjtXMmTNVUFDgK2qYzWa1b99eJSUlysrK0vbt29WtWzeVlpZq48aNvqp2ZeICgHBz5NOaMTExKiwslCS98MILev3117Vnzx6ZTCYVFRXp4MGDkqRx48aptLRUN910kwoKCjRo0CDdfvvtio6OPup+/vWvf2nmzJm6+OKLVa9ePd8TS8czfPhw7d+/X/fee6/27NmjtLQ0/eMf/1CjRo0kHX4C9khNmzb1exW7zO7duyv1tNDvv/8ul8ulZs2a+aY1b95cTqfTl/+xBHNscnJy9MQTT/i6kpIOPw1V9qq2yWTSqFGjdMMNN+iOO+5QXFzcceMAgNrqaO1OZZx00km+/3c4HGrcuLHf57KulI7nyLbDZrOpSZMmvnPuO++8o/nz5ysnJ0der1clJSVKTEz0W//PxYNjtZmSFBsb69cOOByOcrmUxX68dg8Awkmoz/mffvqpZs2ape3bt8vtdsvpdOqcc8455n7i4+N9n6Ojo8vt58jrhJNOOkl2u1179+7V7t27dejQIfXo0cM33zAMvweeYmNjVa9ePd/nY53zv/32Wz3++OP6+eefVVJSIo/HU66gcLTju2/fPp188smy2Wx+cW/btk3S4Qe+Jk2apKeeekpbt25V79699Y9//MN3Pw91B29WIOId66bXkCFD1LVrV3Xr1k1btmzxu+nVtWtX3XTTTfrLX/6iadOm+fXDV5HU1FStX79ev//+u37//XcNGzZMOTk5ysvL04YNG3zFivbt26u0tFRbtmzRunXr1Lt3b3Xt2lUbNmzwK2pYLBbf2xpr165VamqqevbsqbVr12rt2rXq0aOHTCbTiThkAFDrlL2C/O9//1tffvmlNmzYoDPOOMPXv2tsbKwmT56sFStW6L///a/Wrl2rV1555ZjbPO200/TII49ozZo1mjZtmv79739r8+bNiomJkSQVFxf7lj2y/1mr1aoJEybonXfeUUZGhnbv3q1Zs2b55u/evdtvP7/++qsSEhLK7b9p06basWPHcXNv1KiRbDabX3eEOTk5stvtatiwoWJiYlRSUuLX1+2R8QZzbE455RTdcccd2rBhg++/b775RuPHj5d0+I2/adOm6bLLLtOzzz7rlzNtE4BIcLy2oLodeR51uVzav3+/Tj75ZO3evVtTpkzR5MmT9fnnn2vDhg0655xz/M75kmQ2/+/S/nhtZqCO1+4BQLirqXO+0+nUpEmTdNlll+nTTz/Vxo0bNWrUqKDPz2WOvE44cOCAnE6nEhISdOqpp6px48Z+f9Nv3LjR7027I9sP6djn/Ntuu02pqan68MMP9dVXX+mWW26pdOwnn3yy9u3b5zeI95+vm6688kotWrRIH3/8sex2ux588MGAjwXCH8UK1Ekn4qZXu3bt5HK59PLLL6tHjx6yWCzq2rWrXnzxRVmtVp155pmSDhchunfvroyMDOXm5qpVq1bq2bOn1qxZoy+//FKpqam+bZa9rVFWxOjZs6df8QIA6orCwkJZLBY1atRIXq9Xb7zxhrZs2eKbv2rVKm3fvl1er1dxcXGyWq2yWCzH3OZbb72l3377TSaTSfXq1ZPZbPbto2nTpr5ultauXevr/kiSvvjiC2VmZsrtdsvhcCgqKspvX2vXrtXHH38st9utRYsWaf/+/TrvvPPK7f+vf/2rvv32W7366qtyOp0qLi72G4y7jNls1rBhw/TEE08oNzdXBw8e1OOPP67hw4fLbDYrKSlJNptN7777rjwej5YuXarMzMwqHZsrr7xS8+bN0+bNm2UYhoqLi/X5559rz549kqT/+7//U7du3fTAAw/o4osv1u233y6PxyPp8NNcO3furPJFFwCE0vHagur23nvvadOmTXI6nZo1a5YaNWqkzp07q6ioSIZhqFGjRjKbzVq9erXWrFlzzG0dr80M1PHaPQAIdzV1znc6nSotLVWDBg1kt9u1adMmvy6ZgvXaa69p27ZtKikp0WOPPabu3bvrlFNOUYcOHXTKKafoiSee8HUpnpOTc8zcjnXOLygoUL169RQTE6OtW7f6xmOtjE6dOql+/fp65pln5HQ6tWnTJr+xY7/99lt99dVXcjqdvi5yaWvqJooVqJNOxE2vsjchXnzxRV8hoWfPnnrxxRfLvQWRmpqqBQsW+F7F69mzp5YsWaKoqChfUaNsuc8++0z5+flq2bKlkpOTtXfvXn355ZeMVwGgTunTp48GDBigYcOGqU+fPsrKylKXLl1883fs2KFrrrlGXbp00ZAhQ9S5c2ddfvnlx9zm559/ruHDhyslJUUTJ07UP/7xD1/3ev/617+0ZMkSde3aVa+99pqGDBniW+/AgQO69dZb1b17d/Xr10/x8fFKT0/3zR86dKgWLVqk7t2766WXXtIzzzyj+vXrl9v/KaecohdffFFLly5V7969lZaWpuXLl1cY6913361mzZppyJAhGjp0qE4//XRNmTJFkhQXF6d//vOf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rtTMmTP1m9/8Ru+//76cTqceffTRJtdx//3366OPPtJTTz2lf/7zn+rRo0d9P4CBQEDXXHONhg4dqg8++EC//OUv9dxzz7WofUOHDtWaNWv0wQcf6JxzztGNN94ot9vd4H3bt2/Xn/70Jy1btkwff/yxnn32WfXr169F2wKAZBQLhe/KykrdeOONGjx4sM4++2z9+9//Dpvvdrs1d+5cnXrqqTr11FN12223qaamRpI0btw4SdJpp52mwsJCvfLKKxGdwABArNqzZ48mT55cf/PO1q1b6+d9++23uvHGGzVkyBCdfvrpuv/++xUIBCT99y79VatWafjw4frRj36kFStWaNu2bRo3bpxOPvlkXXvttfXHU+nINwodOl7c4fLHkcyfP18bN27Uvffeq8LCQl111VVNtuNQf//73zV8+HBt3LhRkvT666/r/PPP1+DBgzV27Fh99NFH9e+dMGGC7rvvPk2ZMkWFhYW66KKL9MUXXzS5z0OhkFauXKmzzz5bhYWF+ulPf6p33nlH0oGbte677z6dfvrpGjJkiGbOnKnvvvtOUtM3Y9XNf+mll/STn/xEgwcP1pw5c+T3+7V//35NnTpVVVVVKiwsVGFhYX0bASBRHe6a1vHHH6/nnntOGzdu1HXXXadf//rX2rFjhyRp+fLlCgaDeuedd/TBBx/o97//vTIyMlq87ZdfflkrV67UW2+9pcrKSt19991t2jYgEhQrEPcuu+wydevWTSkpKTr//PO1adOmZi97zTXXKD09Xb1799bxxx+vQYMG6bjjjpPL5dKoUaOaXJdpmnr66ad1yy23qHPnznK5XJo5c6Y++ugjffPNN/rkk0+0f/9+zZgxQy6XS4WFhRo9enSL2jd27FhlZWXJ6XTqqquuUigUavQEw263yzRNbd26VV6vV0cffbSOP/74Fm0LAJKV1YXvu+66S1VVVXrrrbf0xBNP6KWXXgqb//vf/15fffWVXn31Vb3yyivavn277rnnHkmqf4pu/fr1+vjjj3XBBRe02QkMAMSCX/3qV+rUqZM2bNigP/7xj3r22WfD5jkcDq1bt06rVq3S3//+dz322GP186urq7Vr1y6tW7dODzzwgBYsWKAFCxbowQcf1Pr16/X111/rmWeeqX9/c28UqtPS/DFnzhwNHjxYs2fP1scff1wfa1PtqPPss8/q7rvv1vLlyzV48GCtX79ef/jDHzR//nz9v//3/zRt2jRdc8012r9/f/0yL7/8sm666Sb9+9//1kknnaS77rqryX3+5z//WU888YTuvfdeffTRR1qxYoW6du0qSXr00Uf1j3/8Q0899ZTWrVsnwzA0e/bsJtd5sH/+85968cUX9frrr+u9997Tq6++qg4dOmjp0qXKysrSxx9/rI8//pguoQAkvMNd07rgggt01FFHyW6369xzz1XPnj318ccfS5IcDofKy8v11VdfyW63q2/fvsrNzW3xtq+66irl5eUpOztbN954o1599VWFQqG2bB7QYhQrEPc6depU/+/09HRVV1c3e9mjjz66/t9paWk66qijwl4ffJdVY/bv36+amhr94he/0ODBgzV48GANGzZMTqdT33zzjfbu3avOnTvL6XTWL1P3Jb85QqGQ7r//fv30pz/VySefrMGDB6uqqirs5KPOscceq/nz5+vPf/6zfvzjH2vy5MnavHlzs7cFAMnMysJ3MBjU6tWrNXPmTGVnZysvL6/+TlvpQC549dVX9atf/UodOnRQx44dNWvWLL300kuHPZloqxMYALDaN998o40bN+rXv/610tLS1KtXr/pBrktLS/X+++/rlltuUUZGhrp27arp06frxRdfDFvHDTfcIJfLpR//+MfKycnRGWecoWOOOUZZWVkaMWJE2HG6uTcK1WlN/qjT3HYsWrRIK1as0KpVq3TcccdJklatWqUpU6boxBNPlM1m009/+lP16NFD69evr1/uggsu0PHHHy+Hw6ELL7xQn3/+eZMxPf3007r++ut10kknyTAMdenSRb169ZJ0oEBzzTXXqEuXLsrIyNCcOXO0YcOGsK5wm3LttdcqMzNTeXl5Gj58eET7DQASweGuaa1YsULnnnuuBg0apMGDB2vLli3114KmTJmiQYMG6cYbb9SwYcN01113yev1tnjbB1+f6tKli/x+f/2TcoBVHFYHAERDenq6JMnj8Sg7O1uStG/fPqWmprbpdnJzc5WWlqZnn322/sv7wTZu3Ki9e/fK7/fXFyx2797d7DhfffVVvfrqq1q2bJm6d+8uwzD0ox/96LDxnHPOOTrnnHPk9Xr1wAMP6Ne//rVeffXVNmsvACQqqwvffr9fXbp0qZ928L+/++47+f3+sJOJbt26yefzNVq8lg6cwNTW1tbfETx69GjNnj27zfMgAETb3r17lZKSEnZsrTse7tmzRykpKWHH4W7dumnPnj31rzMyMsKOfWlpaQ2O23XH6VAopAceeEBr1qzRt99+K5vNJrfbfdhjrdS6/FGnOe3wer1asWKFZs+erWOOOaZ++q5du3T//fdr4cKF9dMCgYD27t1b//rg9aanpzeZl6QD5yw//OEPDxvvwTkpLy9PLpdLpaWl6tixY5PrlsL3W1paGv2kA8BBNm7cqIULF+qJJ57QCSecIJvNpjFjxsg0TUkHcttNN92km266STt27NA111yjp556SpMnT27Rdnbt2qUBAwZIOnBzgNPpbPZxHIgWnqxAQurYsaO6dOlSf9fp+++/H3Z3UVux2WwaP368/vCHP9T3T7t//36tXr1akjRgwADl5OTo4Ycfls/n06effho2KFJTcbrdbjmdTnXo0EF+v18PPfTQYU+AiouLtWHDBnm9XjmdTmVkZMhut7d5mwEgWRxcUK7TnPEnWqpDhw5yOp1hxeyD/92xY0c5nc6wMSd27doll8ulDh06yGZr+HWu7gTmb3/7m/7yl7/o/fff11NPPdXmsQNAtHXu3Fm1tbUqKyurn1Z3jPzBD36g2tpaffvtt/Xzdu3apR/84AcRbavuRqFHH31UH374oTZu3KisrKzWNaARhmGEvW5OO1JTU/X444/rT3/6k15//fWwZW+++WZt3Lix/ueTTz7R1Vdf3aoYu3Tpoq+++qrReT/4wQ/CctK+ffvk8/mUl5fX6tzZWE4DgGRTXV0tu92ujh07KhQK6bnnntOWLVvq57/99tvavn27QqGQMjMz5XA4Irr+s2zZMpWWlqqyslIPPPCAzj33XI7DsByfQCSsu+++Wy+88IIGDRqkZ555Rueee25UtvPLX/5SAwcO1KRJk1RYWKixY8fqX//6lyTJ6XRq8eLF+te//qWioiLde++9uvjii5sd50UXXaTjjjtOZ5xxhs4880ylpqYe9uTL7/frgQce0I9//GMVFRXp/fff1/z586PSZgBIBu1V+Lbb7Tr77LP1wAMPqLKyUqWlpVq2bFn9fJvNpvPPP1/333+/ysvLtX//fv3P//yPxowZI5vNpo4dO8pms+nrr7+uX6atTmAAwGrHHHOMTj75ZN17773yer0qLi6uH2MiLy9PRUVF+sMf/qCamhrt3r1bjzzyiC688MKIttWS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1lmaPHly2DSXyxXNcAEgKsgVAJAYon1xinwRubvuukvjx49Xjx49wqbv2LFDJSUluummm8Kmn3POOVqwYIF8Ph/nGADaFLkieihWAIgrbp9bNf6aNltfujNdafYjdxmSlZWll19+WZL0t7/9TYsWLdJDDz3U4m3l5eXFVYJorsWLF6tjx471r4cOHary8nI9/vjjuvbaa4848NLRRx/NY9kAoqIt80W6M12ZriMPDkeuAID4c2iuMGUqFArJ5rXJUMsvRJEvomft2rX68ssvtXDhQm3atClsXnFxsSQ1KGL06tVLfr9fO3bsUK9evdotVgCJ5+B8Qa6IrqQpVtjtdh7fARJAjb9G63f9U9VtcAEqw5mu07oOb7JYcTC3262srCxJB/rr++Mf/6h///vf8vv9uuqqq3TBBRfohRde0Pr161VZWamdO3fq5z//uSZPnqydO3fqhhtu0AsvvKCamhrddNNN2r59uwYMGKD3339fr732mj7//HM98sgjSktL07Zt23T66afrlltuaXVbo+ngQkWdvn376tlnn1VNTY0yM4+chAEgGtoqX9TliqZOKA5Grkh8nFsAieHQXGGGTIVCAdlsDhm2lv0fJ19Ej8fj0fz58zVr1qxGzy0qKiokSdnZ2WHT617XzY+EaZqqqYnsu4TH45HdbldtbW2jOcM0zYjjilUejyfsd7Kg3YnV7traWoVCIQWDwfpxGqr91Vq/oy5fmAqFgrLZ7FILixUZznSd1q1516Hqtl1ZWanMzMz6eO699159+OGH8vv9mjx5ss4//3y9+OKLeuedd+pzxfjx43XllVdq165dmjlzpv7617+qpqZGN998s7Zv367+/fvrgw8+qO/S+9FHHw3LFTfffHODeOqOWaZpNjp20KGxh0IheTwehUIhmabZ7O/OSVOs6PCDjioPlKuquqrR+c2pagGIDdX+Grn97nbbXlVVlcaMGSOv16vy8nI9/fTTkqTnnntOnTp10vPPPy+v16tLL71Uw4cPlyR98cUXev755xUMBnX22Wfr8ssvD1vnqlWr1KVLFy1atEjvvvuuXnjhhfp5//u//6vXX39d2dnZOu+88zRp0iR16dKl3drbFj788EPl5eU1Wah49dVX9eyzz8rpdGrw4MGaPXu2CgoK2inKxh3pbmxyBRBf2jNfkCuSC+cWQOI4OFeYIVPBYEB2e8uLFc1Fvmi5xYsX66ijjtLYsWPbfdt+v1+bN2+OaFm73a4OP+iob71lkrfhfJfh0v493zV50S8elZSUWB2CJWh34nA4HKqtrZV0oMunUCikqtpKVflad24RCgUUCoVUW1t7xIJlVVWVLrzwQnm9XlVUVOjxxx+X1+vV888/rw4dOmjlypXyer2aNGmSfvSjH8nv9+uLL77Qn//8ZwWDQV100UW65JJL6gsvXq9XK1euVOfOnfXHP/5RH3zwgV566SXV1tbK5/Ppf//3f/Xcc88pOztbl1xyiS699FIdc8wxjcZWt1+OpLa2VoFAoP7JN6n5XX4nRbHCMAz5TJ/e2/m+vKGGOzSSOyAAJI+DH79bu3atfve732nFihXasGGDvvzyS73yyiuSDtwZtWPHDknSsGHDlJGRIUnq3LmzysrKwtb58ccfa+rUqZKkH//4x8rNza2fV1hYqKOPPlqSdNxxx2n37t1xdUKxceNGrV69utFK/MFGjhyp/v37q0uXLtqxY4ceeeQRXXbZZXrppZfUrVu3iLffmrufDMNQVaBK63f+U9X+6rB5Gc4MnZY/XPagPWbugkrUO1liBfs3utpy/zZ295MpU2bowE9rmCFTppq+eygrK6v+4tDf/vY3zZs3T8uXL9e//vUvbdmypT6PVFVV6auvvlIoFNLQoUOVmpoqSerUqZP27t2rUCgk6cDdSB999JGuuuoqBYNBFRUVKScnp/4upYEDB6pDhw6SpN69e2vHjh3Ky8sLj72Zdz8deudT3TI8OdA4zi0AtAbnFi2za9cuLV++XIsWLVJV1YECcd13/ZqaGlVXVysnJ0fSgRzbqVOn+mUrKyslqX5+JJxOp3r37h3RsrW1tfrWW6b/V/ZveUPh1Yq6c4uCgoKYObdoCx6PRyUlJerevbvS0prfg0G8o92J1e7a2lrt3r1bKSkp9d/VbV6bbDaH7HaH9P25gd3e8icrbDaHbDabUlJSjvi+rKwsvfTSS5IOnFssWLBAy5cv17///W9t2bJFa9askSRVV1dr3759cjqd+vGPf1zf80Xnzp3ldruVkpIim82m1NRUff7557rqqquUmpqq0047TTk5OUpJSZHL5VJhYaG6du0qSerTp4/KysoadK1nmqZqa2uVkpLSrPMEh8OhY489VikpKdq6dWuz91FSFCvqVPur5Qk1Us4GgGY644wz6i/Ch0Ih/e53v9Mpp5wS9p6tW7eGVYxtNluDi0RH+kJ68LJ2uz2u7rTZs2ePZs2apaKiIk2cOPGI77311lvr/z148GANGzZMo0eP1rJly3THHXdEHENr7n5yOp1K65Sub77drQpvZdi8nNRsuXMPfBHw+/0RxxcNiXgnSyxh/0ZXW+3fxu5+CoUCCgYDrVpvyN68u58kyes98D1zyJAhuuWWW+T1euX3+/Wb3/xGgwYNCnvv5s2bZbfb65cxDKO+cFN391MwGFRtbW39eyTV3/108LJ12z749cGauvupsTufpObf/ZSsOLcA0FqcWzRt586d8vv9uvrqqxvMmzhxogYMGFDfH3txcbF69uxZP7+4uFhOp7NVN0IZhqH09PSIl5VX8oa8DfKFPeSQ3WZPqAu8B0tLS4t4v8Uz2p0YbDabbDab7Hb79wUJyZAhw3bgxwzVvdNo8VN4hs2QIaN+vUdS954zzzxTt9xyi+z2AzdONpYriouLlZqaWr9M3e+6MUQPfl3fJuNAHHXFk7rpDocjbJk6dfmjbrmmYrfZbEpLS1NqamqLboJKqmIFALTWRx99VP9ld9iwYXrqqac0aNAg2e12ffnll80euK2wsFBr165VYWGh3nvvPZWXl0cx6vZRWVmpqVOnKjc3VwsXLjziwNqN6dy5swYNGtRgwLyWas3dT4ZhqDxQruycHBlp4ck3y5WpzMwM5ed2jZm7nxL1TpZYwf6Nrrbcv03f/RS55t79JKl+25988ony8/OVmpqq4cOH6/nnn9eQIUNkt9u1ZcsW9ezZU06nU3a7/b/xHrSNurufBg0apH/84x8qKirS+++/r4qKivq7nw5e1m63y+Vy1b+u05K7nw6+80lSi+5+AgBEhnOLpvXt21crV64Mm7Z582bdc889mjdvnvr166du3bqpe/fuWrt2rUaNGlX/vtWrV2vo0KEU3wHEtWTLFRQrAMSdDGfbVOybu566fmVN05TD4dDvfvc7SdKll16qnTt36sILL5RpmurUqZOWLl3arHX+4he/0OzZs3Xuueeqf//+ysvLa3CRKZ54vV5NmzZNVVVVeuaZZ+oHCrRCa+5+kqSq6irZ7Y76uwnq2O2xe/dTot3JEmvYv9HVFvv3cHc/ZaZktLrP8QxnerPufqqqqtLFF19cnyvuvPNO2e12jR8/Xrt379bYsWPDcsXBMR/cjjp2u12XX365Zs+erQsuuKA+V2RkZMhms4Xd0WQYRoN1Sc2/++nQO5/qlgGAZHDwOYEZMhWyRz7AdnNwbtEy2dnZKioqanTeiSeeqBNPPFGSdP3112v27Nk69thjVVRUpNWrV+uzzz7Tn//85/YMF0ACqzvOkyuii2IFgLiS/n0/0G25vqb87//+b6PT7Xa7brrpJt10001h0y+++OKw1wcPcFf375SUFD3wwANyuVz67LPP9OWXX8put6uoqCjsy/iDDz7Y7LZYJRAIaObMmSouLtaqVasa9JneXKWlpfrwww81ZsyYNo4QQDJqy3xBrgCAxHRorjBlKhQKHSgKt7Af8rr1NYV8ER3nnXeePB6Pli5dqiVLlqhHjx566KGHVFhYaHVoABLAwfmCXBFdFCsAxJVMV2abD1hpRb+tNTU1uuKKKxQIBORwOFo1RoPV5s2bp7fffltz5syR2+3WJ598Uj/vhBNOkMvl0qRJk7R79269+eabkqTXXntNb7/9tk477TR17txZO3bs0JIlS2S323XllVda1BIAiSQa+aK9JVKuAIBYdGiuqBsr6OC+u+NBsuWLoqIiffHFFw2mjxs3TuPGjbMgIgCJ7uB8Qa6ILooVAGCB7OzssEp3PNuwYYMkaf78+Q3mrVu3Tvn5+QqFQmFFofz8fO3du1d33323qqqqlJWVpSFDhuiGG25o1QB4AJBIEilXAEC8iJWxyVqCfAEA7YtcET0UKwAArfLWW281+Z4nn3wy7PXAgQMbTAMAAAAAAEDysjX9FgAAAAAAAAAAgOihWAEAAAAAAAAAACxFsQIAmlBQUBA28NDevXvVt29fLVy48IjLzZkzR2+//bYkaerUqfJ6vYd9729/+1t9/fXXbRIvAKD9kSui54UXXlBBQUGDn3vvvdfq0ACgxcgXAICmJHOuYMwKAGhCbm6uPv30UwWDQdntdv3tb39T7969W7SOpUuXHnH+73//+9aECACwGLki+h577DFlZWXVv87Ly7MwGgCJyjCMqK6ffJFcbIZNGc4M2UPhl98ynOkyFN3PGoDoIVdED09WAIgrprtKodJv2uzHdFc1a7uDBg3S//t//0+S9Oabb+qnP/1p/by///3vuuSSS3ThhRfq6quvVmVlZYPlR44cqerqaknSc889p/PPP18XXHCB/vCHP0iSJkyYoC+//FKS9NJLL+n888/Xeeedp8cee0yStHPnTl188cX16/vDH/6gF154of7fZ511li644AI9/PDDLd2lAJCQ2jJfxGuuWLBggV555RVJiZErTjzxRA0cOLD+55hjjrE6JABx7tBcoX2lcu7/TtpXmlT54v7779eLL74oKTHyRSw52paqHzt76nRXQdjPEHt3Zfqsjg5Acx2cL5I1V7TXuQVPVgCIK2a1W4G33pBZ7W71uoyMTDlG/lRKS2/yvaNHj9bLL7+snj17yul0qkOHDtq/f78k6Uc/+pHOPPNMGYahlStXatWqVbrmmmsaXc8XX3yhJ554QqtWrVJ2drbKy8vD5peWluqhhx7Sc889p7S0NI0fP15DhgxRbm5uo+vbv3+/1qxZo7feeks2m01VVc1LegCQ6NoqX9TlCiMzq8n3xmquKC8vJ1cAQCMOzRWmaSoUDMpmt7f4rtlEyBecW7QtwzBk83hU+/fV8lZ9FzYvNedoGedOkDpYFByAFjk4XyR7roj2uQXFCgBxx6x2S1UNq8YtXk8L3nvyySfrrrvu0urVq3X22Wertra2ft4333yjG2+8UWVlZfJ6verfv/9h1/PBBx9o9OjRys7OlqQGB////Oc/Gjp0aP30s846Sx9++KHOPPPMRteXlZWlrKws/eY3v9GoUaN0+umnt6BVAJDY2iJfJEKuyMzMTIhccd5552n//v3q0qWLLr30Ul111VWy2+1WhwUgzoXlCtOUGQxKdrvUwgtQiZAvOLeIDn9VufwVZWHTHDYuxwHxpj5fJHmuiPa5BUdHAGgGwzA0ePBgLVmyRKtXr9brr79eP++uu+7S9OnTdeqpp+rtt9+uf4S6LTkcDpnmf9Oaz+ern/7888/rX//6l15//XW98sorevDBB9t8+wCAppEroqNTp066/vrrNWDAABmGobfeekt/+tOfVFpaqttuuy3i9ZqmqZqamhYvV3eiGAwEFQgFGswP2gIKhoLyeDxhf4945/F4wn4nC9qdWO2ura1VKBRSMBhUMBg8cMHJNKXv/6/W/Zc98LuF/3+/X1cwGGzyraFQSIMGDdKSJUv02muv6fXXX6+P684779S0adM0bNgw/eMf/9BLL72kYDB44E7e799Tt51QKNToNht7b912TdOUYRhh830+X/30Z599Vhs2bNDq1av18ssv609/+lP9euu26fF4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Xa0RI0aooKBA//nPf6wOJ2G8+OKLuvDCC9WvXz8VFRXpqquuktfrtTos4LA49rYvjr3Rw/E3etatW6dx48apsLBQp556qm688Ubt2LHD6rDiWrIee9evX6/LL79cQ4YM0UknnaQzzzxT99xzj6qqqqwOrV0lSy544YUXVFBQ0ODn3nvvtTq0dpFseWnChAmN/r0LCgr0+uuvWx1ezIv0epNpmlqyZIlOP/109e/fXz/72c/0ySefRD/gNhBJm/fu3asFCxZozJgxKiws1IgRI/SrX/1Ku3btaqeoW68tri2uWLFCBQUFmjZtWpSibHutaXdpaaluvvlmDRkyRP3799fo0aP1yiuvRDnithFpu/fv36/bbrtNp59+ugYOHKjzzjtPTz/9dDtE3Da++uor3XbbbRozZoxOOOEEnXfeec1aLhrHNEerlo5hFRUVmjRpkrp3766FCxeqtLRU8+fPl9fr1W233WZ1eAlhxYoV6tq1q+bMmaMOHTro3Xff1dy5c7Vnzx7NmDHD6vASzsMPP6xgMGh1GAll8eLFWrp0qaZPn66BAwdq//79eu+999jPiGkce9sXx97o4PgbPR988IFmzJihCy+8ULNmzVJ5ebkeeOABTZ48Wa+++qpSU1OtDjEuJeuxt7y8XP3799eECROUm5urLVu2aOHChdqyZYuWL19udXjtJtlywWOPPaasrKz613l5eRZG0z6SMS/dfvvtcrvdYdOeeOIJvfHGGxo6dKhFUcWH1lxvWrp0qR588EHNnj1bBQUFWrVqlSZPnqyXX35Z3bp1a6cWtFykbd60aZPefPNNjR07VgMGDND+/fu1ePFijRs3Tq+99po6duzYjq1ouba4trhv3z4tWrRIRx11VJSjbTutaffevXv1s5/9TD169NCdd96pzMxMbdmyJS5uHm9Nu2+88UYVFxfrl7/8pY455hi98847uuOOO2S323XppZe2Uwsit2XLFq1fv14DBgxQKBRq9g05UTmmmQnqkUceMQcOHGju37+/ftpf/vIXs2/fvuaePXusCyyBlJWVNZh26623mieffLIZDAYtiChxbd36/9u796Coyv8P4G8gAYFZEAc0oMbb7LYgQYQhCQSrTTFqTuWFlLCJAZxWMLSUHMtMRLpgKoFEQmkhGufq5QAADU1JREFUIw02XQYYUTMLqtGYsIhyuHRREw0V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Odal3BJT6x7a+PwnhUIBFxeXf51fLImpdQNAeno6nnnmGWzbtg3R0dH44YcfUFxcjMTERIt/TompdUdFRcHHxwdpaWnQarXw9vbGV199hY8++gipqalSlXNLuru78cUXXwAYvNFJr9ejqqoKAHDffffB09NzzHqabDcr3N3dsW/fPmzduhVarRaurq5YvHgx0tPTpY4mGzU1NQCA7OzsEdeOHj0q67utyPrZ29ujsLAQ27dvx0svvQSDwYDQ0FCUlJTI+s0YWT/2XrJ27L/iSkhIgKOjI0pLS1FeXg5XV1cEBwdj586dmDBhgtTxrJat9t67774bFRUVKCwshCAI8PX1xZIlS5CYmCjbDRpbNnXqVJSXl+PChQsYGBjAlClTsHHjRjz55JNSRxOVLc9LHR0d+PLLL7Fy5UrY2dlJHcdq3Ox608DAAPr7+43GkpKSIAgCiouLcfnyZajVahQVFeGOO+4YyxJumak119fXQ6fTQafT4YknnjD6s48++ugN51VLMpqftTUbTd0ajQY7duxAfn4+SktL4e3tjdTU1BserWhpTK3bzc0N7733Ht5880288cYb0Ol08PPzQ0ZGhtEnTCxZe3s71qxZYzQ29PX+/fsRFhY2Zj3NThAEweTvJiIiIiIiIiIiIiIiGiV7qQMQEREREREREREREZFt42YFERERERERERERERFJipsVREREREREREREREQkKW5WEBERERERERERERGRpLhZQUREREREREREREREkuJmBRERERERERERERERSYqbFUREREREREREREREJCluVhARERERERERERERkaS4WUFERERERERERERERJLiZgUREREREREREREREUmKmxVERERERERERERERCQpblYQEREREREREREREZGk/gdL2RHDm41SUQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ─── Feature distributions: benign vs malicious ─────────────────────────\n", + "top_feats = feat_corr.head(8).index.tolist()\n", + "fig, axes = plt.subplots(2, 4, figsize=(16, 7))\n", + "axes = axes.flatten()\n", + "\n", + "for ax, feat in zip(axes, top_feats):\n", + " for lbl, color, name in [(0, '#4CAF50', 'Benign'), (1, '#F44336', 'Malicious')]:\n", + " data = df.loc[df['is_malicious']==lbl, feat].clip(\n", + " df[feat].quantile(0.01), df[feat].quantile(0.99)\n", + " )\n", + " ax.hist(data, bins=40, alpha=0.6, color=color, label=name, density=True)\n", + " ax.set_title(feat, fontsize=9)\n", + " ax.legend(fontsize=7)\n", + "\n", + "plt.suptitle('Feature Distributions: Benign vs Malicious', y=1.02)\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'eda_feature_distributions.png', dpi=150, bbox_inches='tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Data Preparation\n", + "\n", + "We prepare two tasks:\n", + "- **Binary**: benign (0) vs malicious (1)\n", + "- **Multi-class**: benign (0) / phishing (1) / defacement (2) / malware (3)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train: 520,952 | Test: 130,239\n", + "Binary train dist : {0: 342482, 1: 178470}\n", + "4-class train dist : {0: 342482, 1: 75289, 2: 77165, 3: 26016}\n" + ] + } + ], + "source": [ + "from sklearn.model_selection import train_test_split\n", + "from sklearn.preprocessing import StandardScaler, LabelEncoder\n", + "\n", + "# ─── Encode labels ─────────────────────────────────────────────────────\n", + "label_map_4 = {'benign': 0, 'phishing': 1, 'defacement': 2, 'malware': 3}\n", + "df['label_4'] = df['label'].map(label_map_4)\n", + "df['label_2'] = (df['label'] != 'benign').astype(int) # binary\n", + "\n", + "CLASS_NAMES_4 = ['benign', 'phishing', 'defacement', 'malware']\n", + "CLASS_NAMES_2 = ['Benign', 'Malicious']\n", + "\n", + "X = df[feat_names].values.astype(np.float32)\n", + "y_4 = df['label_4'].values\n", + "y_2 = df['label_2'].values\n", + "urls = df['url'].values\n", + "\n", + "# ─── Binary split ──────────────────────────────────────────────────────\n", + "X_train, X_test, y2_train, y2_test, y4_train, y4_test, u_train, u_test = \\\n", + " train_test_split(X, y_2, y_4, urls, test_size=0.20, stratify=y_4, random_state=SEED)\n", + "\n", + "print(f'Train: {len(y2_train):,} | Test: {len(y2_test):,}')\n", + "print(f'Binary train dist : {dict(zip(*np.unique(y2_train, return_counts=True)))}')\n", + "print(f'4-class train dist : {dict(zip(*np.unique(y4_train, return_counts=True)))}')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "βœ… Scaled (dtype=float32, shape=(520952, 54))\n" + ] + } + ], + "source": [ + "# ─── Feature scaling ───────────────────────────────────────────────────────\n", + "scaler = StandardScaler()\n", + "X_train_sc = scaler.fit_transform(X_train).astype(np.float32)\n", + "X_test_sc = scaler.transform(X_test).astype(np.float32)\n", + "\n", + "print(f'\\u2705 Scaled (dtype={X_train_sc.dtype}, shape={X_train_sc.shape})')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Classical ML Models (GPU where possible)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "=======================================================\n", + " BINARY: Benign vs Malicious\n", + "=======================================================\n", + "\n", + "Training XGBoost (GPU) …\n", + "\n", + "──────────────────────────────────────────────────\n", + " XGBoost (GPU)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9802\n", + " Precision : 0.9805\n", + " Recall : 0.9754\n", + " F1 (macro): 0.9779\n", + " AUC-ROC : 0.9968\n", + "──────────────────────────────────────────────────\n", + "\n", + "Training LightGBM (CPU) …\n", + "\n", + "──────────────────────────────────────────────────\n", + " LightGBM (CPU)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9782\n", + " Precision : 0.9759\n", + " Recall : 0.9756\n", + " F1 (macro): 0.9758\n", + " AUC-ROC : 0.9965\n", + "──────────────────────────────────────────────────\n" + ] + } + ], + "source": [ + "from models import build_xgb, build_lgbm\n", + "from evaluation import evaluate_model, print_results_banner\n", + "\n", + "all_results_bin = [] # binary results\n", + "all_results_mc = [] # 4-class results\n", + "\n", + "# ─── Binary Classification ──────────────────────────────────────────────\n", + "print('\\n' + '='*55)\n", + "print(' BINARY: Benign vs Malicious')\n", + "print('='*55)\n", + "\n", + "clf_models_bin = {\n", + " 'XGBoost (GPU)': build_xgb(num_classes=2),\n", + " 'LightGBM (CPU)': build_lgbm(num_classes=2),\n", + "}\n", + "\n", + "for name, model in clf_models_bin.items():\n", + " print(f'\\nTraining {name} …')\n", + " model.fit(X_train_sc, y2_train)\n", + " preds = model.predict(X_test_sc)\n", + " proba = model.predict_proba(X_test_sc)\n", + " result = evaluate_model(name, y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + " all_results_bin.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "=======================================================\n", + " MULTI-CLASS: benign / phishing / defacement / malware\n", + "=======================================================\n", + "\n", + "Training XGBoost (GPU, 4c) …\n", + "\n", + "──────────────────────────────────────────────────\n", + " XGBoost (GPU, 4c)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9745\n", + " Precision : 0.9714\n", + " Recall : 0.9553\n", + " F1 (macro): 0.9630\n", + " AUC-ROC : 0.9968\n", + "──────────────────────────────────────────────────\n", + "\n", + "Training LightGBM (CPU, 4c) …\n", + "\n", + "──────────────────────────────────────────────────\n", + " LightGBM (CPU, 4c)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9681\n", + " Precision : 0.9529\n", + " Recall : 0.9640\n", + " F1 (macro): 0.9581\n", + " AUC-ROC : 0.9966\n", + "──────────────────────────────────────────────────\n" + ] + } + ], + "source": [ + "# ─── 4-Class Classification ─────────────────────────────────────────────\n", + "print('\\n' + '='*55)\n", + "print(' MULTI-CLASS: benign / phishing / defacement / malware')\n", + "print('='*55)\n", + "\n", + "clf_models_mc = {\n", + " 'XGBoost (GPU, 4c)': build_xgb(num_classes=4),\n", + " 'LightGBM (CPU, 4c)': build_lgbm(num_classes=4),\n", + "}\n", + "\n", + "for name, model in clf_models_mc.items():\n", + " print(f'\\nTraining {name} …')\n", + " model.fit(X_train_sc, y4_train)\n", + " preds = model.predict(X_test_sc)\n", + " proba = model.predict_proba(X_test_sc)\n", + " result = evaluate_model(name, y4_test, preds, proba,\n", + " class_names=CLASS_NAMES_4, task='multiclass')\n", + " all_results_mc.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. TF-IDF String Model" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Training TF-IDF + LR (binary) …\n", + "\n", + "──────────────────────────────────────────────────\n", + " TF-IDF + LR\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9803\n", + " Precision : 0.9805\n", + " Recall : 0.9757\n", + " F1 (macro): 0.9781\n", + " AUC-ROC : 0.9971\n", + "──────────────────────────────────────────────────\n", + "\n", + "Training TF-IDF + LR (4-class) …\n", + "\n", + "──────────────────────────────────────────────────\n", + " TF-IDF + LR (4c)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9775\n", + " Precision : 0.9772\n", + " Recall : 0.9609\n", + " F1 (macro): 0.9688\n", + " AUC-ROC : 0.9976\n", + "──────────────────────────────────────────────────\n" + ] + } + ], + "source": [ + "from models import build_tfidf_lr_pipeline\n", + "\n", + "# Binary\n", + "print('Training TF-IDF + LR (binary) …')\n", + "tfidf_bin = build_tfidf_lr_pipeline(num_classes=2)\n", + "tfidf_bin.fit(u_train, y2_train)\n", + "preds = tfidf_bin.predict(u_test)\n", + "proba = tfidf_bin.predict_proba(u_test)\n", + "result = evaluate_model('TF-IDF + LR', y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + "all_results_bin.append(result)\n", + "print_results_banner(result)\n", + "\n", + "# 4-class\n", + "print('\\nTraining TF-IDF + LR (4-class) …')\n", + "tfidf_mc = build_tfidf_lr_pipeline(num_classes=4)\n", + "tfidf_mc.fit(u_train, y4_train)\n", + "preds = tfidf_mc.predict(u_test)\n", + "proba = tfidf_mc.predict_proba(u_test)\n", + "result = evaluate_model('TF-IDF + LR (4c)', y4_test, preds, proba,\n", + " class_names=CLASS_NAMES_4, task='multiclass')\n", + "all_results_mc.append(result)\n", + "print_results_banner(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Deep Learning Models (CharCNN Β· BiLSTM Β· Hybrid) β€” GPU" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DL device: cuda\n", + "\n", + "── Binary: Deep Learning Models ──\n", + "\n", + "Training CharCNN (binary) …\n", + " Epoch 1/20 loss=0.1873\n", + " Epoch 5/20 loss=0.0524\n", + " Epoch 10/20 loss=0.0302\n", + " Epoch 15/20 loss=0.0145\n", + " Epoch 20/20 loss=0.0079\n", + "\n", + "──────────────────────────────────────────────────\n", + " CharCNN\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9872\n", + " Precision : 0.9862\n", + " Recall : 0.9853\n", + " F1 (macro): 0.9858\n", + " AUC-ROC : 0.9985\n", + "──────────────────────────────────────────────────\n", + "\n", + "Training CharBiLSTM (binary) …\n", + " Epoch 1/15 loss=0.2838\n", + " Epoch 5/15 loss=0.0653\n", + " Epoch 10/15 loss=0.0475\n", + " Epoch 15/15 loss=0.0414\n", + "\n", + "──────────────────────────────────────────────────\n", + " CharBiLSTM\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9844\n", + " Precision : 0.9822\n", + " Recall : 0.9833\n", + " F1 (macro): 0.9828\n", + " AUC-ROC : 0.9980\n", + "──────────────────────────────────────────────────\n", + "\n", + "Training CNN-BiLSTM (binary) …\n", + " Epoch 1/15 loss=0.1749\n", + " Epoch 5/15 loss=0.0481\n", + " Epoch 10/15 loss=0.0323\n", + " Epoch 15/15 loss=0.0240\n", + "\n", + "──────────────────────────────────────────────────\n", + " CNN-BiLSTM\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9867\n", + " Precision : 0.9851\n", + " Recall : 0.9853\n", + " F1 (macro): 0.9852\n", + " AUC-ROC : 0.9985\n", + "──────────────────────────────────────────────────\n" + ] + } + ], + "source": [ + "import torch\n", + "from models import DeepURLClassifier\n", + "\n", + "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", + "print(f'DL device: {device}')\n", + "\n", + "dl_configs = [\n", + " dict(name='CharCNN', arch='cnn', epochs=20, batch_size=2048, lr=1e-3),\n", + " dict(name='CharBiLSTM', arch='bilstm', epochs=15, batch_size=2048, lr=5e-4),\n", + " dict(name='CNN-BiLSTM', arch='cnn_bilstm',epochs=15, batch_size=2048, lr=7e-4),\n", + "]\n", + "\n", + "# ─── Binary ───────────────────────────────────────────────────────────────\n", + "print('\\n\\u2500\\u2500 Binary: Deep Learning Models \\u2500\\u2500')\n", + "for cfg in dl_configs:\n", + " print(f\"\\nTraining {cfg['name']} (binary) …\")\n", + " model = DeepURLClassifier(\n", + " arch=cfg['arch'], num_classes=2,\n", + " epochs=cfg['epochs'], batch_size=cfg['batch_size'],\n", + " lr=cfg['lr'], device='auto',\n", + " )\n", + " model.fit(list(u_train), y2_train, class_weight='balanced')\n", + " preds = model.predict(list(u_test))\n", + " proba = model.predict_proba(list(u_test))\n", + " result = evaluate_model(cfg['name'], y2_test, preds, proba,\n", + " class_names=CLASS_NAMES_2, task='binary')\n", + " all_results_bin.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "── 4-Class: Deep Learning Models ──\n", + "\n", + "Training CharCNN (4-class) …\n", + " Epoch 1/20 loss=0.3261\n", + " Epoch 5/20 loss=0.0887\n", + " Epoch 10/20 loss=0.0556\n", + " Epoch 15/20 loss=0.0305\n", + " Epoch 20/20 loss=0.0211\n", + "\n", + "──────────────────────────────────────────────────\n", + " CharCNN (4c)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9819\n", + " Precision : 0.9741\n", + " Recall : 0.9767\n", + " F1 (macro): 0.9753\n", + " AUC-ROC : 0.9985\n", + "──────────────────────────────────────────────────\n", + "\n", + "Training CharBiLSTM (4-class) …\n", + " Epoch 1/15 loss=0.6086\n", + " Epoch 5/15 loss=0.1544\n", + " Epoch 10/15 loss=0.0932\n", + " Epoch 15/15 loss=0.0801\n", + "\n", + "──────────────────────────────────────────────────\n", + " CharBiLSTM (4c)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9730\n", + " Precision : 0.9615\n", + " Recall : 0.9699\n", + " F1 (macro): 0.9654\n", + " AUC-ROC : 0.9970\n", + "──────────────────────────────────────────────────\n", + "\n", + "Training CNN-BiLSTM (4-class) …\n", + " Epoch 1/15 loss=0.3709\n", + " Epoch 5/15 loss=0.0917\n", + " Epoch 10/15 loss=0.0624\n", + " Epoch 15/15 loss=0.0510\n", + "\n", + "──────────────────────────────────────────────────\n", + " CNN-BiLSTM (4c)\n", + "──────────────────────────────────────────────────\n", + " Accuracy : 0.9775\n", + " Precision : 0.9670\n", + " Recall : 0.9744\n", + " F1 (macro): 0.9705\n", + " AUC-ROC : 0.9979\n", + "──────────────────────────────────────────────────\n" + ] + } + ], + "source": [ + "# ─── 4-Class ──────────────────────────────────────────────────────────────\n", + "print('\\n\\u2500\\u2500 4-Class: Deep Learning Models \\u2500\\u2500')\n", + "for cfg in dl_configs:\n", + " print(f\"\\nTraining {cfg['name']} (4-class) …\")\n", + " model = DeepURLClassifier(\n", + " arch=cfg['arch'], num_classes=4,\n", + " epochs=cfg['epochs'], batch_size=cfg['batch_size'],\n", + " lr=cfg['lr'], device='auto',\n", + " )\n", + " model.fit(list(u_train), y4_train, class_weight='balanced')\n", + " preds = model.predict(list(u_test))\n", + " proba = model.predict_proba(list(u_test))\n", + " result = evaluate_model(cfg['name']+' (4c)', y4_test, preds, proba,\n", + " class_names=CLASS_NAMES_4, task='multiclass')\n", + " all_results_mc.append(result)\n", + " print_results_banner(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Optuna Hyperparameter Tuning" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tuning XGBoost (GPU, binary) …\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3df14b4177d343ffba5207983e26f2d5", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/60 [00:00. at 0x70508ca94040>)\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 1-2: surrogates not allowed\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 143, in orjson_packer\n", + " return orjson.dumps(obj, default=json_default, option=option)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "TypeError: str is not valid UTF-8: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 103, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/tornado/ioloop.py\", line 758, in _run_callback\n", + " ret = callback()\n", + " ^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 684, in \n", + " self.io_loop.add_callback(lambda: self._handle_events(self.socket, 0))\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 600, in _handle_events\n", + " self._handle_recv()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 629, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 550, in _run_callback\n", + " f = callback(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 169, in _handle_event\n", + " event_f()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 620, in _flush\n", + " self.session.send(\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 856, in send\n", + " to_send = self.serialize(msg, ident)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 727, in serialize\n", + " content = self.pack(content)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 145, in orjson_packer\n", + " return json_packer(obj)\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 111, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n" + ] + } + ], + "source": [ + "from evaluation import build_comparison_table, plot_accuracy_bar\n", + "\n", + "print('\\n\\ud83d\\udcca Binary Classification \\u2014 Final Comparison')\n", + "comparison_bin = build_comparison_table(all_results_bin, task='binary')\n", + "print(comparison_bin[['Method','Accuracy','F1 (macro)','AUC-ROC','Source']].to_string(index=False))" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 1-2: surrogates not allowed\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 143, in orjson_packer\n", + " return orjson.dumps(obj, default=json_default, option=option)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "TypeError: str is not valid UTF-8: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 103, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 550, in _run_callback\n", + " f = callback(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 169, in _handle_event\n", + " event_f()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 620, in _flush\n", + " self.session.send(\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 856, in send\n", + " to_send = self.serialize(msg, ident)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 727, in serialize\n", + " content = self.pack(content)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 145, in orjson_packer\n", + " return json_packer(obj)\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 111, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 1-2: surrogates not allowed\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 143, in orjson_packer\n", + " return orjson.dumps(obj, default=json_default, option=option)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "TypeError: str is not valid UTF-8: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 103, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 600, in _handle_events\n", + " self._handle_recv()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 629, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 550, in _run_callback\n", + " f = callback(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 169, in _handle_event\n", + " event_f()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 620, in _flush\n", + " self.session.send(\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 856, in send\n", + " to_send = self.serialize(msg, ident)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 727, in serialize\n", + " content = self.pack(content)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 145, in orjson_packer\n", + " return json_packer(obj)\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 111, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "ERROR:tornado.application:Exception in callback functools.partial(. at 0x705074b391c0>)\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 1-2: surrogates not allowed\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 143, in orjson_packer\n", + " return orjson.dumps(obj, default=json_default, option=option)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "TypeError: str is not valid UTF-8: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 103, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/tornado/ioloop.py\", line 758, in _run_callback\n", + " ret = callback()\n", + " ^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 684, in \n", + " self.io_loop.add_callback(lambda: self._handle_events(self.socket, 0))\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 600, in _handle_events\n", + " self._handle_recv()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 629, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 550, in _run_callback\n", + " f = callback(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 169, in _handle_event\n", + " event_f()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 620, in _flush\n", + " self.session.send(\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 856, in send\n", + " to_send = self.serialize(msg, ident)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 727, in serialize\n", + " content = self.pack(content)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 145, in orjson_packer\n", + " return json_packer(obj)\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 111, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n" + ] + } + ], + "source": [ + "print('\\n\\ud83d\\udcca 4-Class Classification \\u2014 Final Comparison')\n", + "comparison_mc = build_comparison_table(all_results_mc, task='multiclass')\n", + "print(comparison_mc[['Method','Accuracy','F1 (macro)','AUC-ROC','Source']].to_string(index=False))" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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VatM28bExFCyZEmcnJwstt8ZIY2JiTH+t7GxybDOtnz58hbfx8bGcuPGDdavX8/69eszPeeDjIZt27aN6tWrc+3aNa5duwaAp6cnqamphIaG8sILLwBw7tw5ypUrh63tvd+OnDt3jpIlS1KkSJEcx5GVu0f87rh27Rrz589n586d/PXXXxb74uLigNv5iI+Px93dPcv+nZ2dadasGdu3b2f48OHA7enhLi4u1K1bN8tjL1++nIMrsZTVjfEcHR25efNmlsff2X+/QvxeMstr27Zt2bhxI+PHj2fmzJnUq1ePFi1a0Lp1a2xssh7radu2LbNmzeLixYu4uLjwww8/8Ndff1nMhHjxxRcJCQmhX79+uLi40KBBA9q0aUPjxo0f6BoeVFRUFABvvvnmPdvExcVRuHBh4/sHfR1a29/jiIqKwmw2W3xIdresfmdFHnf67RAREclj7du3Z8KECVy5coXGjRv/a2sb74ymdejQgU6dOmXaJqfThKOiooybj2X25jw4ONgosK3lXiPZaWlp9zymQIECGbYNHz6cY8eO8corr+Dp6YmDgwPp6en07dv3gaajd+zYkdDQUI4ePcozzzzDnj176Nat232LyoYNG+b4XHf8fQnA3SpUqMDPP/9MSkrKPaeJ//rrr+TPnx83Nzcg57nNbDlBwYIFWbNmDQcPHmTv3r3s37+fnTt3sn79epYtW5bltO42bdowc+ZMQkJC6NOnDyEhIRQqVMiieH7iiSfYsmUL33zzDfv27WPfvn0EBQXRsWNHZsyYcc++re3Oa+SNN97A09Mz0zYODg4W3+fG69Aavw/p6emYTCYWL16c6c/n79chIv9HBbaIiEgea9GiBW+99RY//vgjs2fPvme70qVL8/333xMfH28xiv37778b++/8n56ezrlz5yxGre+0u6NYsWI4OjqSnp5O/fr1rXItwcHB5M+fn/feey9DIXnkyBFWr17N+fPnKVWqFGXLluWnn34iNTWV/PnzZ9pf2bJl+eabb7h27do9R7HvjAj+/XnA58+fz3bc169f5/vvv2fIkCEW09HvjEreUaxYMZycnDh16tR9+2zUqBHFihUjODiYZ599lsTERIs1u/eyfPnybMedE02bNuXYsWOEhIRkGkd0dDRHjhyhXr16FtOv4XZu7/7gJye5BbCxsaFevXrUq1ePMWPG8PHHHzN7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kJBAREQEFStWxMHBIa/DeSQop7lDec0dyqv1Kae5Q3nNHcqr9f2XchoeHp7tthrBFhEREREREbECFdgiIiIiIiIiVqACW0RERERERMQKVGCLiIiIiIiIWIEKbBERERERERErUIEtIiIiIiIiYgUqsEVERERERESsQAW2iIiIiIiIiBWowBYRERERERGxAhXYIiIiIiIiIlagAltERERERETEClRgi4iIiIiIiFiBCmwRERERERERK1CBLSIiIiIiImIFKrBFRERERERErEAFtoiIiIiIiIgVqMAWERERERERsQIV2CIiIiIiIiJWoAJbRERERERExApUYIuIiIiIiIhYgQpsEREREREREStQgS0iIiIiIiJiBSqwRURERERERKxABbaIiIiIiIiIFajAFhEREREREbECFdgiItlgMpmwt7fHZDLldSiPDOU0dyivuUN5tT7lNHcor7lDeZXsMpnNZnNeByEij6fw8HAAqlWrlseRiIiIiPz3pKWbyWfz3yz6ExISiIiIwNPTEwcHh7wOJ0s5ec9qm9vBiIhk5cKNVEbNOZXXYYiIiIj8p1QsWZAF3crkdRjyNyqwRSRPpdwyE34+Ka/DEBERERH5x7QGW0RERERERMQKVGCLiIiIiIiIWIEKbBERERERERErUIEtIiIiIiIiYgUqsB9zK1asoGfPntlqe/DgQby9vbNs8+OPPxIYGGiN0HLsfvF5eXnx66+//osRPXzmzZvHoEGD7rl/9OjRTJ06NVt9HTlyhG7dulkrNBERERHJRVFRUXTt2pVWrVrRuXNnTp3K+BSX9PR0ZsyYQfv27WndujVjx44lJSXF2L9o0SLatm2Lv78/gYGBHD9+3Ni3efNm/Pz88Pf3p2PHjnz99dfGvq+//ppOnTrh7+9P+/bt2bx5c+5ebB5Sgf03PXv2ZMWKFRm2e3h4EBER8e8HxO3C0cPDI0Mxk5KSQp06dfDw8ODGjRt5EtvfffDBBwwcOND4/vfff2fgwIHUqVOHmjVr0rp1axYtWmTs9/HxYffu3f9KbMeOHcPDwyNX+p43bx6VK1fGy8vL4t/df3QeNbVq1cLW1vZf+/mJiIiIyIObOHEigYGBhIWF0a9fP0aPHp2hzaZNmzh58iRBQUGEhIRgY2PDqlWrAIiIiGDdunVs3LiRrVu30r17d6ZMmQLAtWvXePvtt1m2bBlbt25l/PjxRv9ms5nXX3+dadOmsXXrVj7++GMmTpzIzZs3/72L/xepwH7IpaamAuDo6EhMTAxRUVHGvt27d1OsWLE8iiyj3377jcjISJo0aWJsGzBgAB4eHuzdu5dDhw4xb948ypR5NJ/X17RpU44dO2bxr3r16nkdVq7q1KkTa9asyeswRERERCQLf/31FydOnKBDhw4AtGrVigsXLnD27FmLdr/88gv169fHzs4Ok8lE48aN2bp1KwAmk4nU1FQSExMBiIuLw9XVFbg98m02m42i+e59d46Ni4sDID4+niJFimBnZ5e7F51HVGDnUGxsLNWqVeOPP/4wtiUnJ/Pcc8/x008/ER0djYeHBxs2bMDHx4c6deowadIki6kVJ0+epGfPntSuXZsWLVqwYcMGY9+8efMYMGAAb731FrVr12bmzJkA2NjY4O/vT1BQkNE2KCiIgIAAi/hSU1OZOXMmTZs2pW7dugwfPpzY2Fhj/6lTpwgMDMTLy4uePXty6dIli+P/+usvRo4cScOGDWnYsCFTp061iD0re/bswdvbm3z58hm5OnfuHF27dsXe3p58+fLh7u5OmzZtABg6dCjnz59nxIgReHl5MXHiRADee+89mjVrhpeXF23btiUkJMTiPCdOnKBXr17Url2bunXr8vbbb2caz+7du2nUqBGHDx8GLGchzJs3j4EDBzJlyhS8vb1p2rQpO3fuNI5NSUlh4sSJ1K5dGx8fHzZu3IiHhwfR0dHZysXf9ezZk5kzZ/LKK6/g5eVFp06dLKarL1++nKZNm+Ll5WWc747vvvuOLl264O3tTbt27fjyyy+NfaNHj2bs2LEMHToULy8v2rVrx2+//cZnn31G48aNqVu3boYCOC0tjbFjx1KzZk1atmzJrl277hn3uXPnGDhwIHXr1qVZs2Z89NFHpKenG/vr1avHDz/8QHx8/APlRURERET+mcTERBISErL8FxkZSfHixUlJSSEhIYHExERcXFyIjIy0aOfu7s7u3bu5dOkS169fJzg4mJiYGBISEihbtizdu3fH19eXRo0asXz5ckaNGkVCQgIFCxZk3LhxdOrUiSZNmjBmzBjeeust41zTpk1j8ODBNGnShBdffJHJkydz69atbMef1//MZnO2fx62ufWDflQVK1aMZs2asWXLFoYMGQLArl27KFmyJM8++6xRgO3a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7drh7OyMnZ0dffv25c8//+T8+fMA7Nq1CxcXFwIDA7GzsyMwMJDixYuza9cuAIoXL0737t2pXr16pv3/8ccfVKtWDQ8PD0wmEx07duTWrVv88ccfRpt69erx1Vdf3TP3IiIiIvLPJSYmkpCQcM9/kZGRFC9enJSUFBISEkhMTMTFxYXIyEiLdu7u7uzevZtLly5x/fp1goODiYmJISEhgbJly9K9e3d8fX1p1KgRy5cvZ9SoURnOtX37dkqXLs3TTz+do3P//d+d98f3u7aH4Z/ZbM72z8o2t14E8vgoWrQo5cqVY8yYMQQGBvLss89SunTpHPfToEED1qxZw5kzZ6hQoQJBQUG899577Nu3757H/PLLL7i4uODk5HTPNn/++Sf79++na9euxrZSpUqxcuVKXF1dOXjwIP3798fT05NatWoZbfbv38/mzZu5efMmgYGBBAcHGyPlN2/e5PTp03zxxRdER0fTuXNno9j+8MMPKVu2LIsXLwYgPDycfPnyATB27FhsbW3Ztm0btra2jB8/nilTpvD+++9n67xZ+eGHH3B2dubJJ58Ebq+VqVSpkkWbSpUq8euvv963L4C2bdsSFBTEzz//bBT+Li4uxlR8gAoVKnDlyhUuXbpEyZIls9WviIiIiORMZGSkUZDea39KSorFkr/ExETOnTtHoUKFjG3u7u64u7vTo0cP7OzsqFq1KnB7evilS5fYvn07M2fOpGjRooSFhTFkyBAmTZpkca41a9ZQt25d41zZPfe9REVFZScFec7Ozi5b7VRgyz9mMplYvXo1S5cuZcGCBfz++++UK1eOcePG0aBBg2z3Y2NjQ8eOHQkKCsLX1xdbW9t7jq7ecf369UyL699++w1vb2/MZjPx8fF4eXnh7+9v7G/VqpXxdd26dWnYsCE//PCDRYE9aNAgnJyccHJyolGjRpw8edIodM1mM8OHD6dAgQJUqFABLy8vTp48SZ06dbC1teXy5cvExMTg5uZGzZo1gdsj/V988QUHDhzA2dkZgKFDh9K+fXumT5+erfPey/nz55k4cSJvvvkmtra3f60TEhKM89zh7OzMzZs3s+zrjmLFitG0aVM6d+6MyWTC3t6e+fPnW8wouJP7GzduqMAWERERySXlypXLchTVxcWFadOm4e7ujq2tLWazmevXr1O7dm3Kli1r0bZy5crG16GhoURF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et9znzhxgnz58lG3bl0AXnjhBb766iuSk5OteYmPFD0H+xGUL18+unTpwtSpU4mMjKR69erZOq5v377Mnz+fl156ibJly2bYbzabWb16NWvXruXKlSt4enoyadIkKlSowNChQzl//jwjRowgX758+Pn5ZfhULD4+ng8++IC33nrLYrS0atWqfPLJJxZtN27cyPz580lKSqJz58688cYbAJw/f55x48YRERFBWloaXl5eTJw4kaeeegq4PRJtY2PDzZs32b9/P//73/+4fv06NjY2zJs3D1vb2y95Z2dnXnzxRYtztm3blm+++YZt27bRsWPHTHNUoEABevbsyQcffGB8Ing/e/bswdfXN1ttAb777jtmzZpFVFQULi4ujBgx4p7H9+/f3/ja1dWVjh07EhYWZmz7/PPP6dmzJ+XKlQNg2LBh9OjRg7feeouCBQtSv359AIKCgjLt/48//qB///44OjoCt3O0aNEiY7/JZKJu3brs2bOHWrVqZfsaRUREROS2xMREzGbzPfdHRkZSvHhxUlJSjJmKLi4uREZGUqJECaOdu7s7n3/+OQEBARQoUIDg4GBiYmJISEigbNmydO/eHV9fX5ydnbGzs2Pp0qUkJCQYx/fq1Ytbt25Ru3ZtXnvtNezt7YmKisLV1dVoZ2Njg6OjI2fPnjXef/+T6777/4eZ2WzGZDJlq60K7EdQamoq69evJ3/+/JQuXTrbx5UrVw5/f38+/PBDZs2alWH/2rVr2bRpEx9//DFPPfUUa9euZeDAgezYsYO5c+fi4+PD2LFjad68eab9//jjjyQlJdGmTZss47h58yanT5/miy++IDo6ms6dO9OkSRPq1KlDeno6ffr0oW7duqSmpjJ27FgmTJjA8uXLjeN37NjB/PnzmT17NsnJybz00ku0atXKKK7vxdbWlmHDhjFr1izatm2LnZ1dpu1eeeUV1q1bx/79+2nUqFGWfcLtKTn9+vW7bzu4/cnjsGHDmDt3LnXq1OHo0aMMGDCAjRs3Ur58+fsef+jQIYtp/b/++iuDBw82vvf09CQ5OZmoqCgqVap03/5eeuklQkNDadq0KWazmR07dtCsWTOLNhUrVuTbb7/N1vWJiIiIiKXIyMgsi8zIyEhSUlIslhcmJiZy7tw5ChUqZGxzd3fH3d2dHj16YGdnR9WqVYHb70UvXbrE9u3bmTlz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OpQ333yT2rVr4+LiwksvvXTfZ28XKlSIzz77zLhD+rVr1yhatCh16tTh1VdfzfSYatWq0bhx43v+kYLbBfHIkSMt7uSdGX9/fz766COuXr1qMZ3m79fcqVMnpk+fzsyZM/nwww/5/fffMZlMeHp68uabb2ba96xZs4iPj6dXr17GtlKlShlT17t06cKff/5Jt27dSEpKwsfHx/hEEm4/QmzMmDHG99WrV6d06dLs2bMHgI8++ohp06bRuHFj0tPT8fT0ZOHChUb7w4cP4+TklK01+CIiIiIijzqTOasV9SJiFZ988gk3btzg9ddfz+tQrOqVV17h5ZdfpkGDBg90fHh4OElJSVa7C6WIiIjIf4WTkxO1a9fO6zDyTEJCAhEREXh6ej70a7DDw8OB24Nw96MRbJF/wd/vvP2oyGqduoiIiIjI48YmrwMQEREREREReRSowBYRERERERGxAk0RF5E8ZTKZsvVcbhEREZFHiaOjY16HILlABbaI5KkCBQpk64YRIiIiIo8as9mMyWTK6zDEijRFXEQkGxITE/n5559JTEzM61AeGcpp7lBec4fyan3Kae5QXnNHbuVVxfWjRwW2iEg2mM1mEhMT0ZMNrUc5zR3Ka+5QXq1POc0dymvuUF4lu1Rgi4iIiIiIiFiBCmwRERERERERK1CBLSIiIiIiImIFKrBFRERERERErEAFtoiIiIiIiIgVqMAWERERERERsQIV2CIiIiIiIiJWoAJbRERERERExApUYIuIiIiIiIhYgQpsEREREREREStQgS0ikg0mkwl7e3tMJlNeh/LIUE5zh/KaO5RX61NOc4fymjuUV8kuk9lsNud1ECLyeAoPDwegWrVqeRyJiIiIyL8nLd1MPpvHu1hPSEggIiICT09PHBwc8jqcLOXkPattbgcjIpKVCzdSGTXnVF6HISIiIvKvqFiyIAu6lcnrMCSXqMAWkTyVcstM+PmkvA5DREREROQf0xpsEREREREREStQgS0iIiIiIiJiBSqwRURERERERKxABbbIPxQdHY2Hhwc3btz4V8/bt29f1qxZ86+eU0RERET+PVFRUXTt2pVWrVrRuXNnTp3KeGPY9PR0ZsyYQfv27WndujVjx44lJSXF2L9o0SLatm2Lv78/gYGBHD9+PEMfc+fOxcPDg4iIiAz7Pv/8czw8PNi9e7d1L+4RpQJb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zPL4+Ph4ChQogLOzMzdv3mTWrFk5juHWrVts3LgRe3t7ypQpc892KSkpJCcnG9/ny5ePvXv3Eh8fT+PGjSlWrJixpuZB1nM//fTTrF69mlKlSuX4WBERERHJmfLly7N+/foM26dOnWp8Xbx4cUJCQjI93mQyMXLkSGMaeFbuDAJlZvXq1dmIVkAFtki2NGvWjMWLF7Nw4ULmzJkD3J7W7e/vbzE1PDMvvfQSI0eOpEGDBhQtWpShQ4eybt26+54zLi7OKILz5ctHxYoVWbhwIYULF77nMQ0aNLD4fvDgwdStW5e1a9cyffp0kpOTKVKkCD4+PowYMeK+MWRGz70WEREREcmcyZzVynoRkVwUHh7OudgU+u3UsxVFRETk8VCtVEHChrnndRh5LiEhgYiICDw9PR/6Ndjh4eEAVKtW7b5ttQZbRERERERExApUYIuIiIiIiIhYgQpsERERERERESvQTc5EJE/Z2ZqoVqpgXochIiIi8q+oWFLvex5lKrBFJE+5OufXjT5ERETksZKWbiafjSmvw5BcoCniIiLZkJiYyM8//0xiYmJeh/LIUE5zh/KaO5RX61NOc4fymjusnVcV148uFdgiItlgNptJTExETza0HuU0dyivuUN5tT7lNHcor7lDeZXsUoEtIiIiIiIiYgUqsEVERERERESsQAW2iIiIiIiIiBWowBYRERERERGxAhXYIiIiIiIiIlagAltERERERETEClRgi4iIiIiIiFiBCmwRERERERERK1CBLSIiIiIiImIFKrBFRERERERErEAFtohINphMJuzt7TGZTHkdyiNDOc0dymvuUF6tTznNHcpr7lBeJbtMZrPZnNdBiMjjKTw8HIBq1arlcSQiIiIiDyYt3Uw+GxXeOZWQkEBERASenp44ODjkdThZysl7VtvcDkZEJCsXbqQyas6pvA5DREREJMcqlizIgm5l8joMeYiowBaRPJVyy0z4+aS8DkNERERE5B/TGmwRERERERERK1CBLSIiIiIiImIFKrBFRERERERErEAFtoiIiIiIiIgVqMCWR84rr7zC119/nddhPJL8/f0JCgoC4MiRI3Tr1i2PIxIRERH574iKiqJr1660atWKzp07c+pUxieppKenM2PGDNq3b0/r1q0ZO3YsKSkpxv5FixbRtm1b/P39CQwM5Pjx48a+oUOH0rBhQzw8PLhx44ZFv9evX2fkyJG0atWKdu3a8cEHH+TehT7GVGA/BpKSkmjdujXLly+32P7aa68xcuRI4/u0tDSWL1+On58fNWrUoF69egQGBvLpp59y69YtAIKCgvD09MTLywsvLy8aNmzIpEmTLH7pc0N0dHSmfyj+7sCBA1y9epUmTZoY2+Lj43n33Xdp0qQJ1atXp3nz5syfP9+4puwYPXo0U6dOfeD4raFnz56sWLEiT2O4W61atbC1tWX37t15HYqIiIjIf8LEiRMJDAwkLCyMfv36MXr06AxtNm3axMmTJwkKCiIkJAQbGxtWrVoFQEREBOvWrWPjxo1s3bqV7t27M2XKFOPYrl27snXr1kzPPXbsWCpXrkxYWBg7duygd+/euXORjzkV2I+BggULMmPGDObOncuZM2cA2LJlC8ePH2fixIlGu5EjR/L5558zfvx4Dhw4wLfffsuECRM4fvw4cXFxRrtnnnmGY8eOcezYMT7//HOOHj3K0qVL//XryszatWsJCAgwvk9NTaVv375ERESwbNkyjh07xocffkhYWBgjRozIw0gfDZ06dWLNmjV5HYaIiIjIQ++vv/7ixIkTdOjQAYBWrVpx4cIFzp49a9Hul19+oX79+tjZ2WEymWjcuLFRNJtMJlJTU0lMTAQgLi4OV1dX49j69evzxBNPZDj32bNnOXHiBC+99JKxrUSJEla/RtFzsB8bzz77LD169GD06NHMnj2bqVOn8sEHH1C4cGEADh48yJdffsnOnTspU6aMcVy1atV477337tmvi4sLDRs25PTp08a2K1eu8Pbbb3Pw4EEKFiyIv78/Q4YMwdb29svtm2++4YMPPuCPP/6gbNmyvP7669SvXx+Ab7/9lunTpxMdHY29vT0tWrRg8uTJPP/88wDGyPTkyZONP053pKamsn//foYOHWpsCw4OJjIykt27d1OoUCEAqlatyoIFC2jbti0HDx6kTp06zJs3jxMnTvDEE08QGhpK8eLFef3112nRogWrVq0iODgYk8nEpk2bKFWqFDt27MDHx4exY8fSvHlzAHbv3s27777Lnj17APDx8aFbt27s2rWLU6dOUaVKFd5//32efPJJAN577z1CQkK4du0aTz75JEOGDKFNmzaZ5nn69OkcPnyYY8eOMWfOHGrVqsWSJUvw8PBgy5YteHp6ArBixQq+/PJLVq9e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ITRq1Aiz2ZxhpHrLli306NEj2+cUEREREXmUmcz3W40v8h/zyiuv0KtXL4u7pN/PvHnziIiI4KOPPsrFyB4tR48e5f3332fdunUP3Ed4eDjnYlPot1PTk0REROS/p1qpgoQN01K5B5GQkEBERASenp4P/Rrs8PBw4PYjjO9Ha7DlkbN06dK8DuGxULNmzX9UXIuIiIiIPGo0RVxERERERETECjSCLQIMGTIkr0MQEREREZH/OBXYIpKn7GxNVCtVMK/DEBEREcmxiiX1HkYsqcAWkTzl6pxfNwcRERGR/6y0dDP5bEx5HYY8JLQGW0QkGxITE/n5558zPAtcHpxymjuU19yhvFqfcpo7lNfckVVeVVzL3VRgi4hkg9lsJjExET3Z0HqU09yhvOYO5dX6lNPcobzmDuVVsksFtoiIiIiIiIgVqMAWERERERERsQIV2CIiIiIiIiJWoAJbRERERERExApUYIuIiIiIiIhYgQpsEREREREREStQgS0iIiIiIiJiBSqwRURERERERKxABbaIiIiIiIiIFajAFhEREREREbECFdgiItlgMpmwt7fHZDLldSiPDOU0dyivuUN5tT7lNHcor7lDeZXsMpnNZnNeByEij6fw8HAAqlWrlseRiIiIiDyYtHQz+WxUeOdUQkICEREReHp64uDgkNfhZCkn71ltczsYEZGsXLiRyqg5p/I6DBEREZEcq1iyIAu6lcnrMOQhogJbRPJUyi0z4eeT8joMEREREZF/TGuwRURERERERKxABbaIiIiIiIiIFajAFhEREREREbECFdgiIiIiIiIiVqAC+zHSrl07vvrqq2y1DQoKwt/fP5cjyh3x8fE0b96c2NjYvA7lkXPjxg08PDyIjo4GYOHChcyePTuPoxIRERF5+EVFRdG1a1datWpF586dOXUq41NU0tPTmTFjBu3bt6d169aMHTuWlJQUY/+iRYto27Yt/v7+BAYGcvz4cWPf0KFDadiwIR4eHty4cSPTGObOnYuHhwcRERHWv0ABVGA/cnr27MmKFSsy3bdjxw6aNWtmlfPMmzePQYMGZdh+/vx5xowZQ6NGjfDy8qJZs2YMHTqUI0eOWMRYtWpVvLy88PLyol27doSEhBj7o6Oj8fDwoGnTpqSnp1v03759+/v+UVi2bBnNmzenWLFixrazZ88ydOhQateuTY0aNQgI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L7t27SIkJOSWccLVnl9nZ2c8PDy4cuUK06dPv+Ux12K4ltBWrlwZR0dHYmJijMedJSQk0KxZs0LF0K1bN3r37k1QUBANGjQgNzeXQ4cO4eHhwaOPPsozzzzDBx98QL169XBxccl38wKuzgNv0aJFoc4nIiIicr+qUqUKq1evzrd94sSJxu9eXl5Wj6+9nslkYsSIEQWuiQNXn5FdGH99uo/Ylh7TdQ967733qF27tvHTpk2bfGWaNGnCwIEDGThwIEFBQeTk5FCpUqVCT95v06YN7u7uNG7c2Bi6XKFCBaKiosjIyOC5554znnF94MABFixYYHX81KlTjedgP//880Y8BfH19b3hytp/5eDgwLPPPms15LlChQqsWrWKP/74gzZt2tCwYUPmzp3L66+/Ts+ePa2Ov7ZKecOGDfnf//7H3LlzjRsI/fr145NPPqF+/frGYhLvvPMO0dHR1KtXj9WrV/PMM88UKk6Al156CTs7O5544glCQ0OtetJvZOjQobz99ts0aNCARYsW4e7uzoQJE5g2bZqxSNm1BdsKo3r16kybNo2ZM2fSuHFjmjZtyvvvv2+sbjlgwABq1qxJaGgoHTp0yHcTJD09nV27dtGlS5dCn1NERERE5F5lstxsNr7cN7KysmjYsCGLFy+mXr16xR3OP5KWlkaHDh1Ys2aN1fzqW+nRowctW7Y05obLrV0b+fDKK6/8reMPHDjAiQtZ9Pm8cDd2RERERO4ktcqVIHaob3GHcVdKT08nISEBf3//O34O9oEDBwCoVavWLctqiPh97L///S/NmjUjLy+PmTNn4unpWag3zZ3O3d2d7du3F3cY94XIyMjiDkFERERE5I6hIeL3sY0bNxIUFETTpk05fPgw8+bNK/QQcREREREREbGmHuz7WEELVt3PtMpi8XByMFGrXOFWXhcRERG5k1Qtq+8wYk0JtogUKx8PR81dEhERkbtWbp4Fe7vCPydZ7m0aIi4iUghms5nDhw/f1uPs5ObUpkVD7Vo01K62pzYtGmrXonGzdlVyLddTgi0iUggWiwWz2YwevGA7atOioXYtGmpX21ObFg21a9FQu0phKcEWERERERERsQEl2CIiIiIiIiI2oARbRERERERExAaUYIuIiIiIiIjYgBJsERERERERERtQgi0iIiIiIiJiA0qwRURERERERGxACbaIiIiI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el9TUA+1yWQiMjKSt956i65du97xw3tERERE/g1VqlRh9erV+bZf/8gsLy8vtmzZUuDxJpOJESNGMGLEiAL3BwQEWHWmXFO7dm02bNjw94IWm9BzsEXuEFOnTjWegz148GAefPBB1q1bZ/WIrn/L0aNHqV27ttXPvn37Ciz71FNPUapUKT755JN/OUoRERERkTuLyXKzGfoiIkXowIEDnLiQRZ/PC7cqo4iIiEhxqVWuBLFDfYs7jHtGeno6CQkJ+Pv73/FzsA8cOABArVq1bllWPdgiIiIiIiIiNqAEW0RERERERMQGlGCLiIiIiIiI2IBWEReRYuXkYKJWuRLFHYaIiIjITVUtq+8rcmtKsEWkWPl4OGrBEBEREbkr5OZZsLczFXcYcgfTEHERkUIwm80cPnwYs9lc3KHcM9SmRUPtWjTUrranNi0aateica1dszIzijsUucMpwRYRKQSLxYLZbEZPNrQdtWnRULsWDbWr7alNi4batWioXaWwlGCLiIiIiIiI2IASbBEREREREREbUIItIiIiIiIiYgNKsEVERERERERsQAm2iIiIiIiIiA0owRYRERERERGxASXYIiIiIiIiIjagBFtERERERETEBpRgi4iIiIiIiNiAEmwRERERERERG1CCLSJSCCaTCRcXF0wmU3GHcs9QmxYNtWvRULvantq0aKhdi4bJZMLR0bG4w5C7gMlisViKOwgRuT8dOHAAgFq1ahVzJCIiIiI3l52TS052Fi4uLsUdyj0hPT2dhIQE/P39cXV1Le5wbup2vrM6FHUwIiI3c+pyNiPf/6W4wxARERG5oaplSzD3uQrkZBd3JHKnU4ItIsUqK8fCgZSM4g5DREREROQf0xxsERERERERERtQgi0iIiIiIiJiA0qwRURERERERGxACbaIiIiIiIiIDSjBFrkH9OrVi127dv2r58zNzSU0NJRff/31Xz2viIiIyJ0uKSmJbt26ERISQqdOnfjll/xPTMnLy2Py5Mm0a9eONm3aMHr0aLKysoz9ixYtom3btoSFhdG1a1d++uknY9+PP/5I+/btCQkJISIigtOnTwNw+vRpevXqRUhICKGhoQwePJgLFy4U/QWLQQm23JMyMjJo06YNS5cutdo+cOBARowYYbzOzc1l6dKlhIaG8vjjj9O4cWO6du3KJ598Qk5ODgDR0dH4+/sTEBBAQEAAQUFBvPnmm1YfgEXh5MmT+Pn5cfny5ZuW++6777h48SLNmzc3tmVkZDBz5kxCQkKoU6cOQUFB9OjRgw0bNhhlZs+eTfXq1QkICKBu3bqEhoayadOmm547OjqasLAwAOzt7Xn55ZeZPn26ja5YRERE5N4wbtw4unbtSmxsLH369GHUqFH5ykRFRXHo0CGio6PZsmULdnZ2fPzxxwAkJCSwcuVK1q5dy8aNG3nhhRd46623gKuJ+ciRIxk9ejSxsbE0b96ciRMnAle/n/Xv35/Y2FhiYmIoX74877333r934aIEW+5NJUqUYPLkycyaNcvoYd2wYQM//fQT48aNM8qNGDGCdevW8frrr/Pdd9/x7bffMnbsWH766SdSU1ONco899hjx8fHEx8ezbt06vv/+e5YsWfKvX1dBVqxYQXh4uPE6Ozubl156ib179zJ16lT27dvHjh07GDJkSL5e7hYtWhAfH09cXBz9+/fnP//5z231SIeEhLB7925SUlJsdj0iIiIid7Pz589z8OBB2rdvD1z9vnTq1CmOHz9uVe7IkSM0adIEJycnTCYTzZo1Y+PGjQCYTCays7Mxm80ApKam4uPjA8DBgwext7enUaNGADz77LPs2LGDzMxMvLy8qF+/vnGOOnXqkJycXOTXLP+PnoMt96w6derQvXt3Ro0axYwZM5g4cSJTp06lVKlSAOzZs4cvvviCzz//nAoVKhjH1apV66Z3+ry9vQkKCuLYsWPGtnPnzjFhwgT27NlDiRIlCAsLY/DgwTg4XP0n9s033zB16lR+//13KlasyKuvvkqTJk0A+Pbbb3n33Xc5efIkLi4utG7dmvHjx9OlSxcAo2d6/Pjxxgf1NdnZ2Xz99dcMGTLE2BYTE0NSUhL//e9/KVmypLG9QYMGNGjQoMBrsrOzo23btowfP55jx45Ro0aNWzcw4OrqSq1atdi5cyfPP/98oY4RERERuVtlZmZisVhuWiYxMREvLy+ysrKMEY/e3t4kJiby4IMPGuV8fX1Zt24d4eHhODs7ExMTQ3JyMunp6VSsWJEXXniBli1b4uHhgZOTE0uWLCE9PZ2kpCR8fHxIT08Hrn6Pc3Nz4/jx45QvX96oPzc3l48//pgWLVoYZe8k124eXPvvncxisWAymQpVVgm23NMGDx7Mzp076dy5MyEhIVbDqL/55htq165tlVwXxh9//MHXX39Nt27djG0jRozAy8uLL774gj///JO+ffvi4uJCZGQkx48fZ8CAAUydOpXg4GC2b99O//792bRpExUqVOD//u//GDlyJB06dCA9PZ0jR44AsHbtWlq2bMmuXbvw8PAoMJbjx49jNpupXLmy1XU1bdrUKrm+ldzcXLZu3cqVK1fw8/O7rfaoWrWqEbOIiIjIvSwlJeWWCWFiYiJZWVkkJCQY28xmMydOnLD6fubr64uvry/du3fHycmJmjVrAleHh585c4ZNmzYxbdo0PD09iY2NZfDgwbz55pskJyeTlpZmVX9ubi7Hjh0zRmBaLBaWLFmCyWQiICDAquydJikpqbhDKBQnJ6dClVOCLfc0Jycn6tSpw9q1a+nYsaPVvosXL1K2bFmrbSEhIZw/f56srCxmzpxJcHAwAD///DP169fHYrGQlpZGQECAMRf59OnTxvByNzc33NzciIyMZM6cOURGRvL5558TGBjIU089BUCbNm1Ys2YNmzdvJjIyEkdHR06cOMGFCxcoU6YMdevWLfT1Xbp0CRcXF+zt7a2u6/oe6KysLKO3PDMzk7Vr11KtWjUAdu3aRf369bG3t6d8+fJMmzaNSpUqcfLkyULH4O7uftd8MIqIiIj8E+XKlbtlouXt7c2kSZPw9fXFwcEBi8XCpUuXCAwMpGLFilZlq1evbvy+detWkpKS8Pf3Z9++fdSuXdv4DlepUiWWLVtG1apVycvLY8OGDfj7+wNw5coVzGYzjRs3xtnZGYB3332XzMxM5s2bh6Ojoy2bwGbMZjNJSUlUqlQJFxeX4g7npq4fuXorSrDlnrZ79262bt3Ks88+y4QJE1i7dq3xIePp6UliYqJV+djYWACCg4PJy8sztj/22GPGnJgrV67w/vvv07t3b1atWsWpU6dwdnbGy8vLKF+hQgVOnToFwKlTp3j44YetzlO+fHlj/5w5c1iwYAFt2rShXLly9O3bl7Zt2xbq+kqVKoXZbCY3N9dIsj09PTlz5oxRxsnJibi4OAD8/PyshjU1b96cefPm5av3WhtdW+jtmpycHGPY+zVpaWnGsHsRERGRe5mzs/Mtk0FXV1dq1KjB9u3bCQ8PZ+vWrfj4+BgdHNdkZmaSkZFBqVKluHDhAsuWLWPo0KG4urpSpUoVYmJisFgsuLm5sXPnTipVqkSpUqWoV68eubm5/PTTTzRq1IiVK1cSHByMp6cnAG+//TYpKSksWLCg0L2uxcnFxQVXV9fiDuOmCjs8HJRgyz0sLS2NMWPGMGrUKMLCwujSpQsLFy5k0KBBADRp0oRly5Zx8uRJq/kqt+Lm5kbnzp1ZtmwZFy9exMfHh8zMTM6dO2ck2cnJycZCFD4+Puzfv9+qjuTkZGM+dI0aNZg9ezZ5eXls376dYcOGERgYiJ3drdcgfOSRR3BxcSExMZGqVasa1zV9+nTS0tJwd3cv9HVdz8vLC0dHR06ePEmZMmWM7SdOnMh3s+DYsWOEhIT8rfOIiIiI3IvGjx/Pa6+9xsKFC3Fzc2PSpEkAjBkzhuDgYFq2bElqaio9evTAzs6OvLw8IiIijNGTrVu35sCBA3Tq1AknJydcXV2ZNm0acHXO9ZQpUxg3bhxZWVmULVvWWD9o//79LF++nCpVqhjr+ZQvX565c+cWQyvcn5Rgyz1r0qRJVK1alc6dOwNXh8o899xztGrVimrVqtG4cWNatGhB//79GTt2LLVr18bJyYkjR45w5cqVG9abkZFBdHQ0ZcuWpXTp0phMJho2bMjkyZMZP348f/75JwsWLKBDhw4AtG3blvnz57N9+3ZatGjBl19+SVxcnPGor88//5wnn3ySUqVKGfNy7O3tKVOmDHZ2dpw4ccKYk/NXjo6OBAUFsWfPHiPBbt++PVFRUURGRjJq1Cgee+wx7Ozs+OGHHwrddvb29rRr146ZM2cyadIkHnzwQX744QeioqJ4++23jXJms5kDBw7wzjvvFLpuERERkXtdlSpVWL16db7t1x6nBVc7NLZs2VLg8SaTiREjRlg9XvZ6AQEBxMTE5Nter149jh49+jejFltQgi33pF27drFt2zarD55q1arRq1cv/u///o+oqCgcHR2ZPn06H330EW+99Ra///47bm5uPPzwwwwdOpSmTZsax/78888EBAQAV5PaGjVqsGjRImO4yLRp05gwYQJPPvkkJUqUIDQ0lN69ewNXe5lnz57N9OnT+c9//kOFChWYM2cOFSpUICsri02bNjFp0iSysrIoV64cU6dONYb4DBw4kD59+pCdnc0bb7xBaGhovmt9/vnnmTp1Ki+88AJwdUj40qVLWbBgAcOHD+fUqVN4eHhQqVIlpk6dymOPPVaoNnz99deZOXMm3bp149KlSzz88MOMGDGCVq1aGWViY2Np2LBhvl5tEREREZH7kclyq3XmReSO16tXLyIiIqxWSS9qeXl5hIWFMWPGDKP3/HYdOHCAExey6PP5nT8/SERERO5ftcqVIHaoL2az+Y5fkOtukZ6eTkJCAv7+/nf8HOwDBw4AVx/neyvqwRa5ByxZsuRfP6ednV2BQ5NERERERO5Xt15FSURERERERERuST3YIlKsnBxM1CpXorjDEBEREbmhqmX1XUUKRwm2iBQrHw9HYof6FncYIiIiIjeVnZNb3CHIXUBDxEVECsFsNnP48GHMZnNxh3LPUJsWDbVr0VC72p7atGioXYuG2Wwm4fAhtD603IoSbBGRQrBYLJjNZv2P1YbUpkVD7Vo01K62pzYtGmrXomGxWMjOzi7uMOQuoARbRERERERExAaUYIuIiIiIiIjYgBJsERERERERERtQgi0iIiIiIiJiA0qwRURERERERGxACbaIiIiIiIiIDSjBFhEREREREbEBJdgiIiIiIiIiNqAEW0RERERERMQGlGCLiIiIiIiI2IASbBGRQjCZTLi4uGAymYo7lHuG2rRoqF2LhtrV9tSmRUPtWjTUnlJYDsUdgIjI3cDFxYXq1asXdxj3FLVp0VC7Fg21q+2pTYuG2rVoODs74+joWNxhyF1ACbaIFKvMzEz27t1b3GGIiIiIFMjNzY0aNWrg4KDUSW5N7xIRKVYWi4W0tLTiDkNERERE5B/THGwRERERERERG1CCLSIiIiIiImIDSrBFREREREREbEAJtoiIiIiIiIgNKMG+h40dO5bAwECeeOKJ4g6lSPzwww907drVJnWdPHkSPz8/Ll++XOD+uLg4mjVrZpNz3SvS0tJo1aoVFy5cKO5QRERERO4ISUlJdOvWjZCQEDp16sQvv/ySr0xeXh6TJ0+mXbt2tGnThtGjR5OVlQXA119/TVhYmPETFBREx44djWM3bNhA+/btadeuHT179iQlJcXYt2vXLjp27EhYWBjt2rVj/fr1RX/Bks89k2D36NGDmjVrEhAQQGBgIN27d+fAgQNWZfz8/KhTpw4BAQHGz9GjR4s8ttmzZzNgwIACY/7oo48A2LNnD35+fkZcTz75JNOmTSMvL++W9RQkLi6O2NhYvvjiC7799tt/fA2jRo1i4sSJ/7geW5o6dSqRkZHG699++43IyEgaNmxI3bp1adOmDYsWLbLJuerXr89XX31lk7psafLkyYSEhBAQEEBwcDALFy602p+dnc1bb71FgwYNCAwMZMKECeTk5Bj7P/nkE8LDw6lZs2aB762DBw/y3HPPUbduXVq2bMmGDRuMfe7u7nTo0IEFCxYU2fWJiIiI3E3GjRtH165diY2NpU+fPowaNSpfmaioKA4dOkR0dDRbtmzBzs6Ojz/+GICmTZuyceNG46dGjRqEhoYC8OuvvzJlyhQWL17Mpk2bCA8P58033wSuPpXl1VdfZdKkSWzcuJEFCxYwbtw4PamlGNwzCTbAyJEjiY+P55tvvqF27doMHjw4X5lVq1YRHx9v/Pj5+RVDpAUrWbKkEdfixYtZv3490dHRf6uukydP8tBDD1GyZEkbR/n3WCwWcnNzbVbfzz//TGJiIs2bNze29evXDz8/P3bu3Mm+ffuYPXs2FSpUsNk570TOzs7MmTOHuLg4PvjgA1avXs3q1auN/fPnz2f//v1s3ryZTZs2ERcXZ5UQly1blgEDBhQ4EuDy5cv07duX9u3bs2/fPqZPn86ECROIi4szynTo0IHo6GjMZnPRXqiIiIjIHe78+fMcPHiQ9u3bAxASEsKpU6c4fvy4VbkjR47QpEkTnJycMJlMNGvWjI0bN+ar7/Tp0+zevZuwsDAAfvnlF/z8/ChbtiwAzZs356uvvuLixYsAmEwmUlNTgasjDUuXLo2Tk1ORXa8U7J5KsK9xcnKiY8eO/PHHH397+Orx48fp1asXgYGBtGrVyuhpBoiOjiYsLIy5c+fSuHFjmjRpYrXfFh599FHq1q3LoUOHbvvYjz/+mLFjx/Lzzz8TEBBg3Dk7ceIEkZGRNGrUiCeffJJ58+YZPeQpKSm89NJLNGrUiAYNGtC3b19Onjxp1BcTE8PKlSsJCAjgmWeeASA4OJjt27cb592+fTvBwcHG62s9ql27dqVOnTocO3aM8+fPM2LECIKCgggKCmLixInGkJg///yTgQMH0qBBA+rXr094eDjJyckFXuOXX35J/fr1sbe3B+DChQucOHGCbt264eLigr29Pb6+vjz99NPGMUuXLuWpp54iICCAVq1a8cknnxRYb+vWralfvz6jRo0iOzsbuDrCoH79+ka5Hj16MG3aNHr16kVAQAAdO3a0Gg1x6tQpXnrpJerWrUt4eDgLFiywaptz584xdOhQGjVqRIsWLZgxY4bRszxw4ECrURY1atQo8O4nwLBhw/D19cXe3p5HH32U1q1bs3//fmP/unXr6N+/P2XLlqVs2bJERkaybt06Y/9TTz1Fq1at8PT0zFd3fHw8Tk5OPPfcc9jb21OnTh2eeuopoqKijDLly5endOnS7N27t8D4RERERO4lZrOZ9PT0An8SExPx8vIiKyuL9PR0zGYz3t7eJCYmWpXz9fVl+/btnDlzhkuXLhETE0NycnK++tasWcMTTzyBi4sL6enpPPLIIxw6dIiEhATS09OJiorCYrHw22+/YTabmTRpEoMGDaJ58+Y8//zzjB8/npycnBvGW9w/1zpobtamd8qPxWIp9HvEoajefMUpIyODqKgoPD098fDwuO3jc3Jy6NevH8HBwcybN4/ExER69+7NAw88YAzROHbsGGFhYXz11Vd8//33vPzyywQHB1OxYkWbXMPRo0eJi4ujX79+t31sREQE7u7uLFu2zLgbZjabefHFF4mIiGDWrFmcO3eOvn378uCDD9KlSxfy8vJ48cUXadSoEdnZ2YwePZqxY8eydOlSIiIiOHz4MCVLlmTMmDG3FUt0dDTz58/nkUceITc3l+7du1O3bl22bdtGRkYGQ4YMYd68eQwbNowPP/yQ3NxcvvrqK5ycnPj5559xc3MrsN6EhASqVKlivPb09KRy5cq89tprRkL/8MMPWx1Trlw5li1bho+PD3v27KFv3774+/tTr149o8zXX3/N+vXruXLlCl27diUmJobw8PACY9i4cSOLFi2iatWqjB8/nrfffpvly5cDMGLECCpVqsT8+fP5448/6NOnj9WxI0aMwMvLiy+++II///yTvn374uLiQmRkJHPnzjXKHTt2jBdeeIF27drdsq0tFgv79u0zboBcunSJU6dO4e/vb5Tx9/cnJSWF1NTUW45uyMvLy/dhkpeXx88//2y1rWrVqhw5csRqNIGIiIjIvSgpKemG+xITE8nKyiIhIcHYZjabOXHihNX3Ll9fX3x9fenevTtOTk7UrFkTwOo4i8XC2rVriYiIsNres2dPRo4cSW5uLgEBAbi6unLixAlyc3OZNWsWgwcPxt/fn19//ZXXXnuNd99992/lQ/+mm7XpnaSwowHuqQR7+vTpzJkzh7S0NB544AHmzJmDg4P1JT7//PNGr6e/v7+REF3vxx9/5OzZ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RERERMQGlGCLiIiIiIiI2IASbBEREREREREbUIItd6RevXqxa9eu4g7jXxMQEMDRo0eLO4zbsn//fp577rniDkNERETuIUlJSXTr1o2QkBA6derEL7/8kq9MXl4ekydPpl27drRp04bRo0eTlZVl7E9JSSEyMpKQkBDatm3L8uXLjX2LFi2ibdu2hIWF0bVrV3766Sdjn5+fH6GhoYSFhREWFkZcXFzRXqzck5Rg3yUyMjJo06YNS5cutdo+cOBARowYYbzOzc1l6dKlhIaG8vjjj9O4cWO6du3KJ598Qk5ODgDR0dH4+/sTEBBAQEAAQUFBvPnmm1YfTEXh5MmT+Pn5cfny5ZuW++6777h48SLNmzcHYM+ePfj5+RnxPvnkk0ybNo28vLwii/Xnn3+mW7duBAQE0Lx583ztXpBRo0ZRs2ZNAgICqFevHp07d+bbb78t1Pni4+Px8/O7rRjPnz/PiBEjaNasGXXr1qVDhw588cUXVmVOnz5Nnz59ePzxx2nRogVr1qyx2j927FhCQkKoVq0aH330Ub5zbNq0iaeffpqAgAA6depk9T+hevXq4eDgwPbt228rbhEREZEbGTduHF27diU2NpY+ffowatSofGWioqI4dOgQ0dHRbNmyBTs7Oz7++GPg6tNJBg0aRFhYGLGxsXz++ec8/fTTACQkJLBy5UrWrl3Lxo0beeGFF3jrrbes6v7000/ZuHEjGzdupH79+kV/wXLPUYJ9lyhRogSTJ09m1qxZ/PrrrwBs2LCBn376iXHjxhnlRowYwbp163j99df57rvv+Pbbbxk7diw//fQTqampRrnHHnuM+Ph44uPjWbduHd9//z1Lliz516+rICtWrCA8PNxqW8mSJY14Fy9ezPr164mOji6yGMaPH4+/vz/79u1j48aN1KlTp1DHPffcc8THx7Nnzx7atm3LoEGDbnlD4e9KT0+nevXqrFmzhri4OIYMGcKIESM4duyYUWbEiBF4eXnxv//9j/fff5/33nvP6pnT1apV480336R27dr56t+/fz9vvPEG7777LnFxcXTp0oW+fftavY86duzIp59+WiTXJyIiIveX8+fPc/DgQdq3bw9ASEgIp06d4vjx41bljhw5QpMmTXBycsJkMtGsWTM2btwIwO7du3FycjKSagAvLy8ATCYT2dnZmM1mAFJTU/Hx8fk3Lk3uI3oO9l2kTp06dO/enVGjRjFjxgwmTpzI1KlTKVWqFHC1p/eLL77g888/p0KFCsZxtWrV4r333rthvd7e3gQFBVklZufOnWPChAns2bOHEiVKEBYWxuDBg3FwuPqW+eabb5g6dSq///47FStW5NVXX6VJkyYAfPvtt7z77rucPHkSFxcXWrduzfjx4+nSpQuA0TM9fvx44wP0muzsbL7++muGDBlyw3gfffRR6taty6FDh+jcuTMAS5cuZeXKlZw9e5YHHniAF198ke7duxvHHDhwgIkTJ3Ls2DHKli3LgAEDaNeu3Q3PYW9vT7ly5XBwcKB06dLUrVv3hmUL4uDgwLPPPsvkyZM5ceIEv/76Kx988AHJycmUKlWKDh06MHToUEwmE3B1SNKGDRvw9/fn0KFDjB8/nmPHjuHo6EhAQAALFizId44KFSrQq1cv43VwcDCVK1fmhx9+oGrVqpw4cYL9+/czc+ZMXF1dqVOnDqGhoaxbt47AwEAAXnjhBQDmzZuXr/4vvviCli1bGjcXunXrxqJFi9i2bZtxA6Rx48aMHTuWtLQ03N3db6uNRERE5P5hNpuxWCw3LZOYmIiXlxdZWVnGyEpvb28SExN58MEHjXK+vr6sW7eO8PBwnJ2diYmJITk5mfT0dA4fPoyHhweDBw/m+PHjlCtXjuHDh1O+fHkqVqzICy+8QMuWLfHw8MDJyYklS5aQnp5u1B0REUFOTg6BgYEMHDgQFxcXI/7r/yv/3N3UphaLxfjefitKsO8ygwcPZufOnXTu3JmQkBAjWYWrSW/t2rWtkuvC+OOPP/j666/p1q2bse1az+cXX3zBn3/+Sd++fXFxcSEyMpLjx48zYMAApk6dSnBwMNu3b6d///5s2rSJChUq8H//93+MHDmSDh06kJ6ezpEjRwBYu3YtLVu2ZNeuXXh4eBQYy/HjxzGbzVSuXPmG8R49epS4uDj69etnbCtXrhzLli3Dx8eHPXv20LdvX/z9/alXrx6XL1+md+/eDBo0iG7duhEfH0+/fv146KGHqFevXoHnqF+/PnPmzMHf35+goKDbak+4eqNg5cqVuLm5UalSJc6fP8/s2bOpVKkSR44coVevXlSpUiXfDQaACRMm8OSTT7Jq1SpycnL48ccfC3XO8+fP8+uvvxpDzY8ePcqDDz5o3LUF8Pf3Z8WKFYWqz2KxFPg/wuvnij/00EM4OTnxyy+/EBAQUKh6RURE5P6TmJh4y0QqMTGRrKwsEhISjG1ms5kTJ05QsmRJY5uvry++vr50794dJycnatasCVwdAp6SksKePXt46623KF++PNu3b2fIkCFMnDiRM2fOsGnTJqZNm4anpyexsbEMHjyYN998E4BZs2bh5eVFRkYGH374IePGjePll1+2ijEpKck2DSKGu6VNnZycClVOCfZdxsnJiTp16rB27Vo6duxote/ixYuULVvWaltISAjnz58nKyuLmTNnEhwcDFydY1y/fn0sFgtpaWkEBAQQFhYGXJ23e214uZubG25ubkRGRjJnzhwiIyP5/PPPCQwM5KmnngKgTZs2rFmzhs2bNxMZGYmjoyMnTpzgwoULlClT5rZ6fy9duoSLiwv29vZW21NTU6lfvz5ZWVlkZmYSHh5utcBWSEiI8XujRo0ICgpi79691KtXj507d1KmTBl69OgBQGBgIO3atWPDhg0FJtjX5ussXryYV155hTfffJNWrVoBVxcji4qK4tFHHy0w/pUrV7J+/XocHR2pUqUKCxYswN3d3epGiL+/P8888wx79+4tMMF2cHAgJSWFM2fO4OPjQ4MGDW7ZbllZWbzyyis8/fTT1KpVC4ArV67ku5FRsmRJrly5csv6AJo1a8aAAQPYv38/tWvXZs2aNaSkpJCWlmZVzt3dvciGwYuIiMi9oXLlyrfswfb29mbSpEn4+vri4OCAxWLh0qVLBAYGUrFiRauy1atXN37funUrSUlJ+Pv7c/LkSQ4fPkzr1q0BqFSpEkuXLqVq1ars27eP2rVrG6MuK1WqxLJly6hatSqOjo5W9ffu3Zu3334bf39/4Gqin5SURKVKlYxebfln7qY2vX6k760owb7L7N69m61bt/Lss88yYcIE1q5da3wgeHp6kpiYaFU+NjYWuDp8+PpFwR577DFjrsqVK1d4//336d27N6tWreLUqVM4Oztb9XxWqFCBU6dOAXDq1Ckefvhhq/OUL1/e2D9nzhwWLFhAmzZtKFeuHH379qVt27aFur5SpUphNpvJzc21SrJLlixJXFwcubm5rFu3jsWLF5OZmWncSfrss89YunQpycnJ5OXlkZGRQfny5W8Yb4UKFdi3b1+BMSxdupSXX36ZBg0asHDhQnr16oXZbKZKlSqUKlXqhsk1XJ2DPWbM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PaSKK5Nrosphgk1EVAGCIEChUIBPNpQOY6oejKt6MK7SY0zVg3Elql5MsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkwASbiIiIiIiISAJMsImIiIiIiIgkIBMEQajuThDRm+nixYsQBAHa2trV3ZWXEgQBhYWF0NLSgkwmq+7u1AmMqXowrurBuEqPMVUPxlU9GFfp1aaYKpVKyGQyODo6vrRuvSroDxFRmWr6L9NnyWSyWnEhoDZhTNWDcVUPxlV6jKl6MK7qwbhKrzbFVCaTVfjvVs5gExEREREREUmA92ATERERERERSYAJNhEREREREZEEmGATERERERERSYAJNhEREREREZEEmGATERERERERSYAJNhEREREREZEEmGATERERERERSYAJNhEREREREZEEmGATERERERERSYAJNhEREREREZEEmGATERERERERSYAJNhEREREREZEEmGAT0RslKSkJo0aNgr29PVxcXLBixQoolcqXtsvKykJgYCB69eoFe3t7DBgwANu3by+z7rFjx/Dxxx/D3t4eXbp0ga+vL+7duyf1UGoUdcf1t99+g6+vL7p06YKuXbtizJgx+Pvvv9UxlBqjsjHNycnBggUL0LVrV3Ts2BG+vr5lxionJwdz586Fk5MTHBwc4O/vj/v376tjKDWKOuN65coVBAQEwMPDAx07dsS7776LkJAQ5OXlqWs4NYK6v6vPmjhxIuRyOTZv3ixV92usqojrH3/8AT8/Pzg4OMDR0REfffQRf7eWo6JxvXHjBsaPH49u3bqhc+fO8PHxwdmzZ9UxlBojJSUFgYGB8PLygp2dHQYMGFChdoIgIDw8HL169UKHDh0wdOhQ/PHHH6XqZWRkYPLkyXBwcICTkxPmzZuH3NxciUchHSbYRPTGyM7OxsiRI1FYWIi1a9di2rRp2LlzJ5Yv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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA3QAAAKsCAYAAACkiv9NAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAD6nElEQVR4nOzdd1gUVxsF8DPb6FURe8OIvTeiYuxiib3GXqOosSZqEhM/WywxxpJojMbee0VRY4lGY+xdUbGL9A7b5vsD3bguKLuuDgvn9zw+srMzl7PLsMw7984dQRRFEURERERERGRzZFIHICIiIiIiIsuwoCMiIiIiIrJRLOiIiIiIiIhsFAs6IiIiIiIiG8WCjoiIiIiIyEaxoCMiIiIiIrJRLOiIiIiIiIhsFAs6IiIiIiIiG8WCjoiIiIiIyEaxoCMiykZ69OiBHj16SB3jg/D19cX8+fMl+/7pvdcREREYPnw4atasCV9fXyxfvhynT5+Gr68vTp8+/cEzNmjQAOPGjfvg3/elJUuWoFmzZtDr9ZJleJ3U74ktGzduHBo0aGC0zJLfQyl/J1517NgxVK5cGVFRUZLmIHpXCqkDEFHmbN26FePHjzc8lsvlyJUrF2rXro2RI0fC29vbZBtRFLFjxw5s2rQJN2/ehEajQeHChdG0aVP07dsXjo6O6X6v4OBgbNiwAZcvX0ZiYiLc3d1RtWpVdOnSBX5+fm/NmpqainXr1mHPnj24e/cu1Go18ufPj9q1a6NHjx4oVqyY5W9EDvPo0SM0bNjQaJmTkxMKFSqEjh07omvXrpDL5RKlez+uX7+OpUuX4syZM4iMjISjoyPKlCmDVq1aoU2bNln69U6fPh3Hjx/H0KFDkTt3bpQrVw4RERHv9XueO3cOJ06cQK9eveDq6vpev5c5EhIS8Pvvv+PLL7+ETPbf+WNfX1+j9RwcHJA/f360bNkSffr0gYODw4eOmi28+lnxxRdfYMiQISbrjB49Grt374ajoyPOnz//oSNmOf7+/ihcuDAWL15s9PeVyNawoCOyMcOHD0fBggWhVqtx4cIFbNu2DWfPnsXu3bthZ2dnWE+n02H06NHYt28fqlWrhqFDh8LBwQH//vsvFi5ciP379+OPP/5A7ty5DduIoogJEyZg69atKFOmDPr06YPcuXMjPDwcwcHB6N27N9atW4cqVapkmC8qKgr9+/fH1atXUb9+fbRs2RKOjo64d+8e9u7di40bN+LKlSvv9T3Kjlq2bAl/f38AaQfKR48exeTJk/H48WN89dVXhvWWLl0qVUSr2LRpE7777jvkypULrVu3RpEiRZCYmIhTp07h66+/Rnh4OD7//HOpYwJI/70+deoUGjZsiH79+hmWFStWDJcuXYJSqXwvOc6fP48FCxagbdu2JgVdUFAQBEF4L9/3bTZv3gytVouWLVuaPFe7dm20bt0aAJCUlIR///0XP//8M27cuIF58+a911xSvicfgp2dHfbs2WNS0CUlJeHw4cNGfyes4dKlS2afZKlevfp7/Z0wR+fOnTFz5kwMGzYMzs7OUschsggLOiIb4+/vj/LlywMAOnbsCA8PDyxZsgSHDh1C8+bNDev9/vvv2LdvH/r27Wt0wN+5c2cEBAQgMDAQ48aNw++//254btmyZdi6dSt69eqF8ePHGx30DB48GNu3b4dC8eaPjfHjx+P69euYN28emjZtavTciBEj8NNPP73T639Jq9VCr9dDpVJZpb2srkyZMoYDYADo1q0bOnbsiN27dxv9fKV6P5KSkjLs8c2sCxcu4LvvvkOlSpXw22+/GR1c9e7dG5cvX8bt27ffNarVpPdeR0ZGmhRVMpnM6gfRmSXl78fWrVvRoEGDdF970aJFjfbnrl27QqPRIDg4GKmpqe/1/crunxn16tXDgQMHcOPGDZQqVcqw/NChQ9BoNKhTp45Vhzpa8rOS8nfidU2bNsWUKVMQFBSEDh06SB2HyCK8ho7IxlWrVg0A8PDhQ8OylJQULF26FEWLFsXo0aNNtmnQoAHatGmD48eP48KFC4ZtfvvtNxQvXhxfffVVumew27RpgwoVKmSY5eLFizhy5Ag6dOhgUswBaQdSrxYfGV3v9fp1Go8ePYKvry+WLl2K5cuXo1GjRihfvjyuX7+OMmXKYMGCBSZt3L17F76+vli9erVhWVxcHKZOnYp69eqhXLlyaNy4MX777TeT63v27NmDdu3aoXLlyqhSpQpatWqFFStWZPi6pSAIAnLnzm1SYL/+nr68VmXv3r349ddfDScEevXqhfv37xtt+++//2L48OH45JNPUK5cOdSrVw/Tpk1DSkqK0Xrjxo1D5cqV8eDBAwwYMACVK1fGmDFjMG/ePJQtWzbd61G+/fZbVKtWDampqRm+pgULFkAQBMyePTvdM+Xly5dHu3btMtz+8ePH+P7779G0aVNUqFABNWvWxPDhw/Ho0SOj9TQaDRYsWIAmTZqgfPnyqFmzJrp27YoTJ04Y1gkPD8f48ePh7++PcuXKoU6dOhg8eLBRW6++11u3boWvry9EUcSaNWvg6+trGFqY0fVCFy9exIABA1C9enVUqlTJZD+7ceMGxo0bh4YNG6J8+fKoXbs2xo8fj+joaMM68+fPx8yZMwEADRs2NHzflznTu17s4cOHGD58OGrUqIGKFSuiU6dOOHLkiNE65uw36Xn48CFu3ryJjz/++K3rvuTl5QVBEEx6ey5evIh+/fqhatWqqFixIrp3746zZ88arTN//nz4+vri/v37GDduHKpVq4aqVati/PjxSE5ONlo3vffkxo0b6N69OypUqAB/f3/88ssv2LJli9F7+XLbQYMG4d9//0WHDh1Qvnx5NGzYENu3b3/ja9NoNKhRo0a6w/oSEhJQvnx5zJgxw7Bs1apVaNGiBSpWrIjq1aujXbt22LVr1xu/x0uVKlVCwYIFTdbftWsX6tSpA3d3d5NtDh48iIEDB6JOnTooV64cGjVqhIULF0Kn0731+6V3DV1YWBgmTJhgaK9Bgwb47rvvoFarAWT8O7Fv3z60a9fO8Ps7ZswYhIWFGa2T2b8bQOY+y3PlygVfX18cOnTora+VKKtiDx2RjXv8+DEAGPUKnD17FrGxsejZs2eGPWpt2rTB1q1b8eeff6JSpUo4e/YsYmJi0LNnT4uvUTp8+DAAGJ15t6atW7ciNTUVnTp1gkqlgpeXF6pXr459+/Zh6NChRuvu3bsXcrkczZo1AwAkJyeje/fuCAsLQ5cuXZAvXz6cP38ec+bMQXh4OL7++msAwIkTJzBq1Cj4+flhzJgxANKKw3PnzqFXr17v5XVlRnJysqFQSkxMxLFjx3D8+HEMHDgwU9svWbIEgiCgb9++hmubxowZg02bNhnWCQoKQkpKCrp27Qp3d3dcunQJq1evxrNnz0yGwWm1WsNB9ldffQV7e3tUrlwZCxcuxN69e9G9e3fDumq1Gvv370eTJk0yPCufnJyMU6dOoVq1asifP7+5bw8A4PLlyzh//jxatGiBvHnz4vHjx1i3bh169uyJPXv2GK7NWrBgARYvXoyOHTuiQoUKSEhIwJUrV3D16lXUrl0bADBs2DCEhISge/fuKFCgAKKionDixAk8ffoUBQsWNPne1atXx8yZM/Hll18aDSfMyIkTJzBo0CDkyZMHPXv2RO7cuXHnzh0cOXLEsJ+dPHkSDx8+RLt27eDl5YXbt29j48aNCAkJwcaNGyEIAho3bozQ0FDs3r0b48ePh4eHBwDA09Mz3e8bERGBLl26IDk5GT169ICHhwe2bduGwYMHY968eWjcuLHR+pnZb9Lz8vqsMmXKpPt8amqqYX9OTk7GuXPnsG3bNrRs2dLoM+vvv//GgAEDUK5cOQwdOhSCIBhGEaxdu9bkBNOIESNQsGBBjBo1CteuXcOmTZvg6emJsWPHZpg1LCzM8J4PHDgQjo6O2LRpU4Y9effv38cXX3yBDh06oG3bttiyZQvGjRuHsmXL4qOPPkp3G6VSiUaNGiE4OBiTJk0yavvgwYNQq9WGERYbN27ElClT0LRpU/Ts2ROpqam4efMmLl68iFatWmX4Ol7VsmVL7Ny5E2PGjIEgCIb9d+bMmTh+/LjJ+tu2bYOjoyP69OkDR0dHnDp1CvPmzUNCQoLRSbjMCAsLQ4cOHRAfH49OnTqhePHiCAsLw/79+5GSkpLh+/ryOvHy5ctj1KhRiIyMxMqVK3Hu3Dls377d7OtDzfksL1u2LA4ePGhW+0RZCQs6IhuTkJCAqKgoqNVqXLx4EQsWLIBKpUL9+vUN64SEhACA0XCb17187u7duwCAO3fuADCdsMAcL9soWbKkxW28ybNnzxAcHGx0sNq8eXNMnDgRt27dMvq++/btQ/Xq1Q3XCP7xxx94+PAhtm3bhqJFiwIAunTpgjx58mDp0qXo27cv8uXLhyNHjsDZ2RlLly7NUpNvzJ8/3+QseNeuXTF8+PBMbZ+amort27cbDqZcXV0xdepUo/dtzJgxsLe3N2zTuXNnFClSBHPmzMGTJ0+MCi21Wo1mzZqZ9ABXrlwZO3fuNCrojh49itjY2DcWOffv34dGo3mnfeeTTz4xFPAv1a9fH507d8b+/fvRpk0bAMCRI0dQr149TJ48Od124uLicP78eXz55ZdG18INGjQow+9dqFAhFCpUCF9++aXJcMLX6XQ6TJw4EXny5DE5UBVF0fB1t27d0LdvX6NtK1WqhFGjRuHs2bOoVq0aSpUqhTJlymD37t1o1KhRusXmq3777TdERERgzZo1ht79jh074tNPP8X06dPRsGFDowlMMrPfpOfl50pGeTZv3ozNmzcbLWvUqBGmTJli9F58//33qFmzJn7//XfDqIEuXbqgRYsWmDt3LpYtW2bURunSpTFt2jTD45iYGGzevPmNBd2SJUsQGxuLbdu2oXTp0gCAdu3apTvKAADu3btn9P4FBASgXr162Lp16xuLn+bNm2PLli04ceKE0ef13r17UahQIcNQ+iNHjuCjjz56p2sJW7ZsiUWLFhn2k3379kGlUqFBgwbpFnQ//vij0e9+165dMXHiRKxbtw4jR440a5jqnDlzEBERgY0bNxpeE5A2Ucur+/erNBoNZs+ejZIlS2LNmjWGEz9Vq1bFoEGDsHz58kx/1r1kzmd5oUKFEB0djcjISOTKlcus70OUFXDIJZGN6d27N/z8/FCvXj0MHz4cDg4O+PXXX5E3b17DOomJiQDSZkPMyMvnEhISjP5/0zZvY4023qRJkyYmPQ+NGzeGQqHA3r17Dctu3bqFkJAQo2sKg4KCULVqVbi6uiIqKsrw7+OPP4ZOp8OZM2cApB2wJicnGw2/ywo6d+6MP/74A3/88Qfmz5+Pzz77DBs2bMD06dMztX27du2MDsrSG6r76gFdUlISoqKiULlyZYiiiGvXrpm02bVrV5NlrVu3xsWLF/HgwQPDsl27diFfvnyoUaNGhvmsse+8ml+j0SA6OhqFCxeGq6urUX5XV1fcvn0boaGhGbajVCrxzz//IDY21uI8Gbl27RoePXqEnj17mvQ6vDrU+dXX87JHq2LFigCAq1evWvS9jx49igoVKhh+/kDae965c2c8fvzYcDLopczsN+mJiYmBQqHI8OfZsGFDw/78yy+/YNCgQTh+/DhGjx5tOOi/fv06QkND0apVK0RHRxt+Z5OSkuDn54czZ86YDJfu0qWL0eNq1aohJibGsH+l5/jx46hUqZKhmAMAd3f3DHvDSpQoYfT+eXp6olixYm99T2rVqgUPDw+jz6rY2FicPHnS6LPK1dUVz549w6VLl97Y3pt89NFH8PX1xZ49ewAAu3fvRsOGDTOcQfTVfe3lScNq1aohOTnZUJxnhl6vx8GDB1G/fn2jYu6ljCajuXLlCiIjI9G1a1ejXvxPPvkExYsXNxkSnBnmfJa//D18dTgzkS1hDx2RjZk4cSKKFSuG+Ph4bNmyBWfOnDE5e/ryIOplYZee14u+l9csvWmbt3m1jfcxfXp6Z/s9PT1Rq1Yt7Nu3DyNGjACQdsZboVAYDR+7f/8+bt68meFtF14O/+rWrRv27duHAQMGwNvbG7Vr10ZAQIBhhsmMREVFZep6k/R4enq+9QxykSJFjK5HatKkCQRBwIoVK9C+ffu39qy+Pozx5c8nLi7OsOzJkyeYN28eDh8+bFLIvH5ArFAojE4ivNS8eXNMmzYNO3fuxNChQxEfH48///wTvXv3fuPMgtbY/1JSUrB48WJs3boVYWFhRr0B8fHxhq+HDx+OIUOGoGnTpihZsiTq1KmD1q1bG3qtVSoVxowZgxkzZqB27dqoWLEiPvnkE7Rp0wZeXl4W53vp5YH/23ojY2JisGDBAuzduxeRkZFGz736eszx5MkTQ1H4quLFixuefzVXZvYbS+TNm9dof27YsCHc3d0xY8YM/Pnnn2jQoIGh4H5Tr1d8fDzc3Nzemjc2NjbDGQwfP36MSpUqmSwvXLhwuuvny5fPZJmbm9tbi3+FQoEmTZpg9+7dUKvVUKlUOHDgADQajVFBN2DAAJw8eRIdO3ZEkSJFULt2bbRs2RJVq1Z9Y/uva9myJf744w/07t0b58+ff+PssLdv38bcuXNx6tQpk991c/a1qKgoJCQkZDj0NCNPnjwBgHRvaVO8eHGTayYzw5zP8pefFdl59lPK3ljQEdmYChUqGM58NmrUCN26dcPo0aMRFBRkKM58fHwApF3o36hRo3TbuXnzptG6Lw/obt68meE2b/OyjVu3bhmdwTZXRoXRq2eRX9WiRQvD7JqlS5fGvn37UKtWLaPePL1ej9q1a6N///7ptvFyGGauXLmwfft2/PXXXzh27BiOHTuGrVu3ok2bNkaTFryuQ4cOhusZzXXo0KG3DpVLj5+fH1avXo1///33rQXdq8PoXvXyQEan06FPnz6IjY1F//79Ubx4cTg6OiIsLAzjxo0z6QlRqVTptunm5ob69etj165dGDp0KIKCgqBWq/Hpp5++MV+RIkWgUChw69atN673JpMnTzZcX1WpUiW4uLhAEASMHDnSqLirXr06goODcejQIZw4cQKbN2/GihUrMGnSJHTs2BFAWk94gwYNcPDgQfz111/4+eef8dtvv2HFihUZXhdmbSNGjMD58+fRr18/lC5dGo6OjtDr9ejfv3+GQ9es7W37TUbc3d2h1WqRkJCQ6angX55sOXPmDBo0aGD4Hl9++aVR79mrXp9Z1dK85niXodgtWrTAhg0bcOzYMTRq1AhBQUEoXry40fB4Hx8fBAUF4ciRIzh+/DgOHDiAtWvXIjAw0Kxhhy1btsScOXPwzTffwN3d3XB96Ovi4uLQvXt3ODs7Y/jw4ShcuDDs7Oxw9epVzJ49O0vdFP5NXv+7Yc5n+csTFC+vQSWyNSzoiGyYXC7HqFGj0LNnT6xZs8YwQcbLoYW7d+/G4MGD0z0AeTkr28trOapWrQo3Nzfs2bMHn3/+uUUHLfXr18fixYuxc+fOTBV0bm5u6Q5Tenm2NrMaNWqEiRMnGoYyhYaGmlzvVLhwYSQlJWVq1r2X15o0aNAAer0e33//PTZs2IAhQ4agSJEi6W4za9asN87g+CaW9vpotVoA79ar9dKtW7cQGhqKGTNmGK41A2DR0NPWrVtjyJAhuHTpEnbt2oUyZcq89Yy9g4MDatWqhVOnTuHp06fp9oK8zcvr5F6dwTA1NTXdHgZ3d3e0b98e7du3R2JiIrp374758+cbCjogbZ/p27cv+vbti9DQULRp0wbLli3D7Nmzzc72qkKFCgFIe88z2h9jY2Px999/Y9iwYUYT/qQ3TNScXoX8+fPj3r17JstfDquzdEKa1708ufPo0aM3Xsv7qpf7c1JSEoD/3idnZ2ezZss0V4ECBdKdufPVYcPWUr16dXh5eWHv3r2oUqUKTp06lW7PmaOjI5o3b47mzZtDrVZj2LBhWLRoEQYNGpTp6f7z58+PKlWq4J9//kHXrl0znCDrn3/+MfQGV69e3bD89dlhM8PT0xPOzs5m317k5X537949k1EU9+7dM9ovzfm7kdnP8kePHsHDwyPDyYSIsjpeQ0dk42rWrIkKFSpgxYoVhoLCwcEBffv2xb1799K979uRI0ewbds21KlTxzDUyMHBAf3798edO3cwe/bsdM9o79ix443XdVSuXBl169bFpk2b0p0xTK1WG50ZLVSoEO7evWs0zf2NGzdw7ty5TL9+IG1YVZ06dbBv3z7s2bPHMKPcqwICAnD+/Pl0JwSIi4szHEy+fg2FTCYz9H69nHI7PVWrVsXHH39s0T9L78f0559/Anjz5DeZ9bJn49WfuyiKWLlypdlt+fv7w8PDA7///jvOnDnz1t65lwIDAyGKIr788st0i9QrV65g27ZtGW6f3kmIVatWmZy5f/1n7OTkhMKFCxt+vsnJySbFeeHCheHk5PTGfSCzypYti4IFC2LlypUmQxdfvv8ZnVBJ7/YZL6+LyszQuHr16uHSpUuGWSiBtAJq48aNKFCgAEqUKJHp1/EmlStXBpD2M8us1/fncuXKoXDhwli2bFm6+0N6t8ewRJ06dXDhwgVcv37dsCwmJibTtwkwh0wmQ7NmzfDnn39i586d0Gq1RsMtAdP9U6VSwcfHB6IoQqPRmPX9RowYgaFDh6Y7zf+rmQDj3321Wo21a9ea9b1ettWoUSP8+eefuHz5ssnzGfWUlitXDrly5cL69euNfseOHj2KO3fu4JNPPjEsy+zfDXM+y69evZrusFsiW8EeOqJsoF+/fvjiiy+wdetWw0QVAwcOxPXr17FkyRJcuHABTZo0gb29Pc6ePYudO3fCx8fHZNhJ//79ERISgmXLluH06dNo2rQpcufOjYiICBw8eBCXLl3C+vXr35hl5syZ6Nu3L4YOHYr69evDz88PDg4OuH//Pvbu3Yvnz58bronp0KEDli9fjn79+qFDhw6IjIzE+vXrUaJECbN7nZo3b46xY8di7dq1qFOnjsk1fP369cPhw4fx+eefo23btihbtiySk5Nx69Yt7N+/H4cOHYKnpye++eYbxMbGolatWvD29saTJ0+wevVqlC5d2jA8VQrXrl3Djh07AKT1yJ06dQr79+9H5cqVUadOnXduv3jx4ihcuDBmzJiBsLAwODs7Y//+/RZdK6VUKtGiRQusXr0acrkcLVq0yNR2VapUwcSJEzFp0iQEBASgdevWKFKkCBITE/HPP//g8OHDhusk0/PJJ59gx44dcHZ2RokSJXDhwgWcPHnS5L5bLVq0QI0aNVC2bFm4u7vj8uXL2L9/v2FmztDQUPTu3RvNmjVDiRIlIJfLcfDgQURERGT6tbyJTCbD999/j8GDB6NNmzaG2xLcvXsXISEhWLp0KZydnVG9enX8/vvv0Gg08Pb2xokTJ9LtNSlbtiwA4KeffkLz5s2hVCpRv379dG/0PnDgQOzZswcDBgxAjx494Obmhu3bt+PRo0eYP39+hkMWzVWoUCGULFkSf//9d7o3aw4NDTXszykpKbhw4QK2b9+OIkWKGGYIlclkmDJlCgYMGICWLVuiXbt28Pb2RlhYGE6fPg1nZ2csWrTonbP2798fO3fuRJ8+fdC9e3fDbQvy5cuHmJgYq19XFRAQgFWrVmHevHkoWbKkyedKv379kDt3blSpUgW5cuXC3bt3sXr1atSrVy/Tw1dfqlGjxhsnIwLSim83NzeMGzcOPXr0gCAI2LFjh8XDVEeNGoUTJ06gR48e6NSpE3x8fBAeHo6goCCsXbs23eurlUolxowZg/Hjx6N79+5o0aKF4bYFBQoUQO/evQ3rZvbvRmY/yyMjI3Hz5k1069bNotdLlBWwoCPKBpo0aWI4k92pUyfI5XLI5XLMnTsX27dvx6ZNm/Dzzz9Do9GgcOHCCAwMRN++fdO9/mTmzJlo2LAhNm7ciGXLliEhIQEeHh6oXr06xo4dazjznhFPT0+sX78ea9euxd69e/HTTz9Bo9GgQIECaNCgAXr27GlY92VROW/ePEyfPh0lSpTAzJkzsXv3bvzzzz9mvQcNGjSAvb09EhMTTc54A2m9GKtWrcLixYsRFBSE7du3w9nZGUWLFsWwYcPg4uICAPj000+xceNGrF27FnFxcfDy8kJAQACGDRtmtYNdS+zevRu7d+8GkDa5Qr58+dCvXz8EBgZaJZdSqcSiRYswZcoULF68GHZ2dmjcuDE+++wzi+4r2Lp1a6xevRp+fn7IkydPprfr0qULypcvj2XLlmH79u2Ijo6Go6MjypQpg+nTp7+xt+/rr7+GTCbDrl27kJqaiipVquCPP/4wuW6yR48eOHz4ME6cOAG1Wo38+fNjxIgRhlsU5M2bFy1atMDff/+NnTt3Qi6Xo3jx4pg7d26GU9mbq27dulixYgUWLlyIZcuWQRRFFCpUCJ06dTKs8+OPP2Ly5MlYu3YtRFFE7dq1sWTJEtStW9eorQoVKuCLL77A+vXrcfz4cej1ehw6dCjdgi537txYv349Zs2ahdWrVyM1NRW+vr5YtGiRUS+INbRv3x4///wzUlJSTK5/PXHihGE4r1wuh5eXFzp27IgvvvjCKHfNmjWxYcMG/PLLL1i9ejWSkpLg5eWFChUqoHPnzlbJmS9fPqxcudKw73t6euKzzz6Dg4MDpkyZYnEPekaqVKmCfPny4enTp+l+VnXu3Bm7du3CH3/8gaSkJOTNmxc9evTAkCFDrJrjJQ8PDyxatAgzZszA3Llz4erqik8//RR+fn5Gt+3ILG9vb2zcuBE///wzdu3ahYSEBHh7e8Pf3z/D66CBtBlV7e3tsWTJEsyePRuOjo5o1KgRxo4da1QEZvbvRmY/yw8cOACVSoWAgACzXytRViGIH+rKaiIiyjFu3LiB1q1bm1yTRzlHfHw8GjVqhDFjxhhdm2grpk6dig0bNuD8+fNZ6p6UZF1t2rRBjRo1MGHCBKmjEFmM19AREZHVbdy4EY6OjmjSpInUUUgiLi4u6NevH5YuXZrlZ0pMSUkxehwdHY2dO3eiatWqLOaysWPHjuH+/fsmk2gR2Rr20BERkdUcPnwYISEhmDdvHj777DOMHz9e6khEb9W6dWvUqFEDPj4+iIiIwJYtW/D8+XMsX77caOZHIqKsiAUdERFZTYMGDRAREYE6depg5syZZk/iQCSFOXPmYP/+/Xj27BkEQUCZMmUwdOjQ93q7BCIia2FBR0REREREZKN4DR0REREREZGNYkFHRERERERko3gfugycP38eoihCqVRKHYWIiIiIiHIQjUYDQRDeev9fgD10GRJFEVnt8kJRFKFWq7NcLrIt3I/IGrgfkTVwPyJr4H5E1pDV9iNzahH20GXgZc9c+fLlJU7yn6SkJFy/fh0lSpSAo6Oj1HHIRnE/ImvgfkTWwP2IrIH7EVlDVtuPLl++nOl12UNHRERERERko1jQERERERER2SgWdERERERERDaKBR0REREREZGNYkFHRERERERko1jQERERERER2SgWdERERERERDaKBR0REREREZGNYkFHRERERERko1jQERERERER2SgWdERERERERDaKBR0REREREZGNYkFHRERERERko1jQERERERER2SgWdERERERERDaKBR0REREREZGNYkFHRERERERko1jQERERERER2SgWdERERERERDYqSxV09+/fx8SJE9G6dWuUKVMGLVu2zNR2oijit99+wyeffIIKFSqgc+fOuHDhwvsNS0REREREJLEsVdDdvn0bR48eRZEiReDj45Pp7ZYsWYJ58+ahd+/eWLx4Mby8vNC3b188fPjwPaYlIiIiIiKSVpYq6Bo0aICjR49i3rx5KFu2bKa2SU1NxeLFi9G3b1/07t0bfn5+mDNnDtzd3bF06dL3nJiIiIiIiEg6Waqgk8nMj3Pu3DkkJCQgICDAsEylUqFx48Y4duyYNeMRERERERFlKQqpA7yru3fvAgCKFy9utNzH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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ─── Accuracy bar chart ───────────────────────────────────────────────────\n", + "fig_bar = plot_accuracy_bar(\n", + " comparison_bin,\n", + " save_path=str(OUTPUT_DIR / 'results_accuracy_bar.png'),\n", + ")\n", + "plt.show()\n", + "\n", + "# ─── ROC curves (binary) ─────────────────────────────────────────────────\n", + "from sklearn.metrics import roc_curve, auc\n", + "\n", + "fig_roc, ax_roc = plt.subplots(figsize=(9, 7))\n", + "ax_roc.plot([0,1],[0,1], 'k--', lw=1, label='Random')\n", + "\n", + "roc_models = {\n", + " 'XGBoost (GPU)': ('feat', clf_models_bin['XGBoost (GPU)']),\n", + " 'LightGBM (CPU)': ('feat', clf_models_bin['LightGBM (CPU)']),\n", + " 'TF-IDF + LR': ('url', tfidf_bin),\n", + " 'XGBoost (tuned)': ('feat', tuned_xgb),\n", + " 'LightGBM (tuned)': ('feat', tuned_lgbm),\n", + "}\n", + "\n", + "for name, (src, mdl) in roc_models.items():\n", + " try:\n", + " X_in = u_test if src == 'url' else X_test_sc\n", + " prob = mdl.predict_proba(X_in)[:, 1]\n", + " fpr, tpr, _ = roc_curve(y2_test, prob)\n", + " roc_auc = auc(fpr, tpr)\n", + " ax_roc.plot(fpr, tpr, lw=1.5, label=f'{name} (AUC={roc_auc:.3f})')\n", + " except Exception as e:\n", + " print(f' Skip {name}: {e}')\n", + "\n", + "# HyperModel\n", + "try:\n", + " fpr, tpr, _ = roc_curve(y2_test, hyper_proba[:, 1])\n", + " roc_auc = auc(fpr, tpr)\n", + " ax_roc.plot(fpr, tpr, lw=2.5, color='crimson', linestyle='--',\n", + " label=f'HyperModel (AUC={roc_auc:.3f})')\n", + "except Exception as e:\n", + " print(f' HyperModel ROC skip: {e}')\n", + "\n", + "ax_roc.set_xlabel('False Positive Rate')\n", + "ax_roc.set_ylabel('True Positive Rate')\n", + "ax_roc.set_title('ROC Curves \\u2014 Binary Classification (Benign vs Malicious)')\n", + "ax_roc.legend(loc='lower right', fontsize=8)\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'results_roc_curves.png', dpi=150)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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/fp1NG7cWONY7dq1Ua1aNdy6dQvA/+bpqOftqCUkJMDAwADW1tZiXGJiotZ+QImJiWIbJiYmeOedd7TaUl+njlN/TUxM1LpnnTp1SjUsBjARIiIioueoU6cOLl68qHHs9u3bePz4MerWrQsAsLa2RoMGDbB//36NuJiYGHh4eIirv7y9vZGeno4TJ06IMYmJibh48SK8vb3FY97e3oiLi4NKpdJoS6FQwNXVFQDQokULVK1aFfv27RNjVCoVYmNjNdp6EQ6NERERSZFE9hHq06cPvvrqK8ybNw8dOnRAWloaVq5cierVq2ssXR8zZgwmTZqE+vXrw83NDTExMTh//jw2bNggxqh3pp42bRomT54MQ0NDLFmyBA4ODujUqZMYFxwcjD179mDixIno27cvrly5gsjISIwfP15MqgwNDTF8+HAsW7YMlpaWsLe3x+bNm5GWlobg4OBSP59MeLY+VUkYu4ZUdBeIJOvxqbCK7gKRpBnpoIxg3PHrcmsr5+Dkl75WEARs2bIFmzdvRlJSEkxNTeHi4oLx48fDzs5OIzYqKgoRERG4c+cObGxsMGHCBPj4+GjEZGZmYv78+Th48CDy8/Ph5eWFGTNmoFatWhpxp0+fxoIFC3Dp0iVYWlri448/xtChQzWW3qs/YmPTpk1ITU2Fo6Mjpk6dKlaNSoOJEBFpYSJE9HyVKRF623FojIiISIokMjT2tmMiREREJEWvuNqLSofpJhEREVVarAgRERFJEYfGdIKJEBERkRRxaEwnmG4SERFRpcWKEBERkRRxaEwnmAgRERFJEYfGdILpJhEREVVarAgRERFJEYfGdIKJEBERkRQxEdIJfpeJiIio0mJFiIiISIo4WVonWBEiIiKiSosVISIiIiniHCGdYCJEREQkRRwa0wmmm0RERFRpsSJEREQkRRwa0wkmQkRERFLEoTGdYLpJRERElRYrQkRERBIkY0VIJ5gIERERSRATId3g0BgRERFVWqwIERERSRELQjrBRIiIiEiCODSmGxwaIyIiokqLFSEiIiIJYkVIN5gIERERSRATId3g0BgRERFVWqwIERERSRArQrrBRIiIiEiKmAfpBIfGiIiIqNJiRYiIiEiCODSmG6wIERERSZBMJiu316vo378/HBwcin3t3btXjIuKioKfnx+cnJzQtWtXHD58WKutzMxMTJs2Da1b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r2P37t1wdXWFgYEB/vjjD0RGRqJv375MgoiI6KUxEaI3gpGREc6cOYPNmzfjyZMnqFWrlsbGcURERC+DQ2NERERUaXG5DREREVVaTISIiIio0mIiRERERJUWEyEiIiKqtJgIERERUaXFRIiokuvQoQOmTJkivj958iQcHBxw8uTJCuyVpmf7SERUXpgIEVWwHTt2wMHBQXw5OTnBz88PX375pfjJ4W+C3377DcuWLavobhARlQk3VCSSiLFjx6JevXpQKpX466+/sHnzZvFDM42NjXXWj/feew/nz5/X+AT10vjtt9+wceNGbnJJRG8UJkJEEuHt7Q0nJycAwIcffggLCwusWbMGcXFxCAoK0orPzs6GiYlJufdDT08PhoaG5d4uEZEUcWiMSKLc3d0BAMnJyZgyZQpcXV1x69YtDB06FK6urpg0aRIAoLCwEGvXrkVgYCCcnJzQpk0bzJo1C+np6RrtCYKAFStWwNvbG82bN0f//v1x9epVrfuWNEfo3LlzGDp0KN577z24uLigS5cuWLduHQBgypQp2LhxIwBoDPOplXcfiYjKCytCRBJ169YtAICFhQUAID8/H8HBwWjZsiUmT54sftjsrFmzsHPnTvTo0QP9+/dHcnIyNm7ciIsXL2Lz5s3iENd3332HlStXol27dmjXrh3++ecfDB48GCqV6oV9OXbsGIYPH46aNWtiwIABqFGjBq5fv45ff/0VAwcORO/evXH//n0cO3YMCxcu1LpeF30kInoZTISIJCIrKwupqalQKpU4ffo0li9fDiMjI/j4+ODs2bNQKpXo3LkzJk6cKF7z559/IioqCosWLUKXLl3E425ubhgyZAj279+PLl26IDU1FT/88APat2+P77//HjKZDACwZMkSfP/998/tV0FBAWbNmoWaNWvi559/hkKhEM+pP6rQ1dUVDRo0wLFjx9CtWzeN63XRRyKil8WhMSKJGDRoEDw8PNCuXTuMHz8epqamCAsLQ61atcSYvn37alyzf/9+mJmZwdPTE6mpqeKradOmMDExEYe3jh8/DpVKhX79+okJBgAMHDjwhf26ePEikpOTMWDAAI0kCIBGWyXRRR+JiF4WK0JEEjFr1izY2NhAX18fNWrUgI2NDfT0/vdvlSpVqqB27doa19y8eROZmZnw8PAots1Hjx4BAO7cuQMAaNCggcZ5S0tLmJubP7dfSUlJAAB7e/syPY8u+0hE9LKYCBFJhLOzs7hqrDhyuVwjMQKKJiFXr14dixYtKvYaS0vLcu3jy3gT+khElRcTIaI3WP369XHixAm0aNFCnDxdnDp16gAAbty4AWtra/F4amqq1sqtZ6njr1y5gjZt2pQYV9IwmS76SET0sjhHiOgN5u/vj4KCAqxYsULrXH5+PjIyMgAAbdq0gYGBATZs2CBOcAYgLn9/nqZNm6JevXpYv3692J7a022pN318NkYXfSQielmsCBG9wVq3bo3evXtj1apVuHTpEjw9PWFgYIAbN25g//79mD59Ojp37gxLS0sMHjwYq1atwvDhw9GuXTtcvHgR8fHxqFat2nPvoaenh9mzZ2PkyJHo3r07evToASsrKyQkJODatWuIjIwEUJQwAcC8efPg5eUFfX19BAYG6qSPREQvi4kQ0Rvuyy+/RLNmzbBlyxYsWbIE+vr6qFu3Lrp27YoWLVqIcePGjYNcLseWLVtw8uRJODs7Y/Xq1Rg+fPgL79G2bVusW7cOy5cvx+rVqyEIAqytrdGrVy8xplOnTujfvz/27t2L3bt3QxAEBAYG6qyPREQvQyY8XYMmIiIiqkQ4R4iIiIgqLSZCREREVGkxESIiIqJKi4kQERERVVpMhIiIiKjSYiJERERElRYTISIiIqq0mAgRERFRpcVEiIiIiCotJkJERERUaTERIiIiokqLiRARERFVWkyEiIiIqNL6P43em3I95yeUAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ─── Confusion matrix for HyperModel ──────────────────────────────────────\n", + "from evaluation import plot_confusion_matrix\n", + "\n", + "fig_cm = plot_confusion_matrix(\n", + " result_hyper['confusion_matrix'],\n", + " class_names=CLASS_NAMES_2,\n", + " title='HyperModel Confusion Matrix (Binary)',\n", + " save_path=str(OUTPUT_DIR / 'results_confusion_matrix_hypermodel.png'),\n", + ")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 11. Feature Importance Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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tmyp9BKE8mrr1q2oV69eoS9uyM3Nxdq1azFy5EgWD6Q2DmEiIiIiKkR5Lx727duHf//9F0ePHsXkyZMLfSOVRCIRJoATqYsFBBEREVEFNG7cOOjp6aFHjx6Frm5P9K44B4KIiIiIiNTGORBERERERKQ2FhBERERERKQ2zoEgEsH58+ehUCiU3rFPREREVF7k5uZCQ0MDzs7OxbblEwgiESgUCuEPvT+FQoGcnBzmUwTMpbiYT/Ewl+JiPsVTWXNZkvsYPoEgEoFEIkFOTg6sra2hp6dX1uGUe5mZmbh27RrzKQLmUlzMp3iYS3Exn+KprLmMi4tTuy2fQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBARERERkdpYQBCJSENDo6xDqBA0NDSgq6vLfIqAuRQX8yke5lJczKd4mMviaSgUCkVZB0FU3sXFxQEAZDJZGUdCREREFUlevgJamh++mCnJvUyVDx0MUWUStOkebiZllXUYREREVAFYm+tgWd96ZR2GChYQRCK6mZSFuAcsIIiIiKji4hwIIiIiIiJSGwuISiw0NBS+vr5lHQYRERERlSMsIIiIiIiISG0sIIiIiIiISG0sIAixsbHo1q0bnJyc0KNHD1y+fFnYt2bNGnz++edwcXGBu7s7AgMDER8fr3T8jRs3MGzYMDRv3hyOjo7w8fHBypUr1Tr3pEmT0K9fP+Hzs2fP8Mknn+Dzzz8Xtr148QL29vbYv38/Hj58CKlUin/++UfYP3PmTEilUhw9elTYFhERgc6dO7/TOYiIiIioaCwgKrknT55g1qxZCAgIwOLFi5GdnY3g4GDk5uYCAB49eoQBAwbg+++/x6xZs5Cfn48+ffogJSVF6GPEiBFIS0vD7NmzsWLFCgQEBEAul6t1/mbNmiEuLg7Z2dkAgDNnzkBbWxvXrl1D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gYGBhIeHk5KSYlXmxIkT9O/fHz8/Px5//HE+/fTTm7bpp59+ok+fPjRs2JDmzZsTERHB5cuXLdtPnTqFyWTis88+Y/LkyTRp0oSgoCBWrVoFwJYtWwgJCaFRo0aMHj2a5ORky76pqalMnTqVkJAQ/P39ad++PZMnT+bKlStWbbixC1N4eDhdunRh3759dO/enYCAAHr16sXhw4dtjPTNZWZmMnfuXB577DEaNGjAk08+yebNm63K2HrsK1euEBYWRmBgIEFBQcydO5eVK1diMpmAa92UBg4cCECvXr0wmUyWbbmSk5OZMGECgYGBPPbYY5ZrQURERERuza6eQIwYMYKKFSvy9ttvU6ZMGf766y8SEhLyXc/7779P/fr1mTlzJqdOnWLOnDlkZGQwb948ADIyMhgyZAhubm7MmjULgIULF5KSkoKPj4+lnsOHD/P888/TvHlzFixYwIULF4iKiuL48eN8+OGHODk5WcrOnz+fTp06sWDBAnbs2MGMGTNITEzkxx9/5JVXXiElJYXp06cze/Zspk2bBkB6ejrZ2dm8/PLLeHp68vfff7NkyRJGjhzJ+++/f9tzPH/+PNOnT2f48OG4u7sTFRXF6NGj2b59O87OzvmOGcC4cePYv38/o0aNombNmuzZs4dXXnkFDw8P2rZtm69jR0RE8MMPP/DKK69QtWpVPvroI3799VdLHfXr12fy5MlMnTqVyMhIHnnkkTztefPNN+nWrRuLFi1ix44dzJkzB5PJRJs2bQp0fiIiIiL2wG4SiMTERE6dOsXrr79O+/btAWjRokWB6nJxcWHRokWWG/ySJUvyxhtvMHr0aGrWrMmmTZs4d+4cX331lSVhqFevHk888YRVArFkyRK8vLxYsmSJ5cb4oYceYujQoezZs8fSToCAgABee+01S7v//e9/s3btWnbt2kX58uUB+P3339m4caMlgfD09GTKlCmWOq5evUq1atV47rnniIuLw9fX95bnmJSUxNq1a6lduzYAbm5uDBw4kIMHD9KkSZN8x+yHH35g165drFixglatWgHQsmVLzp8/T3R0tFUCcadjHz9+nO3btzNz5ky6d+8OQOvWrXnyySctdZQpU4ZatWoBULt2bfz8/PK0qVOnTowZMwaAoKAgdu/ezbZt24pcApGWlobZbF/zQaSlpVn9lIJTLI2leBpHsTSW4mkc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/fvZtm2bVZncMRsRERH06dOHY8eOsWrVqjxdsW7Up08fOnbsSO3atXFycuKzzz7D2dn5vj59EBEREXkQ6QlEMTNp0iSaNWvG9OnTmTx5Mq1bt+bxxx+/b8cfMmQIkZGR7Nu3j7FjxzJu3Dg++ugj/Pz8LOM1vL29Wb58Oenp6YwbN47ly5czefLkPN2e2rRpwyuvvMKuXbsYNWoUx44dY8qUKVZlTCYTkZGR/Prrr4SGhrJlyxYWLFhgNb7jZho1asRnn33GuHHjGDt2LKdOnWLJkiXUrFnT2ICIiIiIFDMOZo3glCKiW7du1K1blxkzZhR2U/ItNjYWgLBdrsSeSb9jeb8qrmwbV/uO5exVamoqR48epW7dunbV//ReUCyNpXgaR7E0luJpHHuNZe69jJ+f3x3L6gmEiIiIiIjYTGMgxGa3G5js4OCAk5PTfWxN0VTL29XQciIiIiJFjRIIsVn9+vVvua1q1ars2rXrrur//PPP72r/omBR34dtLpudY8bJ8d4PbhcRERExkhIIsdnGjRtvuc3WmQuLs8zMTNLS0mye20HJg4iIiDyIlECIzWwZVGPv9E4CERERKe40iFpERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGzmYDabzYXdCJEH3f79+zGbzTg7O+Pg4FDYzXngmc1msrKyFE8DKJbGUjyNo1gaS/E0jr3GMjMzEwcHBxo1anTHsiXuQ3tEir3cDxh7+qC5lxwcHHBxcSnsZhQLiqWxFE/jKJbGUjyNY6+xdHBwsPk+Rk8gRERERETEZhoDISIiIiIiNlMCISIiIiIiNlMCISIiIiIiNlMCISIiIiIiNlMCISIiIiIiNlMCISIiIiIiNlMCISIiIiIiNlMCISIiIiIiNlMCyqYvXwAAEORJREFUISIiIiIiNlMCISIiIiIiNlMCISIiIiIiNlMCIXKdEydO8PzzzxMQEEDLli2ZNWsWmZmZd9zPbDazbNky2rVrR8OGDenduze//PJLnnJnz55lzJgxBAYG0qxZM15//XVSUlLuwZkUDfcynvv27cNkMuX57+WXX75HZ1O4ChrLdevWERoaSosWLTCZTGzduvWm5XRtGhdPXZt3juW5c+eYNWsW3bp1IzAwkDZt2jBhwgROnz6dp6yuTePiqWvTtn/nYWFhdOrUiYCAAJo2bUq/fv34z3/+k6fclStXeO2112jWrBmBgYGMHTuWc+fO3YtTKXJKFHYDRIqKpKQkBg0ahI+PD9HR0Zw9e5YZM2aQnp7O5MmTb7vv8uXLWbhwIWFhYZhMJtatW8eQIUP4/PPPefjhhwHIysrihRdeACAqKor09HRmzpzJhAkTWLp06T0/v/vtXsczV2RkJI888ohluXz58vfkfArT3cTy888/B6Bt27Z89tlnNy2ja9PYeObStXnrWP76669s376dp59+Gn9/fy5dusTixYt55pln+PLLL/H09AR0bRodz1y6Nm//7zwrK4vBgwfj4+NDRkYGGzduZPjw4bz33ns0adLEUu6ll17i+PHjvPXWW5QsWZL58+czbNgwPvnkE0qUKOa32GYRMZvNZvOSJUvMAQEB5kuXLlnWffjhh+a6deuaExISbrlfenq6uVGjRuaoqCjLuoyMDPNjjz1mfvPNNy3rNm/ebDaZTOYTJ05Y1n377bfmOnXqmA8ePGjouRQF9zqeP/zwg7lOnTrmQ4cO3YvmFykFjaXZbDZnZ2ebzWaz+eTJk+Y6deqYv/rqqzxldG0aG09dm3eOZVJSkjkrK8tq3d9//202mUzmFStWWNbp2jQ2nro2bft3fqOrV6+a27Zta37jjTcs6/bv32+uU6eO+dtvv7WsO3HihNlkMpm3bNly1+0v6tSFSeR/ffPNNwQFBVGuXDnLuieffJKcnBz27t17y/32799PSkoKTz75pGWdi4sLHTt25JtvvrGq32QyWX3r07JlS8qVK8eePXuMPZki4F7H054UNJYAjo53/pjXtWlsPO1JQWPp4eGR5xvaypUr4+npadUFRNemsfG0J3fz7/xGTk5OuLu7k5WVZVW/h4cHLVu2tKx75JFHqFu3rl38v0qfhCL/648//rD6nxRc+1D28vLijz/+uO1+QJ59a9asyZkzZ0hPT79l/Q4ODvj6+t62/gfVvY5nruHDh1O3bl3atGnDzJkz82wvDgoay7upX9fm3dO1mb9YxsXFcfHiRWrWrHnb+nVt2uZm8cyla/POsTSbzVy9epVLly6xYsUK/vzzT3r37m1Vv6+vLw4ODlb7PfLII8Xy2rxRMe+gJWK75ORkPDw88qwvW7YsSUlJt93PxcWFkiVLWq338PDAbDaTlJSEq6srycnJuLu757v+B9W9jqe7uzsvvPACTZs2pWTJkvzwww+sXLmSP/74o9j1jS5oLPNTv65N485X12b+Y2k2m5k+fTre3t507tzZqn5dm8bFU9em7bHcuHEjb7zxBgClSpVi3rx5BAYGWtV/q2vz8OHDd9HyB4MSCBF5INWrV4969epZloOCgvD29mbq1KkcOnSIhg0bFmLrxJ7p2sy/6OhofvjhB959911KlSpV2M154N0qnro2bdehQwceffRRLl26xNatW3nppZeIiYmhbdu2hd20IkFdmET+l4eHB1euXMmzPikpibJly952v8zMTDIyMqzWJycn4+DgYNnXw8Pjpq8evFP9D6p7Hc+byR03Udy+/SloLPNTv67Ne3u+ujZv7aOPPmLRokVMmTKFoKCgPPXr2jQunjeja/PmPD098fPzo02bNvzrX/+iTZs2zJ4926p+e7o2b6QEQuR/3azf4pUrVzh//nyefpQ37gfX+pte748//qBKlSq4urresn6z2UxcXNxt639Q3et42pOCxvJu6te1Kba421hu376dt956i7Fjx9KrVy+b6te1eWt3iqc9Mfrfef369fnzzz+t6o+Li8NsNluVK67X5o2UQIj8rzZt2vDdd9+RnJxsWbd161YcHR2t3rJwo0aNGlGmTBm++uory7qsrCz+/e9/06ZNG6v6f/vtN+Lj4y3rvv/+ey5fvlwsH4ne63jezJYtWwDw8/O7y9YXLQWNZX7q17VpXDxvRtdmXvv27WP8+PE888wzjBo16pb169o0Lp43o2vTNv/973+t5iFq06YNSUlJfP/995Z1cXFxHDly5I7/ryoOHMw3pk4idiopKYnOnTvj6+tLaGioZdKZrl27Wk06M2jQIM6cOcP27dst65YtW0Z0dDRhYWHUqVOH9evX85///CfPRHI9e/YEYPz48aSlpTFr1ixMJlOxG7wG9z6eYWFh1KhRg3r16lkGA65evZq2bduyaNGi+36+99LdxDI2NpbTp0+TmJjIlClTGDJkCP7+/nh6etKsWTNA16bR8dS1eedYnjhxgt69e/PQQw8xZcoUq9fjenp6Ur16dUDXptHx1LV551ju3r2bzz77jHbt2vHQQw+RlJTEl19+ybZt25g7d67VoPShQ4dy4sQJJk6cSMmSJZk3bx6Ojo52MZGcEgiR65w4cYJp06Zx4MABSpcuTbdu3Xj55ZdxcXGxlBkwYACnT59m165dlnVms5lly5bxwQcfkJiYSN26dYmIiLB6YwPA2bNnmT59Ov/5z38oUaIEHTt25LXXXqNMmTL37Rzvp3sZz6VLl7J582ZOnz5NVlYWVatWpWvXrgwfPtyq/uKioLEMDw/n008/zVNfs2bNeP/99y3LujaNi6euzTvHctOmTURERNy0vh49ejBjxgzLsq5N4+Kpa/POsTxx4gRRUVHExsZy6dIlypcvj8lkYvjw4ZYvCXJduXKFyMhItm/fztWrV2nVqhVvvPEGlSpVuq/nWRiUQIiIiIiIiM00BkJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJERERERGymBEJEROzOpk2bMJlMxMbGFnZTCmTdunVs2rSpsJshInZKCYSIiMgDZv369Xz66aeF3QwRsVNKIERERB4QaWlphd0EERElECIiIuHh4QQGBnLmzBlCQ0MJDAykdevWrFu3DoDff/+dgQMHEhAQwGOPPcbmzZut9s/tEvXTTz8xefJkmjdvTqNGjXj11VdJSkrKc7x169bRuXNnGjRoQKtWrZgyZQrJyclWZQYMGECXLl04fPgw/fr1w9/fn7lz59K+fXuOHTvGjz/+iMlkwmQyMWDAAAAuX77MzJkz6dq1K4GBgTRq1IgXXniB3377zaruffv2YTKZ+J//+R8WL15MmzZt8PPzY9CgQfz555952nvw4EGGDRtG06ZNCQgIoGvXrqxZs8aqzIkTJxg7dizNmjXDz8+Pnj17snPnzvz/MUSkyCtR2A0QEREpCrKzsxk2bBhNmjQhLCyMzZs3M3XqVNzc3Jg3bx5du3alU6dOfPjhh0ycOJGAgAAefvhhqzqmTp2Kh4cHo0ePJi4ujvXr13PmzBnef/99HBwcAIiOjiYm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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " feature importance\n", + " has_www 0.3209\n", + "phishing_keyword_count 0.0832\n", + " path_depth 0.0798\n", + " path_length 0.0667\n", + " num_slashes 0.0524\n", + " has_https 0.0462\n", + " num_params 0.0187\n", + " num_percent 0.0186\n", + " has_suspicious_ext 0.0177\n", + "max_consecutive_digits 0.0165\n", + " num_dots 0.0160\n", + " url_length 0.0154\n", + " num_hyphens 0.0143\n", + " num_subdomains 0.0131\n", + " num_special 0.0127\n" + ] + } + ], + "source": [ + "from evaluation import plot_feature_importance\n", + "\n", + "xgb_model = clf_models_bin['XGBoost (GPU)']\n", + "importances = xgb_model.feature_importances_\n", + "\n", + "fig_fi = plot_feature_importance(\n", + " feat_names, importances, top_n=25,\n", + " title='XGBoost Feature Importance (Binary)',\n", + " save_path=str(OUTPUT_DIR / 'feature_importance_xgb.png'),\n", + ")\n", + "plt.show()\n", + "\n", + "feat_imp_df = pd.DataFrame({'feature': feat_names, 'importance': importances})\n", + "print(feat_imp_df.sort_values('importance', ascending=False).head(15).to_string(index=False))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 12. Case Study β€” Adversarial URL Analysis\n", + "\n", + "Testing the HyperModel on hand-crafted adversarial examples: typosquatting,\n", + "brand impersonation, IP-based phishing, and obfuscated URLs." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:tornado.general:Uncaught exception in ZMQStream callback\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 1-2: surrogates not allowed\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 143, in orjson_packer\n", + " return orjson.dumps(obj, default=json_default, option=option)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "TypeError: str is not valid UTF-8: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 103, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 550, in _run_callback\n", + " f = callback(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 169, in _handle_event\n", + " event_f()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 620, in _flush\n", + " self.session.send(\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 856, in send\n", + " to_send = self.serialize(msg, ident)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 727, in serialize\n", + " content = self.pack(content)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 145, in orjson_packer\n", + " return json_packer(obj)\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 111, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "ERROR:tornado.general:Uncaught exception in zmqstream callback\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 1-2: surrogates not allowed\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 143, in orjson_packer\n", + " return orjson.dumps(obj, default=json_default, option=option)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "TypeError: str is not valid UTF-8: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 103, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 600, in _handle_events\n", + " self._handle_recv()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 629, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/pythException in callback BaseAsyncIOLoop._handle_events(28, 1)\n", + "handle: \n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 1-2: surrogates not allowed\n", + "\n", + "The above exception was the direct cause of the following exception:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 143, in orjson_packer\n", + " return orjson.dumps(obj, default=json_default, option=option)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "TypeError: str is not valid UTF-8: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 103, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "\n", + "During handling of the above exception, another exception occurred:\n", + "\n", + "Traceback (most recent call last):\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/asyncio/events.py\", line 88, in _run\n", + " self._context.run(self._callback, *self._args)\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/tornado/platform/asyncio.py\", line 208, in _handle_events\n", + " handler_func(fileobj, events)\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 600, in _handle_events\n", + " self._handle_recv()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 629, in _handle_recv\n", + " self._run_callback(callback, msg)\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/zmq/eventloop/zmqstream.py\", line 550, in _run_callback\n", + " f = callback(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 169, in _handle_event\n", + " event_f()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 620, in _flush\n", + " self.session.send(\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 856, in send\n", + " to_send = self.serialize(msg, ident)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 727, in serialize\n", + " content = self.pack(content)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 145, in orjson_packer\n", + " return json_packer(obj)\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 111, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n", + "on3.12/site-packages/zmq/eventloop/zmqstream.py\", line 550, in _run_callback\n", + " f = callback(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 169, in _handle_event\n", + " event_f()\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/ipykernel/iostream.py\", line 620, in _flush\n", + " self.session.send(\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 856, in send\n", + " to_send = self.serialize(msg, ident)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 727, in serialize\n", + " content = self.pack(content)\n", + " ^^^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 145, in orjson_packer\n", + " return json_packer(obj)\n", + " ^^^^^^^^^^^^^^^^\n", + " File \"/home/zeus/miniconda3/envs/cloudspace/lib/python3.12/site-packages/jupyter_client/session.py\", line 111, in json_packer\n", + " ).encode(\"utf8\", errors=\"surrogateescape\")\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + "UnicodeEncodeError: 'utf-8' codec can't encode characters in position 30-31: surrogates not allowed\n" + ] + } + ], + "source": [ + "CASE_STUDY_URLS = [\n", + " # Clearly benign\n", + " ('https://www.google.com', 0, 'Legitimate Google'),\n", + " ('https://www.amazon.com/dp/B08L5TNJHG', 0, 'Legitimate Amazon'),\n", + " ('https://github.com/openai/gpt-4', 0, 'Legitimate GitHub'),\n", + " ('https://en.wikipedia.org/wiki/Machine_learning', 0, 'Legitimate Wikipedia'),\n", + " # Typosquatting\n", + " ('http://googlΠ΅.com.login-verify.xyz/account', 1, 'Typosquatting Google'),\n", + " ('http://amaz0n-security-alert.com/verify', 1, 'Typosquatting Amazon'),\n", + " ('http://paypa1.com-secure.update-account.ru/login', 1, 'Typosquatting PayPal'),\n", + " # Brand in subdomain\n", + " ('http://apple-id.apple.com-signin.net/verify', 1, 'Brand subdomain phishing'),\n", + " ('http://microsoft.com.update-account.xyz/login.php', 1, 'Brand path phishing'),\n", + " # IP-based\n", + " ('http://192.168.1.234/paypal/login', 1, 'IP-based phishing'),\n", + " ('http://45.77.123.45/amazon-account/verify.html', 1, 'IP-based phishing 2'),\n", + " # Obfuscated\n", + " ('http://xn--pypal-4ve.com/account-login', 1, 'Punycode phishing'),\n", + " ('http://bit.ly/3xK7pQr', 1, 'URL shortener (suspicious)'),\n", + " ('http://secure-update%2Ebank%2Ecom.evil.tk/login', 1, 'Hex-encoded phishing'),\n", + " # Long suspicious\n", + " ('http://login-account-update-security-bank-verify.info/account/login/confirm/id=12345&token=abc',\n", + " 1, 'Long suspicious URL'),\n", + " # Legit with suspicious paths\n", + " ('https://security.microsoft.com/informationprotection/label', 0, 'Legit MS Security'),\n", + " ('https://accounts.google.com/o/oauth2/auth?client_id=abc123', 0, 'Legit Google OAuth'),\n", + "]\n", + "\n", + "case_urls = [u for u, _, _ in CASE_STUDY_URLS]\n", + "case_labels = [l for _, l, _ in CASE_STUDY_URLS]\n", + "case_descs = [d for _, _, d in CASE_STUDY_URLS]\n", + "\n", + "extractor = URLFeatureExtractor()\n", + "case_feat = extractor.transform(pd.Series(case_urls), verbose=False)\n", + "case_feat = case_feat[feat_names]\n", + "X_case = scaler.transform(case_feat.values.astype(np.float32)).astype(np.float32)\n", + "u_case = np.array(case_urls)\n", + "\n", + "pred_xgb = clf_models_bin['XGBoost (GPU)'].predict_proba(X_case)[:, 1]\n", + "pred_lgb = clf_models_bin['LightGBM (CPU)'].predict_proba(X_case)[:, 1]\n", + "pred_tfidf = tfidf_bin.predict_proba(u_case)[:, 1]\n", + "pred_hyper = hypermodel.predict_proba(X_case, u_case)[:, 1]\n", + "\n", + "case_results = pd.DataFrame({\n", + " 'Description': case_descs,\n", + " 'True Label': ['Malicious' if l else 'Benign' for l in case_labels],\n", + " 'XGB Score': pred_xgb.round(3),\n", + " 'LGB Score': pred_lgb.round(3),\n", + " 'TF-IDF Score':pred_tfidf.round(3),\n", + " 'HyperModel': pred_hyper.round(3),\n", + " 'Prediction': ['Malicious' if p > 0.5 else 'Benign' for p in pred_hyper],\n", + " 'Correct': ['\\u2705' if (p>0.5)==bool(l) else '\\u274c'\n", + " for p, l in zip(pred_hyper, case_labels)],\n", + "})\n", + "\n", + "print('\\n\\ud83d\\udccb Case Study Results:')\n", + "print(case_results.to_string(index=False))\n", + "accuracy_case = (case_results['Correct'] == '\\u2705').sum() / len(case_results)\n", + "print(f'\\nCase study accuracy: {accuracy_case:.1%}')" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABWgAAAKsCAYAAABxrVRoAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3gUVdvH8d9uegIJhN4VMKE3KdIhNEEQRKRIVZAqKjYQfFAeFVBAkSJWqlQLSmiCooCAgIqCgEivDxA6hPSd94+8WVmS3exuNiyE7+e6cunO3HPm3pMzw86d2TMmwzAMAQAAAAAAAABuObO3EwAAAAAAAACAuxUFWgAAAAAAAADwEgq0AAAAAAAAAOAlFGgBAAAAAAAAwEso0AIAAAAAAACAl1CgBQAAAAAAAAAvoUALAAAAAAAAAF5CgRYAAAAAAAAAvIQCLQAAAAAAAAB4CQVaAACADJw4cUKRkZH6+uuvvZ0K7Jg6daoiIyPd2nbEiBGKiorycEa4lb7++mtFRkbqxIkT3k4lW0VGRmrq1Kkub7d161ZFRkZq69at2ZAVAADwJAq0AADcBY4dO6bRo0erWbNmqly5smrUqKGuXbtqzpw5io+P93Z6Gfr111/Vr18/NWzYUJUrV1aTJk00cOBARUdHW2Pi4uI0derUO7YAERUVpQEDBmS4Lq24snr16lucleuioqIUGRmpPn36ZLh+yZIlioyMVGRkpHbt2nVrk8sii8Wib775Ro899phq166t6tWrq1WrVnr55Zf1xx9/eDu9HGH+/PmKjIzUY4895u1U7kppf+i4cOFChuvbtm2rnj17Wl+n/fEq7adcuXKqXbu2+vXrpx07drjcPgAAkHy9nQAAAMheP/30k5599ln5+/urffv2ioiIUFJSkn777TdNmDBBBw4c0BtvvOHtNG2sWrVKw4YNU/ny5dWrVy+FhYXpxIkT2r59u5YsWaJ27dpJSi3QTps2TU8//bTq1Knj5azvbgEBAdq6datiYmJUoEABm3XR0dEKCAhQQkKCl7Jz35tvvqn58+erWbNmateunXx8fHT48GFt3LhRJUqUULVq1byd4h0vOjpaxYoV086dO3X06FGVKlXK2yndVnbu3CkfHx9vp5FO27Zt1ahRI1ksFh05ckQLFixQr1699OWXX7p9ZzsAAHcrCrQAAORgx48f17Bhw1S0aFHNmTNHBQsWtK7r3r27jh49qp9++sl7Cdoxbdo0lS1bVosXL5a/v7/NuvPnz3spK9zIMAwlJCQoMDBQklSjRg3t2rVLK1euVO/eva1xp0+f1q+//qoWLVrou+++81a6bjl37pwWLFigzp07p/sjhmEYt/SOwOTkZFkslnTHw53u+PHj2rFjh6ZNm6bRo0crOjpaTz/9tLfTciguLk5BQUHZug+LxaKkpCQFBAQoICAgW/flrgoVKqh9+/bW1/fff7+eeuopLVy4UK+//rr3EgMA4A7EFAcAAORgn376qa5fv6633nrLpjibplSpUjbFtK+++kq9evVS3bp1ValSJbVp00YLFixIt92uXbvUt29f1alTR1WqVFFUVJReeeUVmxiLxaLZs2froYceUuXKlVWvXj2NHj1aly9fzjTvY8eOqXLlyhkWo/Llyycp9Wu2devWlZRa0E37um3aXI09e/a0+VpumozmHr1y5YpGjBih+++/XzVr1tTw4cN19epVm5ivvvpKkZGR2rNnT7o2P/zwQ5UvX15nzpzRhQsXdPDgQcXFxWX6Pl3xyy+/KDIyUmvXrk23Ljo6WpGRkdavF48YMULVq1fX8ePH1bdvX1WrVk0NGjTQtGnTZBiGzbbO/p7SpmPYuHGjOnbsqCpVqmjRokXW9QEBAWrZsqWWL19us93y5csVGhqqBg0aZPi+tmzZoscff1zVqlVTzZo1NWjQIB08eDBd3K+//qpHH31UlStXVvPmzW32fbNvv/3WmmPt2rU1bNgw/e9//7Mbb8+JEydkGIZq1KiRbp3JZLKOxTRXrlzR2LFjFRUVpUqVKqlRo0Z6+eWXbQq558+f18iRI1WvXj1VrlxZDz/8sJYuXZpuv5GRkfrss880e/ZsNW/eXJUrV7b2y8GDB/XMM8+odu3aqly5sjp27KgffvjBpo2kpCRNmzZNLVu2VOXKlVWnTh1169ZNmzZtyvR9Hz9+3Np+1apV1blz53R/yEmbgmPlypWaMWOGGjVqpMqVK6t37946evRopvtIEx0drbCwMDVu3FitWrWymcLkRvv371evXr1UpUoVNWrUSB988IEsFotNzIABA9SsWbMMt+/SpYs6duxos8yZcdKzZ0+1bdtWf/31l7p3766qVavq3XffleTcefCzzz5T165drTEdO3bMcNqSyMhI/fe//9WyZcusx+LGjRut626cg/bkyZN6/fXX1apVK1WpUkV16tTRM8884/W5eGvWrCkpdfy4KivjFQCAnIA7aAEAyMF+/PFHlShRIsMCU0YWLlyo++67T1FRUfL19dWPP/6oMWPGyDAMde/eXVJqgalv377Kmzev+vfvr9DQUJ04cSJd4XD06NFaunSpOnbsqJ49e+rEiROaP3++9uzZo4ULF8rPz89uHkWLFtWWLVt0+vRpFS5cOMOY8PBwvf7663r99dfVokULtWjRQpJc/mqtYRgaPHiwfvvtN3Xt2lVlypTR2rVrNXz4cJu4Vq1a6b///a+io6NVoUIFm3XR0dGqXbu2ChUqpKlTp2ratGmaO3euU9MuJCcnZ3gn5s0F4jp16qhIkSKKjo62vtcb91+yZElVr17duiwlJUX9+vVT1apV9dJLL2njxo2aOnWqUlJS9Oyzz1rjXPk9HT58WC+88IK6dOmizp07695777XJo23btnryySd17NgxlSxZUlJqgbZVq1by9U3/sXPz5s166qmnVLx4cT399NOKj4/X559/rm7duunrr79W8eLFJUn79u1T3759FR4erqFDhyo5OVlTp05NVyCVpBkzZuj9999X69at1alTJ124cEGff/65unfvrm+++UahoaF2fxc3K1q0qCRp9erVevDBBx3eNRkbG6vu3bvr4MGDevTRR1WhQgVdvHhR69at05kzZxQeHq74+Hj17NlTx44dU/fu3VW8eHGtXr1aI0aM0JUrV2z+WCKlPgQrISFBnTt3lr+/v8LCwrR//35169ZNhQoV0lNPPaXg4GCtWrVKQ4YM0dSpU61jY9q0afroo4/02GOPqUqVKrp27Zr++usv7d69W/Xr17f7Ps6dO6euXbsqLi5OPXv2VN68ebV06VINGjRIU6ZMSTf2PvnkE5lMJj355JO6du2aPv30U7344ov64osvnOrjtPHs7++vtm3bauHChdq5c6eqVKlijYmJiVGvXr2UkpKi/v37KygoSEuWLEl3Z2nr1q01fPjwdNufPHlSf/zxh15++WXrMlfGyaVLl/TUU0/poYce0sMPP6x8+fI5fR6cO3euoqKi1K5dOyUlJWnFihV69tln9dFHH6lJkyY2sb/88otWrVql7t27K2/evCpWrFiGfbZr1y7t2LFDDz30kAoXLqyTJ09q4cKF6tWrl1asWJHtd/fac/LkSUly6RhL4+54BQAgxzAAAECOdPXqVSMiIsIYNGiQ09vExcWlW/bkk08azZo1s75eu3atERERYezcudNuO9u3bzciIiKMZcuW2SzfsGFDhstv9sUXXxgRERFGxYoVjZ49exqTJ082tm/fbqSkpNjEnT9/3oiIiDCmTJmSro0ePXoYPXr0SLd8+PDhRtOmTdO9n08++cS6LDk52Xj88ceNiIgI46uvvrIuf/75540GDRrY5LF7926buClTphgRERHGL7/84vA9GoZhNG3a1IiIiHD4s2rVKmv8pEmTjEqVKhlXrlyx6YMKFSrY9MHw4cONiIgI44033rAus1gsRv/+/Y2KFSsa58+fNwzDtd9TWq4bNmzI8H3079/fSE5ONurXr29Mnz7dMAzDOHDggBEREWFs27bN+Oqrr9KNm/bt2xt169Y1Ll68aF22d+9eo1y5csbLL79sXTZ48GCjcuXKxsmTJ63LDhw4YJQvX96IiIiwLjtx4oRRvnx5Y8aMGTb57du3z6hQoYLN8pvHgT0vv/yyERERYdSqVcsYMmSI8dlnnxkHDhxIF/f+++8bERERxpo1a9Kts1gshmEYxuzZs42IiAjj22+/ta5LTEw0unTpYlSrVs24evWqYRiGcfz4cSMiIsKoUaOG9XeVpnfv3kbbtm2NhIQEm/a7dOlitGzZ0rrs4YcfNvr375/p+7vZW2+9ZURERBjbt2+3Lrt27ZoRFRVlNG3a1Dr2f/nlFyMiIsJo3bq1TS5z5swxIiIijH379mW6r127dhkRERHGpk2brO+jUaNGxptvvplhTn/++ad12fnz543777/fiIiIMI4fP24YRuo5r1KlSsb48eNttv/kk0+MyMhI6/hxZZz06NHDiIiIMBYuXGgT68x50DDSn1MTExONtm3bGr169bJZHhERYZQrV87Yv39/ujZuPsdldJ7esWOHERERYSxdutS6LO13lNm5KO2cdfNYS/PQQw/ZnEvTxufUqVON8+fPGzExMcb27duNRx99NN05y5n2DcP98QoAQE7BFAcAAORQ165dkySFhIQ4vU3afKJS6h2cFy5cUO3atXX8+HHrHZ25c+eWlPrwsaSkpAzbWb16tXLnzq369evrwoUL1p+KFSsqODhYW7dudZhHp06d9Omnn6pOnTr6/fff9cEHH6h79+5q2bKlfv/9d6ffjzM2bNggX19fdevWzbrMx8dHPXr0SBfbvn17nT171ib/6OhoBQYGqmXLlpKkoUOHat++fU4/tKxq1aqaNWtWup+b7+BN239iYqLNV6RXrlyp5ORkPfzww+ni0+56llK/kt+9e3clJSVpy5Ytklz/PRUvXlwNGza0+158fHz04IMPasWKFZKkZcuWqUiRItavPt/o7Nmz2rt3rx555BHlyZPHurxcuXKqV6+e1q9fLyn1TuCff/5ZzZs3t97RKkllypRJN23C2rVrZbFY1Lp1a5v3kz9/fpUqVSrTcZeRcePGafTo0SpevLjWrl2rt99+W23atFHv3r115swZa9yaNWtUrly5dHeYSql9L6WOtQIFCqht27bWdX5+furZs6euX7+u7du322zXsmVLhYeHW19funRJv/zyi1q3bq1r165Z39/FixfVoEEDHTlyxJpTaGio9u/fryNHjrj0ftevX68qVarY/M5CQkLUpUsXnTx5UgcOHLCJ79ixo81UJK58zT06Olr58+e3Hismk0lt2rTRypUrlZKSYpNTtWrVbO6KDQ8Ptz4sME2uXLnUqFEjrVq1ymYqj5UrV6patWrW8ePqOPH39083PYIz50HJ9px6+fJlXb16Vffff3+GU6XUqlVLZcuWtdtWRm0mJSXp4sWLKlmypEJDQzNsN7tMnTpVdevWVf369a13j48YMUIPPvigy225O14BAMgpmOIAAIAcKleuXJJSv3rtrN9++01Tp07VH3/8kW4O1atXryp37tyqXbu2WrVqpWnTpmn27NmqXbu2mjdvrnbt2lkLNUePHtXVq1etc8TezJkHfTVs2FANGzZUXFycdu/erZUrV2rRokUaOHCgVq1aleHX291x8uRJFShQIF0h++av70tS/fr1VaBAAS1btkx169aVxWLR8uXL1axZM2t/uypv3ryqV69euuUZPbW9TJkyqly5sqKjo/XYY49JSi1yVatWTaVKlbKJNZvNKlGiRIbvKe2ryK7+ntKmHHCkXbt2mjdvnv7++28tX75cbdq0sRYob3Tq1CmbnG5+nz///LOuX7+u2NhYxcfHp3t/adumFXIl6ciRIzIMw1osv1lG0yxkxmw2q3v37urevbsuXryo33//XYsWLdKGDRs0bNgw6xzNx44ds7vfNCdPnlSpUqVkNtveI1GmTBlJ//ZJmpv7+9ixYzIMQ++/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c+eUO3duValSRRMnTrR5KNV///tfVapUSYsWLdJ7770nHx8fFStWTA8//LBq1KjhMOc333xTP/zwg1atWqWzZ8/KMAyVKFFCAwcO1FNPPWVzx+qbb76pN954Q+PGjVNSUpKefvppRUREqEyZMnr77bc1ZcoUjRs3TmXLltU777yj5cuXa9u2bdbtzWazZsyYobFjx2rZsmUymUyKiorSiBEj1KFDhwzza9eunfX93vhk+VuladOmCgsLk8ViUbNmzTKM8fHx0aeffqrXX39dEyZMUEhIiJ5++mkNGTLEJi4rv6esqlevnj799FNNmTJFU6ZMka+vr2rVqqWXXnrJZiyVK1dOn332mcaNG6cpU6aocOHCGjp0qGJiYtIVuvr376977rlHs2fP1vTp0yVJhQsXVv369Z0uMqW59957NXLkSK1fv14LFizQ+fPn5e/vr4iICL355pvq1KmTNTYkJETz58/X1KlTtXbtWi1dulT58uVT3bp1rV+vDwwM1Lx58zRx4kQtXbpU165d07333qtx48ZZ/1CSmbJly+qrr77StGnTtHTpUl26dEnh4eGqUKGCze+2Z8+eWrdunTZt2qTExEQVLVpUzz33XKaFx/z582vRokWaMGGCPv/8cyUkJCgyMlIffvihmjRp4lL/2bNs2TIFBATY/dq82WxWkyZNFB0drYsXL6pgwYKaO3eu3nzzTX388cfKkyePunbtqoIFC2rUqFHptg8ICFBUVJSio6NVr169DB8omNVx4sx5sG7dunrrrbf0ySefaOzYsSpevLhefPFFnTx5MksF2lGjRslsNis6OloJCQmqUaOGtRDsrkGDBqlYsWKaP3++PvjgAyUnJ6t48eIaOnSo+vfv73RhvlChQmrXrp2+/fZbHTt2zHqHuSR99NFH6eJ9fHw0cOBAt8crAAA5hclwZyZ5AACAu9iFCxfUsGFDDR48OF3B81ZITk5Ww4YN1bRpU40dOzbd+hEjRui7776z+Zo6AAAAgNsTc9ACAAC4aOnSpUpJSVH79u29sv/vv/9eFy5csHuHLwAAAIA7B1McAAAAOGnLli06ePCgPvzwQzVv3lzFixe/pfv/888/tW/fPn3wwQeqUKGCateufUv3DwAAAMDzKNACAAA46YMPPtCOHTtUvXp1/ec//7nl+1+4cKGWLVumcuXKafz48bd8/wAAAAA8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tvlqfhp3i75pmjRpouTkZH399dd65513Moz5448/dPr0aX300UcqV66cdfnVq1dVuHBhp/eVJ08eJScn6/z5804XacPCwjKc5/b8+fMKCwuzvvb398+wH2/k7++voUOHaujQoTp69Ki++uorTZ06VcWLF1eHDh2cfh8AAAAAAAC4vTDFAdySVtw8ePCgddmFCxe0e/dum7g6derowIEDqlChgipXrmzzU7p06SzlEBAQoIEDB6pZs2Zq1qxZhjHx8fGSbO/W/f3333Xy5EmX9vXAAw/IZDLpq6++cnqb+++/X//8848OHTpkXXb58mVt3rxZNWrUsC4rXLiwTT9K0ubNm+22W6pUKT3//PPKkyePTdsAAAAAAAC483AHLdxSuHBhVa1aVdOnT1fu3Lnl6+urTz75RLlz57aJGzBggHr16qW+ffuqc+fOyp8/v86dO6dt27apZs2aatu2rSRp5MiR+uabb1yah1aS+vfv73B9tWrVFBwcrDFjxqh///46c+aMpk6dqkKFCrm0n3vvvVddu3bV+++/r8uXL6tu3bqKj4/XTz/9pKFDh2bYXseOHTV79mwNGDBAzz33nAICAjRjxgz5+vqqV69e1rhWrVppzpw5qly5su69914tW7ZMZ86csWlr8ODBqlixoipUqKCgoCD9+OOPunz5sh544AGX3gcAAAAAAABuLxRos4kpX4EcvT9Jmjhxol599VW98soryp8/v5577jmtWLFCV69etcaULFlSixYt0tSpUzVmzBhdv35dBQoUUK1atRQZGWmNs1gsSklJ8XiO+fPn1/vvv6933nlHgwcP1j333KMxY8bo008/dbmt0aNHq3jx4vriiy80Z84c5cmTR7Vq1bI7VUOuXLk0b948jR8/Xv/5z39ksVhUo0YNff755ypSpIj17t7Bgwfr/Pnzmj59ukwmk7p06aJevXpp/Pjx1rZq1KihVatWadasWUpJSdG9996riRMnql69eu51DAAAAAAAAG4LJsMwDG8ncTvatWuXJKly5coZro+Pj9fhw4d17733KjAw0GadEXddhgsPoPIUU0CATEHBt3y/9qSkpCg+Pl6BgYHy8fHxdjq3lezuG0fj83Z3/fp17d27V+XLl1dw8O0znm8X9I999I199I1j9I999I1j9I999I199I1j9I999I199I1j9I999I199E3WZVZbvBF30GYDU1DwbVUoBQAAAAAAAHB74iFhAAAAAAAAAOAlFGgBAAAAAAAAwEso0AIAAAAAAACAl1CgBQAAAAAAAAAvoUALAAAAAAAAAF5CgRYAAAAAAAAAvIQCLQAAAAAAAAB4CQVaAAAAAAAAAPASCrQAAAAAAAAA4CW+3k4A3hUZGZlpzLhx49SxY8dbkE3moqKidPLkSevrPHnyKDIyUs8884xq1qyZLfv8+uuv9corr2jLli0KDw/Pln0AAAAAAADg7kSBNhvEJccpMSXxlu/X38dfQb5BLm2zePFim9ddunRRz5491bZtW+uykiVLeiQ/T2nVqpWefPJJSdL58+c1Z84c9evXT8uWLcuWXJs0aaLFixcrNDTU420DAAAAAADg7kaBNhskpiRq0b4vdCH+/C3bZ3hgPnWNfMzlAm21atXSLStSpEiGy9PEx8crMDDQxQw9J3/+/Db51axZU3Xq1NHGjRvVvXt3j+8vPDycO2cBAAAAAACQLZiDNptciD+vs9djbtlPdhWDp06dqurVq2vnzp3q0qWLKleurPnz52vr1q2KjIzUrl27bOIHDx6snj172iw7ePCgBg0apPvvv1/VqlVT//79dezYMY/lGBQUJB8fHyUnJ7u838jISH3yySeaOnWq6tWrpzp16uiVV17R9evXrTFff/21IiMjdeHCBeuy06dPa8CAAapataoaN26s2bNn66233lJUVFS67fbs2aN+/fqpWrVqatmypb755huPvXcAAAAAAADc2W6rAu3Ro0c1evRotW/fXhUqVLD5mr0jhmHo448/VpMmTVSlShV16dJFf/zxR/YmexdJSkrSCy+8oIcffliffPKJ6tev7/S2J06cUPfu3XX58mWNHz9eEydO1IULF9SnTx8lJv47DcSIESOcmg9XSv19JycnKzk5WWfPntW4cePk4+OjJk2aWGOOHz+url27ZrpfSZo/f76OHDmi8ePHa8iQIYqOjtYHH3zgcP+DBw/W3r17NWbMGI0ePVpr1qzR2rVrM4x/8cUX1aBBA02fPl3ly5fXiBEjdPDgQafeKwAAAAAAAHK222qKg/3792v9+vWqWrWqLBaLDMNwartPPvlEU6ZM0YsvvqjIyEjNnz9fTz75pL799luVKFEim7PO+ZKSkjRs2DC1adPGumzr1q1Obfvxxx8rLCxMs2bNUkBAgCSp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292uWLFiSklJ0b59+1SuXDnr8t27dytfvny3/IQBAAAAAAAAAM5wqwRetmxZRUdHq2fPnrp06ZJWrlyplStX6tKlS+rVq5eio6N13333udxu165dFRISoiFDhujnn3/WV199pXfeeUddu3ZVoUKFrHG9e/dWixYtrK8bNWqkokWL6plnntG3336rLVu2aMKECVq6dKl69OjhzlsEAAAAAAAAgGzn1h20kpQ/f36NHDlSI0eO9FgyYWFhmjNnjt544w0NGTJEISEh6tSpk4YNG2YTZ7FYlJKSYn2dK1cuzZ49W++9954mTpyoq1evqnjx4hoxYgQFWgAAAAAAAAC3LbcLtGliY2N1+vRpSVLhwoUVEhKSpfbKlCmj2bNnO4yZN29eumWlSpXS5MmTs7RvAAAAAAAAALiV3C7Q7ty5UxMmTNDvv/8ui8UiKXXi4Pvvv18vvfSSKleu7LEkAQAAAAAAACAncqtA++eff6pnz57y8/NTp06dVKZMGUnSwYMHtWLFCvXo0UPz5s1TlSpVPJosAAAAAAAAAOQkbhVo33vvPRUqVEgLFixQgQIFbNYNHTpU3bp103vvvadZs2Z5JEkAAAAAAAAAyInM7mz0559/qkuXLumKs1Lqw8M6d+6sP/74I6u5AQAAAAAAAECO5laB1mw2KyUlxe56i8Uis9mtpgEAAAAAAADgruFWFbV69eqaP3++Tp48mW7dqVOntGDBAtWoUSPLyQEAAAAAAABATubWHLTPP/+8unfvrtatW6tFixa65557JEmHDx/WDz/8IB8fH73wwguezBMAAAAAAAAAchy3CrQVKlTQF198offee0/r1q1TXFycJCkoKEgNGzbUc889p7Jly3o0UQAAAAAAAADIadwq0EpS2bJlNX36dFksFl24cEGSFB4eztyzAAAAAAAAAOAktwu0acxms/Lnz++JXAAAAAAAAADgruJ0gXbNmjUuN96yZUuXtwEAAAAAAACAu4XTBdpnnnlGJpNJkmQYRqbxJpNJe/fudT8zAAAAAAAAAMjhXJriICAgQI0bN1br1q0VHh6eXTkBAAAAAAAAwF3B6QLtzJkzFR0drbVr1+qHH35Q3bp11a5dOzVv3lzBwcHZmSMAAAAAAAAA5EhmZwPr1auncePGafPmzZowYYICAgI0atQo1a9fX8OGDdO6deuUnJycnbkCAAAA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yWTS2LFjXd4OAAAAAAAAAO4WThVot27d6nLDjh4iBgAAAAAAAABwskC7bt267M4DAAAAAAAAAO46zEELAAAAAAAAAF5CgRYAAAAAAAAAvMSpKQ4ysn79es2ePVt79uzR1atXZRhGupi9e/dmKTkA+D/27jusimv7G/j30GyIBVtiiYkxajTGii1qjCUWjF3sXbChiDXYBQuCWLCLvfeYqDGKBcUKFhTFBioIiBRB+qGs9w/eM5EUb+79JYxhvp/nuU9kOOewzr579sys2bM2EREREREREVF+9j/NoP3ll18watQoxMTEoGPHjsjOzkanTp3QsWNHFCxYENWqVcPYsWP/7liJiIiIiIiIiIiI8pX/aQbt+vXrUbt2bezevRsJCQnYs2cPevTogSZNmuDFixewsbFBhQoV/u5YiYiIiIiIiIiIiPKV/2kGbXBwMDp27AhjY2OYmOTkeDMzMwEAFSpUQN++fbFx48a/L0oiIiIiIiIiIiKifOh/StAWLFgQpqamAAALCwuYmZkhOjpa+X2pUqXw4sWLvydCIiIiIiIiIiIionzqf0rQfvzxxwgODlZ+rlGjBo4ePYrMzEykp6fj2LFj+OCDD/62IImIiIiIiIiIiIjyo/8pQdu2bVucOXMGer0eADBq1Chcv34dDRs2ROPGjeHv7w9bW9u/NVAiIiIiIiIiIiKi/OZ/WiRs+PDhGD58uPJzq1atsGPHDpw6dQrGxsZo2bIlGjdu/LcFSURERERERERERJQf/U8J2j/SoEEDNGjQ4O/6OCIiIiIiIiIiIqJ8738qcUBERERERERERERE/3d/eQbtqFGj/qsP1ul0WLt27X8dEBEREREREREREZFW/OUE7fnz51GgQAGUKlUKIvIfX6/T6f5PgRERERERERERERHld385QVu2bFlERUWhRIkSsLa2RqdOnVC6dOl/MjYiIiIiIiIiIiKifO0v16D18fHB9u3b8fnnn2Pt2rX4+uuvMWTIEBw6dAhJSUn/ZIxERERERERERERE+dJ/tUiYlZUV5s+fD19fX6xYsQLFixeHs7MzmjZtinHjxuHkyZPQ6/X/VKxERERERERERERE+cp/laA1MDU1RZs2bbB8+XJcunQJ8+fPR0xMDCZOnIiNGzf+3TESERERERERERER5Uv/U4LWQK/Xw9fXF2fOnMH9+/dRoEABlC9f/u+KjYiIiIiIiIiIiChf+8uLhBlkZ2fj0qVLOH78OLy9vZGWloYmTZrA2dkZbdu2ReHChf+JOImIiIiIiIiIiIjynb+coL158yaOHTuGkydPIj4+Hl9++SUmTpyIDh06oGTJkv9kjERERERERERERET50l9O0Pbr1w8FCxZEixYtYG1trZQyiIyMRGRk5B++p2bNmn9PlERERERERERERET50H9V4iAtLQ2nTp3C6dOn3/k6EYFOp0NQUND/KTgiIiIiIiIiIiKi/OwvJ2gXLVr0T8ZBREREREREREREpDl/OUHbrVu3fzIOIiIiIiIiIiIiIs0xUjsAIiIiIiIiIiIiIq1igpaIiIiIiIiIiIhIJUzQEhEREREREREREamECVoiIiIiIiIiIiIilTBBS0RERERERERERKQSJmiJiIiIiIiIiIiIVMIELREREREREREREZFKmKAlIiIiIiIiIiIiUgkTtEREREREREREREQqYYKWiIiIiIiIiIiISCVM0BIRERERERERERGphAlaIiIiIiIiIiIiIpUwQUtERERERERERESkEhO1A/it4OBguLi44NatWyhSpAi6dOkCBwcHmJmZ/el7Xr16ha1bt+LSpUsIDQ1F0aJF0bBhQzg6OqJ8+fJ5GD0RERERERERERHRX/deJWgTEhIwePBgVK5cGZ6enoiKisLixYuRlpaG2bNn/+n77t27h9OnT6NHjx748ssv8fr1a6xduxa9evXCsWPHULJkyTz8FkRERERERERERER/zXuVoN27dy+Sk5OxatUqFC9eHACQlZWFefPmwc7ODmXLlv3D99WvXx8///wzTEx+/Tr16tXD119/jR9++AHDhg3Li/CJiIiIiIiIiIiI/ivvVQ3aCxcuoEmTJkpyFgA6dOiA7OxsXLp06U/fZ2FhkSs5CwDlypVDyZIl8erVq38qXCIiIiIiIiIiIqL/k/cqQRsSEoJPPvkk1zYLCwuULl0aISEh/9VnPX36FLGxsahSpcrfGSIRERERERERERHR3+a9KnHw5s0bWFhY/G57sWLFkJCQ8Jc/R0Tg4uKCMmXKoFOnTv9zPCKClJSU//n9/xY6nQ6iE2RnC7Kzs/+2zzV81t/7mQIRQWpqKkTkb/vcd/kn2odt8+f+ibbJ+by8bR/uV++m0+lgJjltI+9x39FlZ7Nt3iGv2+efaBuAfedd2HfeLT/0HbbNf/ib3K/+/O+x77z7b/5L+g7b5t24X/05tfrOv+H6k9fm/+lz87591CIi0Ol0f+m171WC9u/i6emJq1evwsvLC4ULF/6fPycjIwNBQUF/Y2TvpwIFCqDsR2WRnpaO1NS0v/3z09P1f99nGaUjIyMDL56/QHp6+t/2ue/yT7YP2+bP/Z1tA+R9+3C/ercCBQrg0zKlkZ6ejqz3uO8Yp6fDKCMDweERbJs/kNft80+2DcC+8y7sO+/2b+47bJt3437159h33u3f0nfYNu/G/erPqdV3/g3Xn7w2/w+fp0L7qMnMzOwvve69StBaWFggMTHxd9sTEhJQrFixv/QZ+/fvx+rVq7FgwQI0adLk/xSPqakpPv300//TZ/wb6HQ6pOvSUaBgARTKLvi3fW52djbS0/UoUMAMRkZ/TzWNAgULwNTUFFWqVMnTO1F/d/uwbf7cP9E2QN63D/erd9PpdDBNS0V2gQKQQu9v39EVYNu8S163zz/RNgD7zruw77xbfug7bJv/8De5X/3532Pfefff/Jf0HbbNu3G/+nNq9Z1/w/Unr83fTY32UcuTJ0/+8mvfqwTtJ5988rtas4mJiYiOjv5dbdo/cvr0acydOxfjx49Hz549/8/x6HS6/9MM3H8TfboeRka6v3WnMzAyMvrbPtfISAedTodCBQv9LZ/3V/1T7cO2+XN/Z9vkfF7etw/3q3fLTk+DkZER5D3uOzojo5y2KcS2+SNqtM8/1TYA+867sO+827+977Bt3o371Z9j33m3f0PfYdu8G/erP6dW3/k3XH/y2vw/fZ467aOGv1reAHjPFglr0aIFLl++jDdv3ijbTp48CSMjIzRr1uyd77127RocHR3Rq1cvjB079p8OlYiIiIiIiIiIiOj/7L1K0Pbp0wdFihTB2LFj4evri0OHDmHJkiXo06cPypYtq7xu8ODBaNu2rfJzcHAwxo4di8qVK6NLly64ffu28r/Q0FA1vgoRERERERERERHRf/RelTgoVqwYtm3bBmdnZ4wdOxZFihRBz549MXHixFyvy87ORlZWlvJzQEAAEhMTkZiYiL59++Z6bbdu3bB48eI8iZ+IiIiIiIiIiIjov/FeJWgBoEqVKti6des7X7Njx45cP3fv3h3du3f/B6MiIiIiIiIiIiIi+vu9VyUOiIiIiIiIiIiIiLSECVoiIiIiIiIiIiIilTBBS0RERERERERERKQSJmiJiIiIiIiIiIiIVMIELREREREREREREZFKmKAlIiIiIiIiIiIiUgkTtEREREREREREREQqYYKWiIiIiIiIiIiISCVM0BIRERERERERERGphAlaIiIiIiIiIiIiIpUwQUtERERERERERESkEiZoiYiIiIiIiIiIiFTCBC0RERERERERERGRSpigJSIiIiIiIiIiIlIJE7REREREREREREREKmGCloiIiIiIiIiIiEglTNASERERERERERERqYQJWiIiIiIiIiIiIiKVMEFLREREREREREREpBImaImIiIiIiIiIiIhUwgQtERERERERERERkUqYoCUiIiIiIiIiIiJSCRO0RERERERERERERCphgpaIiIiIiIiIiIhIJUzQEhEREREREREREamECVoiIiIiIiIiIiIilTBBS0RERERERERERKQSJmiJiIiIiIiIiIiIVMIELREREREREREREZFKmKAlIiIiIiIiIiIiUgkTtEREREREREREREQqYYKWiIiIiIiIiIiISCVM0BIRERERERERERGphAlaIiIiIiIiIiIiIpUwQUtERERERERERESkEiZoiYiIiIiIiIiIiFTCBC0RERERERERERGRSpigJSIiIiIiIiIiIlIJE7REREREREREREREKmGCloiIiIiIiIiIiEglTNASERERERERERERqYQJWiIiIiIiIiIiIiKVMEFLREREREREREREpBImaImIiIiIiIiIiIhUwgQtERERERERERERkUqYoCUiIiIiIiIiIiJSCRO0RERERERERERERCphgpaIiIiIiIiIiIhIJUzQEhEREREREREREamECVoiIiIiIiIiIiIilTBBS0RERERERERERKQSJmiJiIiIiIiIiIiIVMIELREREREREREREZFKmKAlIiIiIiIiIiIiUgkTtEREREREREREREQqYYKWiIiIiIiIiIiISCVM0BIRERERERERERGphAlaIiIiIiIiIiIiIpUwQUtERERERERERESkEiZoiYiIiIiIiIiIiFTCBC0RERERERERERGRSpigJSIiIiIiIiIiIlIJE7REREREREREREREKmGCloiIiIiIiIiIiEglTNASERERERERERERqYQJWiIiIiIiIiIiIiKVMEFLREREREREREREpBImaImIiIiIiIiIiIhUwgQtERERERERERERkUqYoCUiIiIiIiIiIiJSCRO0RERERERERERERCphgpaIiIiIiIiIiIhIJUzQEhEREREREREREamECVoiIiIiIiIiIiIilTBBS0RERERERERERKQSJmiJiIiIiIiIiIiIVMIELREREREREREREZFKmKAlIiIiIiIiIiIiUgkTtEREREREREREREQqYYKWiIiIiIiIiIiISCVM0BIRERERERERERGp5L1L0AYHB2Po0KGoU6cOmjVrhiVLlkCv1//H94kINmzYgK+//hq1a9eGjY0Nbt++/c8HTERERERERERERPQ/eq8StAkJCRg8eDAyMjLg6emJiRMnYv/+/Vi8ePF/fO/GjRuxcuVKDBkyBOvXr0fp0qUxbNgwhIWF5UHkRERERERERERERP89E7UDeNvevXuRnJyMVatWoXjx4gCArKwszJs3D3Z2dihbtuwfvi89PR3r16/HsGHDMGTIEABA/fr10b59e2zatAlz587Nmy9ARERERERERERE9F94r2bQXrhwAU2aNFGSswDQoUMHZGdn49KlS3/6vps3byIpKQkdOnRQtpmZmaFt27a4cOHCPxkyERERERERERER0f/svUrQhoSE4JNPPsm1zcLCAqVLl0ZISMg73wfgd++tUqUKIiIikJaW9vcHS0RERERERERERPR/pBMRUTsIg5o1a2LChAmwtbXNtd3a2hp169aFs7PzH75v7dq1WLNmDe7evZtr+8mTJzFhwgRcuHDhT8sj/JmbN29CRGBqavrffYl/KYEgKSMZ2ZL1936uCHQ63d/2eUY6Y5ibFoEOf99n/hX/RPuwbd7xmX9z2wDqtA/3q3fTiUCSEoGs97jvGBtDZ14U8jf3x//kX9E2gCrt80+0DcC+8y7sO++WH/oO2+bduF/9Ofadd/tX9B22zbtxv/pzKvWdf8P1J6/N302t9lFDRkYGdDod6tWr9x9f+17VoH2fGDrg3z7Av6d00MHCrKjaYby32D5/jm3z59g2/4FOB51Fsb/3I//WT/vnP/fP/+C/p23+6c/+/R/7+9sGYN9550f+rZ+Wd5/9+z/GvvPnf4xt8+4/yP3qz/8Y+867/+C/p++wbdT77N//Me5X7/57vMb6M2yb949Op/vLecX3KkFrYWGBxMTE321PSEhAsWJ/PkBZWFhA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ─── Visualise case study ─────────────────────────────────────────────────\n", + "fig, ax = plt.subplots(figsize=(14, 7))\n", + "cs_colors = ['#F44336' if l else '#4CAF50' for l in case_labels]\n", + "x = range(len(case_results))\n", + "\n", + "ax.bar(x, pred_hyper, color=cs_colors, alpha=0.8, edgecolor='white', width=0.6)\n", + "ax.axhline(0.5, color='black', linestyle='--', lw=1.5, label='Decision threshold')\n", + "ax.set_xticks(x)\n", + "ax.set_xticklabels(case_descs, rotation=45, ha='right', fontsize=8)\n", + "ax.set_ylabel('Malicious Probability (HyperModel)')\n", + "ax.set_title('Case Study: HyperModel Scores on Adversarial URLs')\n", + "ax.set_ylim(0, 1.1)\n", + "\n", + "from matplotlib.patches import Patch\n", + "legend_els = [\n", + " Patch(facecolor='#F44336', alpha=0.8, label='True: Malicious'),\n", + " Patch(facecolor='#4CAF50', alpha=0.8, label='True: Benign'),\n", + "]\n", + "ax.legend(handles=legend_els + [\n", + " plt.Line2D([0],[0], color='black', linestyle='--', label='Threshold')],\n", + " loc='upper left')\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig(OUTPUT_DIR / 'case_study_scores.png', dpi=150, bbox_inches='tight')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 13. Save Models & Final Summary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import joblib\n", + "\n", + "MODELS_DIR = OUTPUT_DIR / 'models'\n", + "MODELS_DIR.mkdir(exist_ok=True)\n", + "\n", + "# Classical\n", + "joblib.dump(clf_models_bin['XGBoost (GPU)'], MODELS_DIR / 'xgb_binary.joblib')\n", + "joblib.dump(clf_models_bin['LightGBM (CPU)'], MODELS_DIR / 'lgbm_binary.joblib')\n", + "joblib.dump(tuned_xgb, MODELS_DIR / 'xgb_tuned_binary.joblib')\n", + "joblib.dump(tuned_lgbm, MODELS_DIR / 'lgbm_tuned_binary.joblib')\n", + "joblib.dump(tfidf_bin, MODELS_DIR / 'tfidf_lr_binary.joblib')\n", + "joblib.dump(scaler, MODELS_DIR / 'scaler.joblib')\n", + "\n", + "# DL models from stacking\n", + "import torch\n", + "for name, mdl in hypermodel.fitted_l0_.items():\n", + " if hasattr(mdl, 'net_'):\n", + " state = mdl.net_.state_dict() if not hasattr(mdl.net_, 'module') \\\n", + " else mdl.net_.module.state_dict()\n", + " torch.save(state, MODELS_DIR / f'{name}_net.pt')\n", + "\n", + "# Meta-learner\n", + "joblib.dump(hypermodel.meta, MODELS_DIR / 'hypermodel_meta.joblib')\n", + "\n", + "# Results tables\n", + "comparison_bin.to_csv(OUTPUT_DIR / 'results_binary.csv', index=False)\n", + "comparison_mc.to_csv(OUTPUT_DIR / 'results_multiclass.csv', index=False)\n", + "case_results.to_csv(OUTPUT_DIR / 'case_study_results.csv', index=False)\n", + "\n", + "print(f'\\n\\u2705 All models and results saved to: {OUTPUT_DIR.resolve()}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ─── Final Summary ───────────────────────────────────────────────────────\n", + "print('\\n' + '='*60)\n", + "print(' FINAL RESULTS SUMMARY')\n", + "print('='*60)\n", + "\n", + "print('\\n\\ud83d\\udccc Binary (Benign vs Malicious):')\n", + "ours_bin = comparison_bin[comparison_bin['Source']=='Ours']\n", + "print(ours_bin[['Method','Accuracy','F1 (macro)','AUC-ROC']].to_string(index=False))\n", + "\n", + "print('\\n\\ud83d\\udccc 4-Class (benign / phishing / defacement / malware):')\n", + "ours_mc = comparison_mc[comparison_mc['Source']=='Ours']\n", + "print(ours_mc[['Method','Accuracy','F1 (macro)','AUC-ROC']].to_string(index=False))\n", + "\n", + "print('\\n\\ud83d\\udccc Key Literature Baselines:')\n", + "print(' Sahingoz 2019 (RF): 97.98% acc')\n", + "print(' Le 2018 (URLNet): ~98.5% acc')\n", + "print(' Nguyen 2021 (Stacking): 97.5% acc')\n", + "print(' Aljofey 2022 (CharCNN): 96.75% acc')\n", + "\n", + "best_ours = ours_bin['Accuracy'].max()\n", + "best_lit = 0.985 # URLNet\n", + "delta = best_ours - best_lit\n", + "print(f'\\n Our best binary : {best_ours:.4f}')\n", + "print(f' \\u0394 vs literature : {delta:+.4f} ({\"\\u2705 BEAT\" if delta > 0 else \"\\u274c BELOW\"} URLNet baseline)')\n", + "print('='*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 14. Inference on New URLs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def predict_url(url: str, threshold: float = 0.5) -> dict:\n", + " \"\"\"Predict whether a URL is malicious.\"\"\"\n", + " ext = URLFeatureExtractor()\n", + " feat_df = ext.transform(pd.Series([url]), verbose=False)\n", + " feat_df = feat_df[feat_names]\n", + " X_sc = scaler.transform(feat_df.values.astype(np.float32)).astype(np.float32)\n", + "\n", + " proba = hypermodel.predict_proba(X_sc, np.array([url]))\n", + " score = proba[0, 1]\n", + " label = 'Malicious' if score > threshold else 'Benign'\n", + "\n", + " top = feat_imp_df.sort_values('importance', ascending=False).head(5)\n", + " top_signals = {row['feature']: round(float(feat_df.iloc[0].get(row['feature'], 0)), 3)\n", + " for _, row in top.iterrows()}\n", + "\n", + " return {\n", + " 'url': url,\n", + " 'prediction': label,\n", + " 'malicious_score': round(float(score), 4),\n", + " 'confidence': f\"{abs(score - 0.5) * 200:.1f}%\",\n", + " 'top_signals': top_signals,\n", + " }\n", + "\n", + "\n", + "test_urls = [\n", + " 'https://www.google.com/search?q=machine+learning',\n", + " 'http://secure-paypal-login.xyz/verify-account?user=victim@email.com',\n", + " 'https://github.com/anthropics/anthropic-sdk-python',\n", + " 'http://192.168.10.45/banking/login.php?redirect=true',\n", + " 'http://free-iphone-giveaway.tk/claim?id=abc123',\n", + "]\n", + "\n", + "for url in test_urls:\n", + " r = predict_url(url)\n", + " icon = '\\ud83d\\udd34' if r['prediction'] == 'Malicious' else '\\ud83d\\udfe2'\n", + " print(f\"{icon} [{r['prediction']:9s}] score={r['malicious_score']:.4f} | {url[:70]}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/urlmodel_info/models.py b/urlmodel_info/models.py new file mode 100644 index 0000000000000000000000000000000000000000..6ffb025d4cb48eb4586b5ea3be9d1ec3f5706dcc --- /dev/null +++ b/urlmodel_info/models.py @@ -0,0 +1,465 @@ +""" +Model architectures for Malicious URL Detection β€” GPU-accelerated. + +Provides: + β€’ build_xgb(n) – XGBoost classifier (GPU via device="cuda") + β€’ build_lgbm(n) – LightGBM classifier (CPU β€” GPU build unreliable) + β€’ build_tfidf_lr() – TF-IDF char-ngram + Logistic Regression pipeline + β€’ DeepURLClassifier – sklearn-compatible wrapper for CharCNN / BiLSTM / CNN-BiLSTM + β€’ ManualStackingEnsemble – OOF stacking with XGBoost GPU meta-learner +""" + +from __future__ import annotations + +import warnings +import numpy as np +import torch +import torch.nn as nn +from torch.cuda.amp import GradScaler +try: + from torch.amp import autocast # PyTorch >= 2.4 +except ImportError: + from torch.cuda.amp import autocast # PyTorch < 2.4 +from sklearn.base import BaseEstimator, ClassifierMixin, clone +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.linear_model import LogisticRegression +from sklearn.pipeline import Pipeline +from sklearn.model_selection import StratifiedKFold + +# ═════════════════════════════════════════════════════════════════════════════ +# 1. Character encoding (vectorised, numpy) +# ═════════════════════════════════════════════════════════════════════════════ + +MAX_URL_LEN = 200 + +# Build lookup table: ord(char) β†’ token_id +_CHAR_LUT = np.zeros(256, dtype=np.int64) # covers full byte range +_PRINTABLE = ( + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ " +) +for _i, _ch in enumerate(_PRINTABLE, start=1): + _CHAR_LUT[ord(_ch)] = _i +_UNK_ID = len(_PRINTABLE) + 1 # 96 +VOCAB_SIZE = _UNK_ID + 1 # 97 (indices 0..96) + + +def url_to_tensor(urls: list[str], max_len: int = MAX_URL_LEN) -> torch.Tensor: + """Vectorised charβ†’int encoding for a batch of URL strings. + + Returns a LongTensor of shape ``(len(urls), max_len)``. + """ + arr = np.zeros((len(urls), max_len), dtype=np.int64) + for i, url in enumerate(urls): + raw = str(url)[:max_len] + chars = np.frombuffer(raw.encode("ascii", "ignore"), dtype=np.uint8) + if len(chars) == 0: + continue + ids = _CHAR_LUT[chars] # mapped chars β†’ id, unmapped β†’ 0 + ids = np.where(ids > 0, ids, _UNK_ID) # replace 0 (unmapped) with UNK + ids[0 : min(len(ids), max_len)] # safety slice + arr[i, : len(ids)] = ids[: max_len] + return torch.from_numpy(arr) + + +# ═════════════════════════════════════════════════════════════════════════════ +# 2. Deep Learning architectures +# ═════════════════════════════════════════════════════════════════════════════ + +class CharCNNNet(nn.Module): + """1-D CNN on character-level URL embeddings.""" + + def __init__(self, num_classes: int = 2, embed_dim: int = 64): + super().__init__() + self.embed = nn.Embedding(VOCAB_SIZE, embed_dim, padding_idx=0) + self.convs = nn.Sequential( + nn.Conv1d(embed_dim, 128, kernel_size=3, padding=1), + nn.BatchNorm1d(128), nn.ReLU(), nn.MaxPool1d(2), + nn.Conv1d(128, 128, kernel_size=3, padding=1), + nn.BatchNorm1d(128), nn.ReLU(), nn.MaxPool1d(2), + nn.Conv1d(128, 256, kernel_size=3, padding=1), + nn.BatchNorm1d(256), nn.ReLU(), nn.AdaptiveMaxPool1d(1), + ) + self.head = nn.Sequential( + nn.Dropout(0.3), nn.Linear(256, 128), nn.ReLU(), + nn.Dropout(0.2), nn.Linear(128, num_classes), + ) + + def forward(self, x): + x = self.embed(x).permute(0, 2, 1) # (B, C, L) + x = self.convs(x).squeeze(-1) # (B, 256) + return self.head(x) + + +class CharBiLSTMNet(nn.Module): + """Bidirectional LSTM on character embeddings.""" + + def __init__(self, num_classes: int = 2, embed_dim: int = 64, + hidden: int = 128, n_layers: int = 2): + super().__init__() + self.embed = nn.Embedding(VOCAB_SIZE, embed_dim, padding_idx=0) + self.lstm = nn.LSTM( + embed_dim, hidden, num_layers=n_layers, + batch_first=True, bidirectional=True, dropout=0.3, + ) + self.head = nn.Sequential( + nn.Dropout(0.3), nn.Linear(hidden * 2, 128), nn.ReLU(), + nn.Dropout(0.2), nn.Linear(128, num_classes), + ) + + def forward(self, x): + x = self.embed(x) # (B, L, E) + _, (h, _) = self.lstm(x) # h: (layers*2, B, H) + h = torch.cat([h[-2], h[-1]], dim=-1) # (B, H*2) + return self.head(h) + + +class CNNBiLSTMNet(nn.Module): + """Hybrid: CNN feature extractor β†’ BiLSTM sequence modelling.""" + + def __init__(self, num_classes: int = 2, embed_dim: int = 64, hidden: int = 128): + super().__init__() + self.embed = nn.Embedding(VOCAB_SIZE, embed_dim, padding_idx=0) + self.cnn = nn.Sequential( + nn.Conv1d(embed_dim, 128, 3, padding=1), + nn.BatchNorm1d(128), nn.ReLU(), nn.MaxPool1d(2), + ) + self.lstm = nn.LSTM( + 128, hidden, num_layers=1, + batch_first=True, bidirectional=True, dropout=0.0, + ) + self.head = nn.Sequential( + nn.Dropout(0.3), nn.Linear(hidden * 2, 128), nn.ReLU(), + nn.Dropout(0.2), nn.Linear(128, num_classes), + ) + + def forward(self, x): + x = self.embed(x).permute(0, 2, 1) # (B, C, L) + x = self.cnn(x).permute(0, 2, 1) # (B, L', 128) + _, (h, _) = self.lstm(x) + h = torch.cat([h[-2], h[-1]], dim=-1) + return self.head(h) + + +_ARCH_MAP = { + "cnn": CharCNNNet, + "bilstm": CharBiLSTMNet, + "cnn_bilstm": CNNBiLSTMNet, +} + + +# ═════════════════════════════════════════════════════════════════════════════ +# 3. sklearn-compatible deep learning wrapper (GPU + AMP) +# ═════════════════════════════════════════════════════════════════════════════ + +class DeepURLClassifier(BaseEstimator, ClassifierMixin): + """scikit-learn interface for character-level DL URL models. + + Features: + β€’ Automatic mixed precision (AMP) for speed + β€’ Multi-GPU via ``nn.DataParallel`` + β€’ Batch prediction to avoid OOM + β€’ torch.compile on single-GPU setups + """ + + def __init__( + self, + arch: str = "cnn", + num_classes: int = 2, + epochs: int = 20, + batch_size: int = 2048, + lr: float = 1e-3, + device: str = "auto", + max_len: int = MAX_URL_LEN, + ): + self.arch = arch + self.num_classes = num_classes + self.epochs = epochs + self.batch_size = batch_size + self.lr = lr + self.device = device + self.max_len = max_len + + def _resolve_device(self): + if self.device == "auto": + return "cuda" if torch.cuda.is_available() else "cpu" + return self.device + + def fit(self, X, y, class_weight=None): + dev = self._resolve_device() + net = _ARCH_MAP[self.arch](num_classes=self.num_classes).to(dev) + + # Multi-GPU + n_gpus = torch.cuda.device_count() + if dev == "cuda" and n_gpus > 1: + net = nn.DataParallel(net) + print(f" DataParallel across {n_gpus} GPUs") + + self.net_ = net + + # Loss with optional class weight + weight = None + if class_weight == "balanced": + counts = np.bincount(np.asarray(y).astype(int), minlength=self.num_classes) + w = len(y) / (self.num_classes * np.maximum(counts, 1)) + weight = torch.tensor(w, dtype=torch.float32, device=dev) + + criterion = nn.CrossEntropyLoss(weight=weight) + optimiser = torch.optim.AdamW(net.parameters(), lr=self.lr, weight_decay=1e-4) + scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimiser, T_max=self.epochs) + _use_amp = (dev == "cuda") + scaler = GradScaler(enabled=_use_amp) + + urls = list(X) + labels = torch.tensor(np.asarray(y).astype(np.int64), device=dev) + + net.train() + for epoch in range(self.epochs): + perm = torch.randperm(len(urls)) + total_loss = 0.0 + n_batches = 0 + for start in range(0, len(urls), self.batch_size): + idx = perm[start: start + self.batch_size] + batch_urls = [urls[i] for i in idx.tolist()] + xb = url_to_tensor(batch_urls, self.max_len).to(dev) + yb = labels[idx] + + optimiser.zero_grad(set_to_none=True) + with autocast("cuda", enabled=_use_amp): + logits = net(xb) + loss = criterion(logits, yb) + scaler.scale(loss).backward() + scaler.step(optimiser) + scaler.update() + total_loss += loss.item() + n_batches += 1 + scheduler.step() + if (epoch + 1) % 5 == 0 or epoch == 0: + print(f" Epoch {epoch+1:>3d}/{self.epochs} loss={total_loss/n_batches:.4f}") + return self + + @torch.inference_mode() + def predict_proba(self, X): + dev = self._resolve_device() + net = self.net_ + net.eval() + _use_amp = (dev == "cuda") + urls = list(X) + all_probs = [] + for start in range(0, len(urls), self.batch_size): + batch = urls[start: start + self.batch_size] + xb = url_to_tensor(batch, self.max_len).to(dev) + with autocast("cuda", enabled=_use_amp): + logits = net(xb) + probs = torch.softmax(logits.float(), dim=-1).cpu().numpy() + all_probs.append(probs) + return np.concatenate(all_probs, axis=0) + + def predict(self, X): + return np.argmax(self.predict_proba(X), axis=1) + + +# ═════════════════════════════════════════════════════════════════════════════ +# 4. Classical ML builders +# ═════════════════════════════════════════════════════════════════════════════ + +def build_xgb(num_classes: int = 2, **extra): + """XGBoost classifier with GPU acceleration.""" + import xgboost as xgb + + dev = "cuda" if torch.cuda.is_available() else "cpu" + objective = "binary:logistic" if num_classes == 2 else "multi:softprob" + params = dict( + n_estimators=500, + max_depth=8, + learning_rate=0.05, + tree_method="hist", + device=dev, + objective=objective, + eval_metric="logloss" if num_classes == 2 else "mlogloss", + n_jobs=-1, + random_state=42, + ) + if num_classes > 2: + params["num_class"] = num_classes + params.update(extra) + return xgb.XGBClassifier(**params) + + +def build_lgbm(num_classes: int = 2, **extra): + """LightGBM classifier (CPU only β€” GPU build unreliable on cloud).""" + import lightgbm as lgb + + objective = "binary" if num_classes == 2 else "multiclass" + params = dict( + n_estimators=500, + max_depth=8, + learning_rate=0.05, + num_leaves=63, + objective=objective, + class_weight="balanced", + device_type="cpu", + n_jobs=-1, + random_state=42, + verbose=-1, + ) + if num_classes > 2: + params["num_class"] = num_classes + params.update(extra) + return lgb.LGBMClassifier(**params) + + +def build_tfidf_lr_pipeline(num_classes: int = 2): + """TF-IDF character n-gram + Logistic Regression pipeline.""" + return Pipeline([ + ("tfidf", TfidfVectorizer( + analyzer="char_wb", + ngram_range=(2, 5), + max_features=100_000, + sublinear_tf=True, + dtype=np.float32, + )), + ("lr", LogisticRegression( + C=1.0, + max_iter=300, + solver="saga", + n_jobs=-1, + random_state=42, + )), + ]) + + +# ═════════════════════════════════════════════════════════════════════════════ +# 5. Stacking HyperModel +# ═════════════════════════════════════════════════════════════════════════════ + +def build_stacking_hypermodel(num_classes: int = 2, use_deep: bool = True, cv: int = 5): + """Return a dict with ``level0`` models and ``meta`` learner config. + + Level-0 models: + β€’ ``xgb`` – XGBoost (GPU, features) + β€’ ``lgbm`` – LightGBM (CPU, features) + β€’ ``tfidf_lr`` – TF-IDF + LR (CPU, URL strings) + β€’ ``char_cnn`` – CharCNN (GPU, URL strings) [if use_deep] + β€’ ``char_bilstm`` – CharBiLSTM (GPU, URL strings) [if use_deep] + + Meta-learner: XGBoost (GPU). + """ + level0 = { + "xgb": build_xgb(num_classes), + "lgbm": build_lgbm(num_classes), + "tfidf_lr": build_tfidf_lr_pipeline(num_classes), + } + if use_deep: + level0["char_cnn"] = DeepURLClassifier( + arch="cnn", num_classes=num_classes, epochs=15, + batch_size=2048, lr=1e-3, device="auto", + ) + level0["char_bilstm"] = DeepURLClassifier( + arch="bilstm", num_classes=num_classes, epochs=12, + batch_size=2048, lr=5e-4, device="auto", + ) + + meta = build_xgb(num_classes, n_estimators=300, max_depth=4, learning_rate=0.1) + return {"level0": level0, "meta": meta, "cv": cv} + + +class ManualStackingEnsemble(BaseEstimator, ClassifierMixin): + """Out-of-fold stacking ensemble. + + Generates OOF probability predictions from each L0 model across + ``cv`` folds, stacks them as features, and trains an XGBoost + meta-learner on those stacked predictions. + """ + + def __init__(self, level0: dict, meta, cv: int = 5, num_classes: int = 2): + self.level0 = level0 + self.meta = meta + self.cv = cv + self.num_classes = num_classes + + def _uses_urls(self, name: str) -> bool: + """Whether a model operates on raw URL strings.""" + return name in ("tfidf_lr", "char_cnn", "char_bilstm") + + def fit(self, X_feat, X_url, y): + """Train all L0 models via OOF, then train the meta-learner. + + Parameters + ---------- + X_feat : np.ndarray (n, d) – scaled feature matrix. + X_url : np.ndarray (n,) – raw URL strings. + y : np.ndarray (n,) – labels. + """ + y = np.asarray(y) + n = len(y) + oof = np.zeros((n, self.num_classes * len(self.level0)), dtype=np.float32) + kf = StratifiedKFold(n_splits=self.cv, shuffle=True, random_state=42) + + self.fitted_l0_ = {} + + for model_idx, (name, base) in enumerate(self.level0.items()): + print(f"\n β–Έ OOF training: {name}") + col_start = model_idx * self.num_classes + col_end = col_start + self.num_classes + fold_models = [] + + for fold, (tr_idx, val_idx) in enumerate(kf.split(X_feat, y)): + mdl = clone(base) + + if self._uses_urls(name): + X_tr = X_url[tr_idx] + X_val = X_url[val_idx] + else: + X_tr = X_feat[tr_idx] + X_val = X_feat[val_idx] + + y_tr = y[tr_idx] + + # Only DeepURLClassifier gets class_weight + if isinstance(mdl, DeepURLClassifier): + mdl.fit(X_tr, y_tr, class_weight="balanced") + else: + mdl.fit(X_tr, y_tr) + + proba = np.asarray(mdl.predict_proba(X_val)) + oof[val_idx, col_start:col_end] = proba + fold_models.append(mdl) + + # Retrain on full data for inference + final = clone(base) + if self._uses_urls(name): + X_full = X_url + else: + X_full = X_feat + if isinstance(final, DeepURLClassifier): + final.fit(X_full, y, class_weight="balanced") + else: + final.fit(X_full, y) + self.fitted_l0_[name] = final + + # Train meta-learner on OOF predictions + print("\n β–Έ Training meta-learner …") + self.meta.fit(oof, y) + self.oof_ = oof + return self + + def _build_meta_features(self, X_feat, X_url): + """Stack L0 predictions into a meta-feature matrix.""" + parts = [] + for name, mdl in self.fitted_l0_.items(): + if self._uses_urls(name): + proba = np.asarray(mdl.predict_proba(X_url)) + else: + proba = np.asarray(mdl.predict_proba(X_feat)) + parts.append(proba) + return np.hstack(parts).astype(np.float32) + + def predict_proba(self, X_feat, X_url): + meta_X = self._build_meta_features(X_feat, X_url) + return np.asarray(self.meta.predict_proba(meta_X)) + + def predict(self, X_feat, X_url): + return np.argmax(self.predict_proba(X_feat, X_url), axis=1) diff --git a/urlmodel_info/results_accuracy_bar.png b/urlmodel_info/results_accuracy_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..a07e55e1e9e6e37654eb58d77dd94506cf194d8c --- /dev/null +++ b/urlmodel_info/results_accuracy_bar.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:40d2e832b38c7f6ca73481ee7d7863fbd816ec5da2cf79493649258a9545a077 +size 125597 diff --git a/urlmodel_info/results_binary.csv b/urlmodel_info/results_binary.csv new file mode 100644 index 0000000000000000000000000000000000000000..6350a3d0939b5ba3caf77b445a42e24bb5fe3da5 --- /dev/null +++ b/urlmodel_info/results_binary.csv @@ -0,0 +1,17 @@ +Method,Accuracy,F1 (macro),AUC-ROC,Source +HyperModel (Stacking Ensemble),0.9888435875582583,0.9875919887801082,0.9989987226653723,Ours +CharCNN,0.98718509816568,0.9857623867375606,0.9985083567225014,Ours +LSTM (Bahnsen 2018),0.987,,,Literature +CNN-BiLSTM,0.9866936939012124,0.9852331088044274,0.998483685483307,Ours +URLNet CharCNN (Le 2018),0.985,,0.986,Literature +CharBiLSTM,0.9844439837529465,0.9827525986682384,0.997992440144913,Ours +XGBoost (Optuna-tuned),0.9815876964657284,0.9794700103530696,0.9973786670930095,Ours +LightGBM (Optuna-tuned),0.9813957416749207,0.9793213647507326,0.9971396658702955,Ours +TF-IDF + LR,0.9803438294212947,0.9780726993573674,0.9971270195370545,Ours +XGBoost (GPU),0.980174909205384,0.9778762050700486,0.996815861156588,Ours +RF on URL features (Sahingoz 2019),0.9798,0.9793,,Literature +LightGBM (CPU),0.9781862575726165,0.9757796254760449,0.9965268674959424,Ours +Stacking CNN+LSTM+GRU (Nguyen 2021),0.975,0.972,,Literature +XGBoost (Rao & Pais 2019),0.9685,,0.993,Literature +CharCNN (Aljofey 2022),0.9675,0.9671,0.991,Literature +Hybrid DNN+LSTM (Ozcan 2021),0.964,,0.973,Literature diff --git a/urlmodel_info/results_confusion_matrix_hypermodel.png b/urlmodel_info/results_confusion_matrix_hypermodel.png new file mode 100644 index 0000000000000000000000000000000000000000..b91754024855a147f59d278b72884bb017cf3ebd Binary files /dev/null and b/urlmodel_info/results_confusion_matrix_hypermodel.png differ diff --git a/urlmodel_info/results_multiclass.csv b/urlmodel_info/results_multiclass.csv new file mode 100644 index 0000000000000000000000000000000000000000..093ce526d94d57e942e38d8cda711370aca1938d --- /dev/null +++ b/urlmodel_info/results_multiclass.csv @@ -0,0 +1,14 @@ +Method,Accuracy,F1 (macro),AUC-ROC,Source +LSTM (Bahnsen 2018),0.987,,,Literature +URLNet CharCNN (Le 2018),0.985,,0.986,Literature +CharCNN (4c),0.9818717895561238,0.9753171238383057,0.9984977568096811,Ours +RF on URL features (Sahingoz 2019),0.9798,0.9793,,Literature +TF-IDF + LR (4c),0.9775028985173412,0.9688250694651577,0.9976441845497839,Ours +CNN-BiLSTM (4c),0.9775028985173412,0.9704743465155556,0.9978764795395705,Ours +Stacking CNN+LSTM+GRU (Nguyen 2021),0.975,0.972,,Literature +"XGBoost (GPU, 4c)",0.9745237601640062,0.963029237159016,0.9967577752908982,Ours +CharBiLSTM (4c),0.9730111564124417,0.9654044824449659,0.9970405309646729,Ours +XGBoost (Rao & Pais 2019),0.9685,,0.993,Literature +"LightGBM (CPU, 4c)",0.9681047919593977,0.9580879899564781,0.9965663369608954,Ours +CharCNN (Aljofey 2022),0.9675,0.9671,0.991,Literature +Hybrid DNN+LSTM (Ozcan 2021),0.964,,0.973,Literature diff --git a/urlmodel_info/results_roc_curves.png b/urlmodel_info/results_roc_curves.png new file mode 100644 index 0000000000000000000000000000000000000000..578f3e166a092baf81bc0979dd70b31f4e89ac31 --- /dev/null +++ b/urlmodel_info/results_roc_curves.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7d9939b0eb0a6f9cb91c102a2bb0972f82272e97182faa446aa9bd839367e8c +size 106690 diff --git a/urlmodel_info/scaler.joblib b/urlmodel_info/scaler.joblib new file mode 100644 index 0000000000000000000000000000000000000000..7d5b130b80b433916dbec8ce5efc3e2a8b2a4822 --- /dev/null +++ b/urlmodel_info/scaler.joblib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4d6639ea1b29bfd247db4edd27337a54ddf028f8463e5c2739d9f62642d8fb6 +size 1879 diff --git a/urlmodel_info/tfidf_lr_binary.joblib b/urlmodel_info/tfidf_lr_binary.joblib new file mode 100644 index 0000000000000000000000000000000000000000..7a9d8b7d26a7ca8e461b885fef31417612b272b8 --- /dev/null +++ b/urlmodel_info/tfidf_lr_binary.joblib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:abfae559a67c78f78691250b433347120d3691f6616eb87205bf2459d9175b3b +size 3411536 diff --git a/urlmodel_info/xgb_binary.joblib b/urlmodel_info/xgb_binary.joblib new file mode 100644 index 0000000000000000000000000000000000000000..594f7b7b6e8ccb122acec10760a7a7d475d7f69a --- /dev/null +++ b/urlmodel_info/xgb_binary.joblib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7bcd4c4d6a3b1d904161717bee4866d3217bc23bceb615108d364ba448f97176 +size 4805146 diff --git a/xgb_malware_model.joblib b/xgb_malware_model.joblib new file mode 100644 index 0000000000000000000000000000000000000000..9cc18c3562cd323c1d39b58fa30927670a87f539 --- /dev/null +++ b/xgb_malware_model.joblib @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:76db5bb9ce9e4ae243e782f5f89e9c689ac22611e2eec1dd04e36b37ff7c3ce5 +size 2033818