#!/usr/bin/env python3
"""
HDGL Hypervisor - Unified Lattice System
=========================================
Elegant 32-slot analog computation with hardware virtualization,
native Linux integration, and superposition-aware execution.

Architecture:
  - HDGL_Hypervisor (Host) manages multiple HDGL_VM instances (Guests).
  - Each VM has an isolated LatticeCore, VirtualFS, and BinaryInterpreter.
  - VM provisioning is managed via the VMManager.
"""

import numpy as np
import matplotlib.pyplot as plt
import psutil
import json
from pathlib import Path
from typing import Dict, List, Optional, Any, Callable
from dataclasses import dataclass
from collections import deque
import uuid # Added for unique VM IDs

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Core Constants & Types (UNCHANGED)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

PHI = 1.6180339887498948
SQRT_PHI = 1.272019649514069
STRANDS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']

@dataclass
class Instruction:
    op: str
    a: int = 0
    b: int = 0
    val: float = 0.0

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Lattice Engine (UNCHANGED)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class LatticeCore:
    # ... (LatticeCore implementation remains the same)
    """32-slot analog superposition engine"""
    
    def __init__(self, blend: float = 0.05):
        self.D = np.zeros(32)
        self.omega = 0.0
        self.blend = blend
        self.cycles = 0
        
        self.resonance = [2, 6, 10, 14, 18, 22, 26, 30]
        
        self.history_size = 1000
        self.history_D = deque(maxlen=self.history_size)
        self.history_omega = deque(maxlen=self.history_size)
    
    def step(self, n: int = 1):
        """Evolve lattice through n superposition iterations"""
        for _ in range(n):
            D_prev = self.D.copy()
            
            for i in range(32):
                res = sum(D_prev[r] for r in self.resonance if r != i)
                
                self.D[i] = np.tanh(
                    D_prev[i] + self.blend * (
                        D_prev[i] * PHI + res + self.omega
                    )
                )
            
            self.omega += 0.01 * self.blend
            self.cycles += 1
            
            self.history_D.append(self.D.copy())
            self.history_omega.append(self.omega)
    
    def get_strand(self, strand: str) -> np.ndarray:
        idx = STRANDS.index(strand.upper())
        return self.D[idx*4:(idx+1)*4]
    
    def set_strand(self, strand: str, vals: List[float]):
        idx = STRANDS.index(strand.upper())
        self.D[idx*4:(idx+1)*4] = np.array(vals[:4])
    
    def to_binary(self, threshold: float = SQRT_PHI) -> str:
        return ''.join('1' if d > threshold else '0' for d in self.D)
    
    def to_hex(self, threshold: float = SQRT_PHI) -> str:
        binary = self.to_binary(threshold)
        return f"0x{int(binary[::-1], 2):08X}"
    
    def reset(self):
        self.D = np.zeros(32)
        self.omega = 0.0
        self.cycles = 0
        self.history_D.clear()
        self.history_omega.clear()

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Hardware Abstraction (UNCHANGED)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class HardwareLayer:
    # ... (HardwareLayer implementation remains the same)
    """Maps physical hardware to lattice state"""
    
    @staticmethod
    def detect() -> Dict[str, Any]:
        try:
            return {
                'cpu': {
                    'cores': psutil.cpu_count(logical=False) or 1,
                    'threads': psutil.cpu_count(logical=True) or 1,
                    'load': psutil.cpu_percent(percpu=True, interval=0.1)
                },
                'memory': {
                    'total_gb': psutil.virtual_memory().total / (1024**3),
                    'used_pct': psutil.virtual_memory().percent
                },
                'disk': [
                    {'dev': d.device, 'mount': d.mountpoint, 
                     'used_pct': psutil.disk_usage(d.mountpoint).percent}
                    for d in psutil.disk_partitions()
                ][:4],
                'net': {
                    name: {'tx_mb': s.bytes_sent/(1024**2), 'rx_mb': s.bytes_recv/(1024**2)}
                    for name, s in psutil.net_io_counters(pernic=True).items()
                }
            }
        except Exception:
            return {'error': 'Hardware detection failed'}

    @staticmethod
    def map_to_lattice(core: LatticeCore):
        hw = HardwareLayer.detect()
        if 'error' in hw: return # Skip mapping on error
        
        cpu_load = hw['cpu']['load']
        for i in range(4):
            core.D[i] = (cpu_load[i]/100 if i < len(cpu_load) else 0.0)
        
        mem_pct = hw['memory']['used_pct'] / 100
        mem_gb = min(hw['memory']['total_gb'] / 32, 1.0)
        core.D[4:8] = [mem_pct, mem_gb, mem_pct*mem_gb, 0.5]
        
        for i, disk in enumerate(hw['disk'][:4]):
            core.D[8+i] = disk['used_pct'] / 100
        
        nets = list(hw['net'].values())
        for i in range(4):
            core.D[12+i] = min(nets[i]['tx_mb']/1024, 1.0) if i < len(nets) else 0.0
        
        core.D[16:] = np.random.rand(16) * 0.1
        core.omega = np.mean(core.D[:16])

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Virtual Filesystem (FIXED & MINOR CHANGE)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class VirtualFS:
    """Minimal hierarchical filesystem"""
    
    def __init__(self):
        # FIX: Changed structure to make navigation simple and robust
        self.root = {
            'boot': {
                'grub.cfg': {'timeout': 5, 'default': 0, 'entries': []},
                'vmlinuz': b'<kernel_placeholder>',
                'initrd.img': b'<initramfs_placeholder>'
            },
            'dev': {'hdgl_lattice': None},  # Device file
            'proc': {'lattice_state': None},  # Proc file
            'bin': {},
            'tmp': {}
        }
    
    def resolve(self, path: str) -> Any:
        """Navigate to path"""
        if path == '/':
            return self.root
        parts = path.strip('/').split('/')
        node = self.root
        for p in parts:
            node = node[p] # Relies on the fixed structure
        return node
    
    def ls(self, path: str = '/') -> List[str]:
        node = self.resolve(path)
        return list(node.keys()) if isinstance(node, dict) else []
    
    def read(self, path: str) -> Any:
        return self.resolve(path)
    
    def write(self, path: str, data: Any):
        parts = path.strip('/').split('/')
        node = self.root
        for p in parts[:-1]:
            node = node.setdefault(p, {})
        node[parts[-1]] = data
    
    def rm(self, path: str):
        parts = path.strip('/').split('/')
        node = self.root
        for p in parts[:-1]:
            node = node[p]
        del node[parts[-1]]

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Boot System & Binary Interpreter (UNCHANGED)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class BootManager:
    # ... (BootManager implementation remains the same, used by VM)
    """GRUB-style boot with lattice kernel"""
    
    def __init__(self, core: LatticeCore, fs: VirtualFS):
        self.core = core
        self.fs = fs
        self.entries = []
    
    def add_entry(self, name: str, phi_seed: float, init_steps: int = 50):
        self.entries.append({'name': name, 'phi_seed': phi_seed, 'steps': init_steps})
        cfg = self.fs.read('/boot/grub.cfg')
        cfg['entries'] = self.entries
    
    def show_menu(self):
        # ... (show_menu remains the same)
        print("\n" + "="*60)
        print("HDGL Lattice Bootloader v1.0")
        print("="*60)
        for i, e in enumerate(self.entries):
            print(f"  [{i+1}] {e['name']} (φ={e['phi_seed']:.4f})")
        print("="*60)
    
    def boot(self, idx: int = 0):
        # ... (boot remains the same)
        if not 0 <= idx < len(self.entries):
            return False
        
        entry = self.entries[idx]
        print(f"\nBooting: {entry['name']}")
        print(f"Initializing lattice (φ-seed={entry['phi_seed']:.5f})...")
        
        self.core.reset()
        np.random.seed(int(entry['phi_seed'] * 1e6))
        self.core.D[:] = np.random.rand(32) * entry['phi_seed']
        
        print(f"Running {entry['steps']} pre-boot cycles...")
        self.core.step(entry['steps'])
        
        print(f"Kernel loaded. Lattice: {self.core.to_hex()}")
        print("System ready.\n")
        return True


class BinaryInterpreter:
    # ... (BinaryInterpreter implementation remains the same, used by VM)
    """Execute HDGL binary programs on lattice"""
    
    OPCODES = {'NOP', 'SET', 'ADD', 'MUL', 'JMP', 'JZ', 'HALT'}
    
    def __init__(self, core: LatticeCore):
        self.core = core
        self.program = []
        self.ip = 0
    
    def load(self, code: str) -> int:
        # ... (load remains the same)
        self.program = []
        for line in code.strip().split('\n'):
            line = line.split('#')[0].strip()
            if not line: continue
            
            parts = line.split()
            op = parts[0].upper()
            
            if op not in self.OPCODES: continue
            
            inst = Instruction(op=op)
            
            if op == 'SET':
                inst.a = int(parts[1][1:]) - 1
                inst.val = float(parts[2])
            elif op == 'ADD':
                inst.a = int(parts[1][1:]) - 1
                inst.b = int(parts[2][1:]) - 1
            elif op == 'MUL':
                inst.a = int(parts[1][1:]) - 1
                inst.val = float(parts[2])
            elif op in ['JMP', 'JZ']:
                inst.a = int(parts[1])
            
            self.program.append(inst)
        
        return len(self.program)
    
    def run(self, max_cycles: int = 10000):
        # ... (run remains the same)
        self.ip = 0
        cycles = 0
        
        while self.ip < len(self.program) and cycles < max_cycles:
            inst = self.program[self.ip]
            
            if inst.op == 'HALT': break
            elif inst.op == 'NOP': pass
            elif inst.op == 'SET':
                self.core.D[inst.a] = np.tanh(inst.val)
            elif inst.op == 'ADD':
                self.core.D[inst.a] = np.tanh(self.core.D[inst.a] + self.core.D[inst.b])
            elif inst.op == 'MUL':
                self.core.D[inst.a] = np.tanh(self.core.D[inst.a] * inst.val)
            elif inst.op == 'JMP':
                self.ip = inst.a
                continue
            elif inst.op == 'JZ':
                # Simplified Jump Zero logic
                if abs(self.core.D[inst.a]) < 1e-6:
                    self.ip = inst.b
                    continue
            
            self.ip += 1
            cycles += 1
        
        return cycles

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Virtual Machine Abstraction (NEW)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class HDGL_VM:
    """Encapsulates a single virtual HDGL system (Guest)"""
    
    def __init__(self, name: str, blend: float = 0.05):
        self.id = str(uuid.uuid4())[:8]
        self.name = name
        self.core = LatticeCore(blend=blend)
        self.fs = VirtualFS()
        self.boot = BootManager(self.core, self.fs)
        self.interp = BinaryInterpreter(self.core)
        self.status = "OFF"
        
        # Default boot entries for the VM
        self.boot.add_entry(f"{name} Minimal", 0.1, 30)
        self.boot.add_entry(f"{name} Resonant", PHI/10, 50)
        
    def boot_vm(self, idx: int = 0):
        if self.boot.boot(idx):
            self.status = "RUNNING"
    
    def step_vm(self, n: int = 1):
        if self.status == "RUNNING":
            self.core.step(n)
        else:
            print(f"VM '{self.name}' is {self.status}. Boot first.")
    
    def run_program(self, code: str):
        self.interp.load(code)
        cycles = self.interp.run()
        print(f"Program finished in {cycles} cycles.")
    
    def get_state(self):
        return {
            'id': self.id,
            'name': self.name,
            'status': self.status,
            'cycles': self.core.cycles,
            'hex_state': self.core.to_hex()
        }

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# VM Management Layer (NEW)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class VMManager:
    """Manages the lifecycle and state of all HDGL VMs"""
    
    def __init__(self):
        self.vms: Dict[str, HDGL_VM] = {}
        self.active_vm_id: Optional[str] = None

    def provision(self, name: str) -> HDGL_VM:
        """Create and register a new VM"""
        if name in [v.name for v in self.vms.values()]:
            print(f"VM with name '{name}' already exists.")
            return None
        
        vm = HDGL_VM(name)
        self.vms[vm.id] = vm
        self.active_vm_id = vm.id
        print(f"Provisioned VM '{name}' (ID: {vm.id}). Set as active.")
        return vm

    def destroy(self, id_or_name: str) -> bool:
        """Destroy a VM"""
        vm = self.get_vm(id_or_name)
        if not vm:
            return False
        
        if vm.id == self.active_vm_id:
            self.active_vm_id = None
        
        del self.vms[vm.id]
        print(f"Destroyed VM '{vm.name}' (ID: {vm.id})")
        return True

    def get_vm(self, id_or_name: str) -> Optional[HDGL_VM]:
        """Retrieve VM by ID or Name"""
        if id_or_name in self.vms:
            return self.vms[id_or_name]
        
        for vm in self.vms.values():
            if vm.name == id_or_name:
                return vm
        
        return None
    
    def get_active_vm(self) -> Optional[HDGL_VM]:
        """Get the currently selected VM"""
        if self.active_vm_id and self.active_vm_id in self.vms:
            return self.vms[self.active_vm_id]
        return None

    def list_vms(self):
        """Display summary of all VMs"""
        print("\n--- VM Inventory ---")
        if not self.vms:
            print("No VMs provisioned.")
            return
            
        print(f"{'ACTIVE':<8}{'ID':<10}{'NAME':<20}{'STATUS':<10}{'CYCLES':<10}{'HEX STATE':<15}")
        print("-" * 75)
        for vm in self.vms.values():
            active = "-> " if vm.id == self.active_vm_id else ""
            state = vm.core.to_hex() if vm.status == "RUNNING" else "N/A"
            print(f"{active:<8}{vm.id:<10}{vm.name:<20}{vm.status:<10}{vm.core.cycles:<10}{state:<15}")
        print("-" * 75)

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Visualization (MODIFIED to accept the active VM Core)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class LatticeViz:
    """Real-time lattice visualization"""
    
    def __init__(self, core: LatticeCore):
        self.core = core
        self.fig, self.ax = plt.subplots(3, 1, figsize=(12, 8))
        # ... (initialization remains the same, but self.core can be updated)
        # Setup initial plots
        self.lines = [self.ax[0].plot([], [], alpha=0.6, lw=0.8)[0] for _ in range(32)]
        self.omega_line, = self.ax[1].plot([], [], 'r-', lw=2)
        self.bars = self.ax[2].bar(range(32), self.core.D, alpha=0.7)
        
        # Set titles/labels...
        self.ax[0].set_title('Lattice Evolution (D1-D32)')
        self.ax[1].set_title('Omega Field')
        self.ax[2].set_title('Current State')
        self.ax[2].set_xticks(range(0, 32, 4))
        self.ax[2].set_xticklabels([f'D{i+1}' for i in range(0, 32, 4)])
        # ... (other plot setup)
        
        plt.tight_layout()
        plt.ion()
        plt.show()

    def set_core(self, core: LatticeCore):
        """Switch the core being visualized"""
        self.core = core
        print(f"Visualization switched to core at cycle {core.cycles}")

    def update(self):
        if not self.core.history_D:
            return
        
        steps = range(len(self.core.history_D))
        
        # Update evolution
        for i, line in enumerate(self.lines):
            vals = [h[i] for h in self.core.history_D]
            line.set_data(steps, vals)
        self.ax[0].relim()
        self.ax[0].autoscale_view()
        
        # Update omega
        self.omega_line.set_data(steps, list(self.core.history_omega))
        self.ax[1].relim()
        self.ax[1].autoscale_view()
        
        # Update bars
        for bar, h in zip(self.bars, self.core.D):
            bar.set_height(h)
        
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()


# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Unified Hypervisor REPL (MODIFIED for VM operations)
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

class HDGL_Hypervisor:
    """Unified lattice hypervisor with VM provisioning"""
    
    def __init__(self):
        # The Hypervisor now manages the VMManager
        self.vm_manager = VMManager()
        self.hw = HardwareLayer()
        self.viz: Optional[LatticeViz] = None
        
        print("HDGL Hypervisor initialized. Use 'provision <name>' to start.")
        
    def _get_active_vm_core(self) -> Optional[LatticeCore]:
        """Helper to get the core of the active VM"""
        vm = self.vm_manager.get_active_vm()
        if vm:
            return vm.core
        print("Error: No VM is currently active. Use 'list' and 'select <id/name>'.")
        return None

    def run(self):
        # ... (Main REPL loop remains the same)
        print("\n" + "="*60)
        print("HDGL Hypervisor - Unified Lattice System")
        print("="*60)
        print("Type 'help' for commands\n")
        
        while True:
            try:
                vm = self.vm_manager.get_active_vm()
                prompt = f"hdgl[{vm.name}]>" if vm else "hdgl[HOST]>"
                cmd = input(prompt).strip()
                
                if not cmd: continue
                if self._exec(cmd.split()) == 'EXIT': break
                    
            except KeyboardInterrupt:
                print("\nUse 'exit' to quit")
            except Exception as e:
                print(f"Error: {e}")
    
    def _exec(self, args: List[str]) -> Optional[str]:
        op = args[0].lower()
        core = self._get_active_vm_core() # Get active core for lattice ops
        vm = self.vm_manager.get_active_vm()
        
        if op in ['exit', 'quit']: return 'EXIT'
        
        elif op == 'help':
            print("""
--- VM MANAGEMENT ---
 list                 - List all provisioned VMs
 provision <name>     - Create and start managing a new VM
 select <id/name>     - Set active VM for lattice operations
 destroy <id/name>    - Remove a VM
--- LATTICE OPS (Active VM) ---
 step [n]             - Evolve active VM lattice n steps
 reset | state        - Control/show active VM state
 set Dn val | omega val - Set slot/omega on active VM
 boot | bootmenu      - Boot the active VM kernel
 run <code...>        - Run binary code on active VM
--- HOST/HW OPS ---
 hwdetect | hwmap     - Check host hardware / map to active VM lattice
 viz                  - Toggle/update visualization for active VM
""")
        
        # --- VM Management Commands ---
        elif op == 'list':
            self.vm_manager.list_vms()
        
        elif op == 'provision' and len(args) == 2:
            self.vm_manager.provision(args[1])
        
        elif op == 'select' and len(args) == 2:
            target_vm = self.vm_manager.get_vm(args[1])
            if target_vm:
                self.vm_manager.active_vm_id = target_vm.id
                if self.viz: self.viz.set_core(target_vm.core)
                print(f"Switched active VM to '{target_vm.name}' (ID: {target_vm.id})")
            else:
                print(f"VM '{args[1]}' not found.")
        
        elif op == 'destroy' and len(args) == 2:
            self.vm_manager.destroy(args[1])

        # --- Lattice Operations (Require Active VM) ---
        elif core is None:
            print(f"Command '{op}' requires an active VM. Use 'select <id/name>'.")

        elif op == 'step':
            n = int(args[1]) if len(args) > 1 else 1
            vm.step_vm(n)
            print(f"→ {n} cycles. State: {core.to_hex()}")
            if self.viz: self.viz.update()
        
        elif op == 'reset':
            core.reset()
            vm.status = "OFF"
            print("Lattice reset. VM is OFF.")
        
        elif op == 'state':
            self._show_state(vm)
        
        elif op == 'set' and len(args) >= 3:
            slot = int(args[1][1:]) - 1
            val = float(args[2])
            core.D[slot] = val
            print(f"D{slot+1} = {val}")
        
        elif op == 'omega' and len(args) >= 2:
            core.omega = float(args[1])
            print(f"Ω = {core.omega}")
        
        elif op == 'hwmap':
            self.hw.map_to_lattice(core)
            print(f"Host Hardware mapped to VM '{vm.name}'")
            self._show_state(vm)

        elif op == 'bootmenu':
            vm.boot.show_menu()
        
        elif op == 'boot':
            vm.boot.show_menu()
            idx = int(input("Select: ")) - 1
            vm.boot_vm(idx)
            if self.viz: self.viz.set_core(vm.core)

        elif op == 'run' and len(args) >= 2:
            code = ' '.join(args[1:])
            vm.run_program(code)
            self._show_state(vm)

        # --- Host/Visualization Commands ---
        elif op == 'hwdetect':
            hw = self.hw.detect()
            print(json.dumps(hw, indent=2))
        
        elif op == 'viz':
            if core:
                if self.viz is None:
                    self.viz = LatticeViz(core)
                    print(f"Visualization enabled for '{vm.name}'")
                else:
                    self.viz.set_core(core)
                    self.viz.update()
            else:
                 print("Cannot initialize visualization. No active VM.")

        else:
            print(f"Unknown: {op}")
        
        return None
    
    def _show_state(self, vm: HDGL_VM):
        core = vm.core
        print(f"\nVM: {vm.name} | Status: {vm.status} | Cycle {core.cycles} | Ω={core.omega:.5f}")
        print(f"Binary: {core.to_binary()}")
        print(f"Hex:    {core.to_hex()}")
        print("\nStrands:")
        for s in STRANDS:
            vals = core.get_strand(s)
            idx = STRANDS.index(s)
            print(f"  {s} (D{idx*4+1}-D{idx*4+4}): {' '.join(f'{v:.4f}' for v in vals)}")
        print()

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Entry Point
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

if __name__ == "__main__":
    hypervisor = HDGL_Hypervisor()
    hypervisor.run()