use std::collections::{HashMap, VecDeque};
use std::env;
use std::fs;
use std::io::{self, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::{Arc, Mutex, OnceLock};
use std::thread;
use std::time::Duration;

use rand::Rng;

type Vars = HashMap<String, i64>;

#[derive(Clone, Debug, Default)]
struct ClassDef {
    fields: Vec<(String, String)>,
    methods: HashMap<String, MethodDef>,
    parent: Option<String>,
    static_fields: HashMap<String, String>,
    static_methods: HashMap<String, MethodDef>,
}

#[derive(Clone, Debug, Default)]
struct MethodDef {
    params: Vec<String>,
    body: Vec<String>,
}

#[derive(Clone, Debug)]
struct Instance {
    class_name: String,
    fields: HashMap<String, String>,
}

#[derive(Default)]
struct VirtualBundle {
    files: HashMap<String, String>,
}

#[derive(Default)]
struct RepeatDef {
    count: i64,
    counter_var: Option<String>,
    body: Vec<String>,
    depth: usize,
}

#[derive(Default)]
struct IfDef {
    condition: bool,
    then_body: Vec<String>,
    else_body: Vec<String>,
    in_else: bool,
    depth: usize,
}

#[derive(Default, Clone)]
struct FuncDef {
    params: Vec<String>,
    body: Vec<String>,
}

#[derive(Default)]
struct WhileDef {
    condition: String,
    body: Vec<String>,
    depth: usize,
}

#[derive(Default)]
struct OopState {
    classes: HashMap<String, ClassDef>,
    instances: HashMap<String, Instance>,
    string_vars: HashMap<String, String>,
    loaded_libs: HashMap<String, libloading::Library>,
    functions: HashMap<String, FuncDef>,
    current_class: Option<String>,
    current_method: Option<String>,
    current_func: Option<String>,
    self_stack: Vec<String>,
    script_dir_stack: Vec<PathBuf>,
    bundle_stack: Vec<VirtualBundle>,
    top_script_path: Option<PathBuf>,
    repeat_stack: Vec<RepeatDef>,
    if_stack: Vec<IfDef>,
    while_stack: Vec<WhileDef>,
    break_flag: bool,
    continue_flag: bool,
    return_flag: bool,
    return_value: Option<String>,
    method_static_flag: bool,
    request_context_stack: Vec<HashMap<String, String>>,
    method_owner_stack: Vec<String>,
    lists: HashMap<String, Vec<String>>,
    dicts: HashMap<String, HashMap<String, String>>,
    modules: HashMap<String, String>,
    current_module: Option<String>,
    interfaces: HashMap<String, Vec<String>>,
    current_interface: Option<String>,
    foreach_stack: Vec<ForeachDef>,
    switch_stack: Vec<SwitchDef>,
    try_stack: Vec<TryDef>,
    error_message: Option<String>,
    current_line_no: u32,
    current_file: Option<String>,
    call_trace: Vec<String>,
    warnings_enabled: bool,
    db_connections: HashMap<String, rusqlite::Connection>,
    log_file: Option<String>,
}

#[derive(Default)]
struct ForeachDef {
    var: String,
    list_name: String,
    body: Vec<String>,
    depth: usize,
}

#[derive(Default)]
struct SwitchDef {
    value: String,
    matched: bool,
    in_case: bool,
    current_body: Vec<String>,
    matched_body: Vec<String>,
    in_default: bool,
    has_matched_ever: bool,
    depth: usize,
}

#[derive(Default)]
struct TryDef {
    try_body: Vec<String>,
    catch_body: Vec<String>,
    err_var: String,
    in_catch: bool,
    depth: usize,
}

#[derive(Clone, Debug)]
enum RouteKind {
    Text,
    Json,
    Redirect,
}

#[derive(Clone, Debug)]
struct RouteResponse {
    kind: RouteKind,
    status_code: u16,
    body: Vec<u8>,
    content_type: Option<String>,
    location: Option<String>,
}

impl RouteResponse {
    fn text(body: String) -> Self {
        Self {
            kind: RouteKind::Text,
            status_code: 200,
            body: body.into_bytes(),
            content_type: Some("text/html; charset=utf-8".into()),
            location: None,
        }
    }

    fn json(body: String) -> Self {
        Self {
            kind: RouteKind::Json,
            status_code: 200,
            body: body.into_bytes(),
            content_type: Some("application/json; charset=utf-8".into()),
            location: None,
        }
    }

    fn redirect(to: String) -> Self {
        Self {
            kind: RouteKind::Redirect,
            status_code: 302,
            body: Vec::new(),
            content_type: None,
            location: Some(to),
        }
    }
}

#[derive(Clone, Debug)]
struct DynamicRoute {
    pattern_segments: Vec<String>,
    body: Vec<String>,
}

#[derive(Clone, Debug)]
struct ServerConfig {
    port: u16,
    default_body: Vec<u8>,
    default_content_type: String,
    static_dir: Option<PathBuf>,
    routes: HashMap<(String, String), RouteResponse>,
    dynamic_routes: Vec<((String, String), DynamicRoute)>,
    current_route: Option<(String, String)>,
    capturing_route_body: Option<Vec<String>>,
}

// Platform-appropriate location for installed packages — mirrors aspkg.rs.
//   Windows: %APPDATA%\aspkg\packages
//   macOS:   ~/Library/Application Support/aspkg/packages
//   Linux:   $XDG_CONFIG_HOME/aspkg/packages or ~/.config/aspkg/packages
fn package_dir() -> PathBuf {
    #[cfg(windows)]
    {
        if let Ok(p) = env::var("APPDATA") {
            return PathBuf::from(p).join("aspkg").join("packages");
        }
    }
    let home = env::var("HOME")
        .or_else(|_| env::var("USERPROFILE"))
        .unwrap_or_else(|_| ".".to_string());
    #[cfg(target_os = "macos")]
    {
        return Path::new(&home)
            .join("Library").join("Application Support")
            .join("aspkg").join("packages");
    }
    if let Ok(xdg) = env::var("XDG_CONFIG_HOME") {
        return PathBuf::from(xdg).join("aspkg").join("packages");
    }
    Path::new(&home).join(".config").join("aspkg").join("packages")
}

fn ensure_dirs() {
    fs::create_dir_all(package_dir()).expect("Failed to create aspkg directory");
}

fn sanitize_path(url_path: &str) -> Option<String> {
    let trimmed = url_path.trim();
    if !trimmed.starts_with('/') {
        return None;
    }
    if trimmed.contains("..") {
        return None;
    }
    Some(trimmed.trim_start_matches('/').to_string())
}

fn guess_mime(path: &Path) -> String {
    let ext = path
        .extension()
        .and_then(|e| e.to_str())
        .unwrap_or("")
        .to_lowercase();

    match ext.as_str() {
        "html" | "htm" => "text/html; charset=utf-8",
        "css" => "text/css; charset=utf-8",
        "js" => "application/javascript; charset=utf-8",
        "json" => "application/json; charset=utf-8",
        "txt" => "text/plain; charset=utf-8",
        "png" => "image/png",
        "jpg" | "jpeg" => "image/jpeg",
        "gif" => "image/gif",
        "svg" => "image/svg+xml",
        "ico" => "image/x-icon",
        "webp" => "image/webp",
        "woff" => "font/woff",
        "woff2" => "font/woff2",
        "ttf" => "font/ttf",
        _ => "application/octet-stream",
    }
    .to_string()
}

#[derive(Default)]
struct ParsedRequest {
    method: String,
    path: String,
    query: HashMap<String, String>,
    headers: HashMap<String, String>,
    body: String,
}

fn url_decode(s: &str) -> String {
    let mut out = String::with_capacity(s.len());
    let mut iter = s.bytes();
    while let Some(b) = iter.next() {
        match b {
            b'+' => out.push(' '),
            b'%' => {
                let h1 = iter.next();
                let h2 = iter.next();
                if let (Some(a), Some(b)) = (h1, h2) {
                    if let Ok(n) = u8::from_str_radix(
                        std::str::from_utf8(&[a, b]).unwrap_or("00"),
                        16,
                    ) {
                        out.push(n as char);
                    }
                }
            }
            c => out.push(c as char),
        }
    }
    out
}

fn parse_query(qs: &str) -> HashMap<String, String> {
    let mut out = HashMap::new();
    for pair in qs.split('&') {
        if pair.is_empty() {
            continue;
        }
        let mut kv = pair.splitn(2, '=');
        let k = url_decode(kv.next().unwrap_or(""));
        let v = url_decode(kv.next().unwrap_or(""));
        out.insert(k, v);
    }
    out
}

fn read_http_request(stream: &TcpStream) -> Option<ParsedRequest> {
    let mut buffer = [0u8; 8192];
    let peeked = stream.peek(&mut buffer).ok()?;
    if peeked == 0 {
        return None;
    }

    let mut full = Vec::new();
    let _ = stream.set_read_timeout(Some(Duration::from_millis(250)));

    let mut content_length: usize = 0;
    let mut header_end: Option<usize> = None;

    loop {
        let mut chunk = [0u8; 2048];
        match (&mut &*stream).read(&mut chunk) {
            Ok(0) => break,
            Ok(n) => {
                full.extend_from_slice(&chunk[..n]);

                if header_end.is_none() {
                    if let Some(pos) = full
                        .windows(4)
                        .position(|w| w == b"\r\n\r\n")
                    {
                        header_end = Some(pos + 4);
                        let header_text = String::from_utf8_lossy(&full[..pos]);
                        for hline in header_text.split("\r\n") {
                            if let Some(idx) = hline.find(':') {
                                let k = hline[..idx].trim().to_lowercase();
                                if k == "content-length" {
                                    content_length =
                                        hline[idx + 1..].trim().parse().unwrap_or(0);
                                }
                            }
                        }
                    }
                }

                if let Some(he) = header_end {
                    if full.len() >= he + content_length {
                        break;
                    }
                }

                if full.len() > 64 * 1024 {
                    break;
                }
            }
            Err(_) => break,
        }
    }

    let request = String::from_utf8_lossy(&full).to_string();
    let mut lines = request.split("\r\n");
    let first_line = lines.next()?.trim().to_string();

    let mut parts = first_line.split_whitespace();
    let method = parts.next()?.to_string();
    let raw_path = parts.next()?.to_string();

    let (path, qs) = match raw_path.find('?') {
        Some(idx) => (
            raw_path[..idx].to_string(),
            raw_path[idx + 1..].to_string(),
        ),
        None => (raw_path, String::new()),
    };
    let query = parse_query(&qs);

    let mut headers = HashMap::new();
    for line in lines.by_ref() {
        if line.is_empty() {
            break;
        }
        if let Some(idx) = line.find(':') {
            let k = line[..idx].trim().to_lowercase();
            let v = line[idx + 1..].trim().to_string();
            headers.insert(k, v);
        }
    }

    let body_start = request.find("\r\n\r\n").map(|i| i + 4).unwrap_or(request.len());
    let body = if body_start < request.len() {
        request[body_start..].to_string()
    } else {
        String::new()
    };

    Some(ParsedRequest {
        method,
        path,
        query,
        headers,
        body,
    })
}

fn match_dynamic_route<'a>(
    method: &str,
    path: &str,
    routes: &'a [((String, String), DynamicRoute)],
) -> Option<(&'a DynamicRoute, HashMap<String, String>)> {
    let path_segments: Vec<&str> = path
        .trim_start_matches('/')
        .split('/')
        .collect();

    for ((m, _), r) in routes {
        if m != method {
            continue;
        }
        if r.pattern_segments.len() != path_segments.len() {
            continue;
        }
        let mut params = HashMap::new();
        let mut matched = true;
        for (pat, actual) in r.pattern_segments.iter().zip(path_segments.iter()) {
            if let Some(name) = pat.strip_prefix(':') {
                params.insert(name.to_string(), (*actual).to_string());
            } else if pat != actual {
                matched = false;
                break;
            }
        }
        if matched {
            return Some((r, params));
        }
    }
    None
}

fn write_http_response(
    mut stream: TcpStream,
    status_code: u16,
    headers: Vec<(String, String)>,
    body: &[u8],
) {
    let status_text = match status_code {
        200 => "OK",
        301 => "Moved Permanently",
        302 => "Found",
        400 => "Bad Request",
        404 => "Not Found",
        405 => "Method Not Allowed",
        500 => "Internal Server Error",
        _ => "OK",
    };

    let mut header_text = String::new();
    header_text.push_str(&format!("HTTP/1.1 {} {}\r\n", status_code, status_text));
    header_text.push_str(&format!("Content-Length: {}\r\n", body.len()));
    header_text.push_str("Connection: close\r\n");

    for (k, v) in headers {
        header_text.push_str(&format!("{}: {}\r\n", k, v));
    }

    header_text.push_str("\r\n");

    let _ = stream.write_all(header_text.as_bytes());
    let _ = stream.write_all(body);
}

fn try_static_or_static_routes(
    stream: TcpStream,
    cfg: &ServerConfig,
    req: &ParsedRequest,
) -> Result<(), TcpStream> {
    if let Some(static_dir) = &cfg.static_dir {
        if let Some(rel) = sanitize_path(&req.path) {
            let mut file_path = static_dir.join(&rel);

            if req.path == "/" {
                file_path = static_dir.join("index.html");
            }

            if file_path.exists() && file_path.is_file() {
                match fs::read(&file_path) {
                    Ok(bytes) => {
                        let mime = guess_mime(&file_path);
                        write_http_response(
                            stream,
                            200,
                            vec![("Content-Type".into(), mime)],
                            &bytes,
                        );
                        return Ok(());
                    }
                    Err(_) => {
                        write_http_response(
                            stream,
                            500,
                            vec![("Content-Type".into(), "text/plain; charset=utf-8".into())],
                            b"Static file read failed",
                        );
                        return Ok(());
                    }
                }
            }
        }
    }

    let key = (req.method.clone(), req.path.clone());
    if let Some(route_resp) = cfg.routes.get(&key) {
        match route_resp.kind {
            RouteKind::Redirect => {
                let location = route_resp.location.clone().unwrap_or_else(|| "/".into());
                write_http_response(
                    stream,
                    route_resp.status_code,
                    vec![("Location".into(), location)],
                    &route_resp.body,
                );
                return Ok(());
            }
            _ => {
                let ct = route_resp
                    .content_type
                    .clone()
                    .unwrap_or_else(|| "text/html; charset=utf-8".into());
                write_http_response(
                    stream,
                    route_resp.status_code,
                    vec![("Content-Type".into(), ct)],
                    &route_resp.body,
                );
                return Ok(());
            }
        }
    }

    Err(stream)
}

fn finish_request_404_or_default(stream: TcpStream, cfg: &ServerConfig) {
    if !cfg.default_body.is_empty() {
        write_http_response(
            stream,
            200,
            vec![("Content-Type".into(), cfg.default_content_type.clone())],
            &cfg.default_body,
        );
        return;
    }

    write_http_response(
        stream,
        404,
        vec![("Content-Type".into(), "text/plain; charset=utf-8".into())],
        b"404 Not Found",
    );
}

fn run_server_blocking(
    cfg: ServerConfig,
    vars: &mut Vars,
    oop: &mut OopState,
) {
    let bind_addr = format!("0.0.0.0:{}", cfg.port);
    let listener = TcpListener::bind(&bind_addr).expect("Failed to bind server");
    listener
        .set_nonblocking(true)
        .expect("Failed to set nonblocking");

    println!();
    println!("AyaanScriptPlus server running:");
    println!("  -> http://127.0.0.1:{}", cfg.port);
    println!("  -> http://localhost:{}", cfg.port);
    println!();
    println!(
        "Static dir: {}",
        cfg.static_dir
            .as_ref()
            .map(|p| p.display().to_string())
            .unwrap_or_else(|| "OFF".into())
    );
    println!(
        "Routes: {} static + {} dynamic",
        cfg.routes.len(),
        cfg.dynamic_routes.len()
    );
    println!("Press Ctrl-C to stop.");
    println!();

    loop {
        match listener.accept() {
            Ok((stream, _)) => {
                let req = match read_http_request(&stream) {
                    Some(r) => r,
                    None => continue,
                };

                match try_static_or_static_routes(stream, &cfg, &req) {
                    Ok(()) => continue,
                    Err(stream) => {
                        if let Some((route, params)) = match_dynamic_route(
                            &req.method,
                            &req.path,
                            &cfg.dynamic_routes,
                        ) {
                            let mut req_ctx: HashMap<String, String> = HashMap::new();
                            req_ctx.insert("req.method".into(), req.method.clone());
                            req_ctx.insert("req.path".into(), req.path.clone());
                            req_ctx.insert("req.body".into(), req.body.clone());
                            for (k, v) in &req.query {
                                req_ctx.insert(format!("req.query.{}", k), v.clone());
                            }
                            for (k, v) in &req.headers {
                                req_ctx.insert(format!("req.header.{}", k), v.clone());
                            }
                            for (k, v) in &params {
                                req_ctx.insert(format!("req.params.{}", k), v.clone());
                            }

                            oop.request_context_stack.push(req_ctx);
                            let prev_response: Option<(u16, String, Vec<(String, String)>)> =
                                oop.string_vars
                                    .get("__response_body__")
                                    .map(|b| (200, b.clone(), Vec::new()));
                            oop.string_vars.insert("__response_body__".into(), String::new());
                            oop.string_vars.insert("__response_status__".into(), "200".into());
                            oop.string_vars.insert("__response_ctype__".into(), "text/html; charset=utf-8".into());

                            let mut server_cfg_local: Option<ServerConfig> = None;
                            for line in &route.body {
                                if !execute(line, vars, &mut server_cfg_local, oop) {
                                    break;
                                }
                            }

                            let status: u16 = oop
                                .string_vars
                                .get("__response_status__")
                                .and_then(|s| s.parse().ok())
                                .unwrap_or(200);
                            let body = oop
                                .string_vars
                                .get("__response_body__")
                                .cloned()
                                .unwrap_or_default();
                            let ctype = oop
                                .string_vars
                                .get("__response_ctype__")
                                .cloned()
                                .unwrap_or_else(|| "text/html; charset=utf-8".into());

                            oop.request_context_stack.pop();
                            if let Some((_, prev, _)) = prev_response {
                                oop.string_vars.insert("__response_body__".into(), prev);
                            } else {
                                oop.string_vars.remove("__response_body__");
                            }
                            oop.string_vars.remove("__response_status__");
                            oop.string_vars.remove("__response_ctype__");

                            write_http_response(
                                stream,
                                status,
                                vec![("Content-Type".into(), ctype)],
                                body.as_bytes(),
                            );
                        } else {
                            finish_request_404_or_default(stream, &cfg);
                        }
                    }
                }
            }
            Err(e) => {
                if e.kind() == io::ErrorKind::WouldBlock {
                    thread::sleep(Duration::from_millis(30));
                    continue;
                }
                thread::sleep(Duration::from_millis(50));
            }
        }
    }
}

fn expand_path(s: &str) -> PathBuf {
    let trimmed = s.trim();
    // Resolve home from HOME (Unix) or USERPROFILE (Windows)
    let home_str = env::var("HOME").or_else(|_| env::var("USERPROFILE")).ok();
    if trimmed == "~" {
        if let Some(home) = home_str {
            return PathBuf::from(home);
        }
    }
    if let Some(rest) = trimmed.strip_prefix("~/") {
        if let Some(home) = home_str {
            return PathBuf::from(home).join(rest);
        }
    }
    PathBuf::from(trimmed)
}

fn resolve_import_path(target: &str, stack: &[PathBuf]) -> PathBuf {
    let p = expand_path(target);
    if p.is_absolute() {
        return p;
    }
    if let Some(base) = stack.last() {
        return base.join(&p);
    }
    p
}

const KNOWN_COMMANDS: &[&str] = &[
    "EmperorPenguin", "about", "abs", "abs_path", "absolute",
    "abspath", "acos", "acosh", "acro", "acronym",
    "ada", "add_days", "add_one", "aeq", "agile",
    "agt", "ahh", "alpha", "alt", "alt_screen",
    "an", "ane", "animation", "apl", "append_file",
    "approx", "arch_name", "arrow_down", "arrow_down_str", "arrow_downleft",
    "arrow_downright", "arrow_left", "arrow_left_str", "arrow_right", "arrow_right_str",
    "arrow_up", "arrow_up_str", "arrow_upleft", "arrow_upright", "arrows_lr",
    "arrows_ud", "as", "ascii_0", "ascii_9", "ascii_a",
    "ascii_cr", "ascii_del", "ascii_esc", "ascii_la", "ascii_lz",
    "ascii_newline", "ascii_null", "ascii_space", "ascii_tab", "ascii_z",
    "asin", "asinh", "askstring", "askyesno", "aspf",
    "assert", "assert_eq", "assert_gt", "assert_lt", "assert_ne",
    "atan", "atan2", "atanh", "atbash", "av",
    "average", "avg", "aw_nuts", "aw_yeah", "awkward",
    "aww", "ayaan_man", "ayaaniscool", "ayaanrules", "b2gb",
    "b2kb", "b2mb", "b64d", "b64e", "b_off",
    "b_on", "backup_file", "band", "banner", "banner_print",
    "barchart", "base64", "base64_decode", "base64_encode", "base_name",
    "basename", "bc", "bcount", "because", "beep",
    "beginroute", "bench", "benchmark", "beta", "bg_black",
    "bg_cyan", "bg_magenta", "bg_white", "bgrgb", "big",
    "biggest", "billion", "biohazard", "bit_count", "bitter",
    "bl_off", "bl_on", "bland", "blech", "blend",
    "blessing", "blink_off", "blink_on", "block_dark", "block_full",
    "block_light", "block_med", "bn", "bnot", "bnr",
    "boiling", "bold_off", "bold_on", "bor", "box",
    "box_b", "box_bl", "box_br", "box_cross", "box_draw",
    "box_h", "box_l", "box_left", "box_lower", "box_r",
    "box_right", "box_t", "box_tl", "box_tr", "box_upper",
    "box_v", "break", "bright", "bringback", "brisk",
    "brittle", "brr", "bullet", "bumpy", "burning",
    "buttery", "bx", "bxor", "byte_count", "bytes_to_gb",
    "bytes_to_kb", "bytes_to_mb", "c2f", "c2k", "c_black",
    "c_blink", "c_blue", "c_bold", "c_bright_black", "c_bright_blue",
    "c_bright_cyan", "c_bright_green", "c_bright_magenta", "c_bright_red", "c_bright_white",
    "c_bright_yellow", "c_cyan", "c_default", "c_dim", "c_est_la_vie",
    "c_green", "c_hidden", "c_invert", "c_italic", "c_magenta",
    "c_red", "c_reset", "c_strike", "c_to_f", "c_to_k",
    "c_underline", "c_white", "c_yellow", "ca", "caesar_decode",
    "caesar_encode", "calc", "call", "camel_to_snake", "cap",
    "capitalize", "capitalize_str", "cat2", "catch", "cb",
    "cbrt", "ccount", "ceil", "ceiling", "center",
    "ch", "ch1", "ch2", "char_at", "char_count",
    "chars", "check_mark", "chewy", "chi", "chickenwins",
    "chilly", "chomp", "choose", "chop", "chr",
    "chs", "circle_filled", "circle_outline", "cl", "clamp",
    "clamp_int", "class", "clear", "clear_below", "clear_line",
    "clear_to_eol", "clr", "clrb", "clrl", "cls",
    "club_card", "clumsy", "cm2in", "cm_per_m", "cm_to_in",
    "cmd_count", "cmds", "cnst", "coffee", "coin",
    "cold", "collapse_spaces", "collatz_length", "color", "color_blue",
    "color_green", "color_off", "color_red", "color_yellow", "colossal",
    "commands", "compliment", "concat", "conscount", "consonant_count",
    "const", "const_e", "const_inf", "const_ln10", "const_ln2",
    "const_log10e", "const_log2e", "const_max_i64", "const_max_u16", "const_max_u32",
    "const_max_u8", "const_min_i64", "const_min_u16", "const_min_u32", "const_min_u8",
    "const_nan", "const_neg_inf", "const_pi", "const_sqrt2", "const_tau",
    "contains", "contains_all", "contains_any", "continents", "continue",
    "cool_temp", "copy", "copy_files", "copy_var", "copyright",
    "cos", "cosh", "count", "count_lines_matching", "count_occurrences",
    "count_substr", "count_words", "countdown", "countup", "cp_v",
    "cpf", "cramped", "crc32", "creamy", "credits",
    "crispy", "cross_mark", "crunchy", "csp", "ctr",
    "ctype", "cube", "cubed", "current_time", "d20",
    "d2h", "d6", "dagger", "damp", "dang",
    "dark", "darn", "date_add", "date_diff", "date_format",
    "date_today", "date_tomorrow", "date_yesterday", "datefmt", "day",
    "dayname", "dayofyear", "days_in_month", "days_in_year", "days_per_leap_year",
    "days_per_week", "days_per_year", "days_to_hr", "db", "db_begin",
    "db_close", "db_commit", "db_count", "db_exec", "db_exists",
    "db_insert", "db_open", "db_query", "db_rollback", "db_tables",
    "dbb", "dbc", "dbcl", "dbcm", "dbe",
    "dbl", "dbo", "dbox_bl", "dbox_br", "dbox_h",
    "dbox_tl", "dbox_tr", "dbox_v", "dbq", "dbrb",
    "dbt", "dclear", "dcount", "dcount_value", "dcv",
    "dd", "dda", "ddel", "deafening", "debug",
    "debug_msg", "dec", "decode_b64", "decr", "default",
    "defeat", "deg_to_rad", "degree", "del_v", "delay",
    "delete", "delta", "despair", "dget", "dhas",
    "diamond_card", "diamond_filled", "diamond_outline", "dict", "dict_del",
    "dict_get", "dict_has", "dict_keys", "dict_merge", "dict_set",
    "dict_size", "dict_values", "diff_days", "digit_count", "digit_product",
    "digit_root", "digit_sum", "dim", "dim_adj", "dimensions_3d",
    "dincr", "ding_ding", "dinvert", "dir_exists", "dir_name",
    "dirname", "display", "dist", "distance", "divide_sign",
    "divider", "divisor_count", "divisor_sum", "diy", "dkeys",
    "dl", "dmerge", "dmg", "dn", "dn_a",
    "docs", "doi", "domit", "double", "double_arrow_left",
    "double_arrow_right", "double_check", "doubledagger", "download", "download_url",
    "dpairs", "dpi", "dpick", "dpop", "dprint",
    "dq", "draw_progress", "dry", "dset", "dsize",
    "dsize2", "dull_adj", "dump", "durable", "dv",
    "dv2", "dvalues", "dx", "dx20", "dx6",
    "e", "eastereggs", "echo", "eek", "eight",
    "eleven", "ellipsis", "else", "emdash", "emit",
    "encode_b64", "end", "endash", "endclass", "endforeach",
    "endfunc", "endif", "endinterface", "endmethod", "endmodule",
    "endrepeat", "endroute", "ends", "endswitch", "endswith",
    "endtry", "endwhile", "enormous", "ensure_dir", "enum",
    "env_dict", "env_list", "env_size", "envelope_alt", "epoch",
    "epsilon", "error", "es", "escape_quotes", "eta",
    "ewww", "ex", "examples", "exec", "exists",
    "exit", "exp", "exp2", "ext_name", "extname",
    "f2c", "f2k", "f_to_c", "f_to_k", "factorial",
    "fast", "fcid", "feet_per_mile", "feet_per_yard", "ffi",
    "fficall", "ffiload", "fib", "fibonacci", "field",
    "file_age", "file_check", "file_count_in_dir", "file_empty", "file_ext",
    "file_grep", "file_hash", "file_head", "file_lines_count", "file_mtime",
    "file_replace", "file_size", "file_stem", "file_tail", "file_words_count",
    "file_writable", "find_files", "find_index", "first", "first_ch",
    "first_letter", "first_word", "five", "flat", "flc",
    "flip", "flip2", "flip_coin", "floor", "flower_alt",
    "floz_to_ml", "fluffy_adj", "fmax", "fmin", "foreach",
    "form_encode", "format", "format_bytes", "format_duration", "format_number",
    "fortune", "four", "fragile_adj", "freezing", "from_bin",
    "from_hex", "from_unix", "frosty", "frowny", "frst",
    "fsz", "ft2m", "ft_to_m", "fu", "func",
    "fw", "fw2", "fwc", "g2oz", "g_to_oz",
    "gal2l", "gal_to_l", "gamma", "gb2tb", "gb_size",
    "gb_to_tb", "gcd", "gcd3", "gen_id", "gen_uuid",
    "get", "get_env", "getenv", "getf", "gethome",
    "getuser", "gib", "gigantic", "gloomy", "glowing",
    "gooey", "gotoxy", "graceful", "grams_per_kg", "greater",
    "greater_equal", "gv", "h2d", "h2m", "h2s",
    "hack", "half", "hamming_distance", "hard", "has",
    "has_v", "has_var", "hash_md5", "hash_sha256", "hdel",
    "he", "heart_filled", "heart_outline", "heavy", "hello1",
    "hello10", "hello2", "hello3", "hello4", "hello5",
    "hello6", "hello7", "hello8", "hello9", "hello_ayaan",
    "help", "hex_decode", "hex_encode", "hf", "hg",
    "hi_low", "hi_max", "hide", "hide_cursor", "hm5",
    "hmac_sha256", "hn", "honk_honk", "hope", "hostname",
    "hot", "hour_now", "hours_per_day", "hp", "hput",
    "hr", "hr2", "hr_to_days", "hr_to_min", "hr_to_sec",
    "hs1", "hs2", "hs5", "html_escape", "http_delete",
    "http_fetch", "http_get", "http_post", "http_put", "http_send",
    "huge", "hundred", "hv", "hxd", "hxe",
    "hypot", "i2ip", "i_off", "i_on", "iay",
    "if", "immense", "implements", "import", "importayaan", "importpkg", "tempdir", "tempfile",
    "clone", "classname", "is_subclass", "field_names", "method_names", "call_method", "has_method", "parent_of",
    "in2cm", "in_str", "in_to_cm", "inc", "inches_per_foot",
    "incr", "infinity", "info", "init2", "initials",
    "ins", "inspect", "instanceof", "insult", "int_to_ip",
    "integral", "interface", "inv", "inv_off", "inv_on",
    "inverse_percent", "invert", "invert_off", "invert_on", "iota",
    "ip2i", "ip_to_int", "ip_v4_check", "ipct", "ipk",
    "ipv4_max_octet", "ir", "is_alnum", "is_alpha", "is_anagram",
    "is_ascii", "is_digit", "is_dir", "is_even", "is_file",
    "is_leap_year", "is_lower", "is_odd", "is_palindrome", "is_perfect",
    "is_power_of_2", "is_prime", "is_root", "is_today", "is_upper",
    "is_weekend", "is_whitespace", "isd", "isf", "isipv4",
    "italic_off", "italic_on", "itty_bitty", "ity", "jaccard",
    "jerky", "jesc", "join", "join_path", "joinpath",
    "joke", "jp", "jp2", "jpp", "jpr",
    "jscall", "json", "json_escape_str", "json_get_path", "json_parse",
    "json_pretty", "json_stringify", "jstr", "k2c", "k2f",
    "k_to_c", "k_to_f", "ka_pow", "kappa", "kb2mb",
    "kb_size", "kb_to_mb", "kebab_to_camel", "kebab_to_snake", "kg2lb",
    "kg_to_lb", "kib", "kind", "km2mi", "km_to_mi",
    "kmh2kts", "kmh2mph", "kmh_to_knots", "kmh_to_mph", "knots_to_kmh",
    "konami", "ks", "kts2kmh", "kyn", "l2gal",
    "l_a", "l_to_gal", "lall_neg", "lall_pos", "lall_zero",
    "lambda", "lang_env", "lany_pos", "lany_zero", "last",
    "last_ch", "last_letter", "last_word", "lavg", "lb2kg",
    "lb_per_ton", "lb_to_kg", "lchoice", "lclear", "lcm",
    "lcompact", "lconcat", "lcontains", "lcopy", "lcount",
    "lcount2", "lcount_eq", "lcount_neg", "lcount_pos", "lcount_zero",
    "lcp", "ld", "ldiff_lists", "ldrop", "le",
    "leading_zeros", "left", "len", "length", "lerp",
    "less_equal", "letter_freq", "levenshtein", "lextend", "lf",
    "lfill", "lft", "lg", "lget", "li",
    "license", "light_adj", "light_weight", "lindex", "line_count",
    "linit", "linsert", "lis_sorted", "lis_unique", "list",
    "list_dir", "list_get", "list_pop", "list_push", "list_set",
    "list_size", "listdir", "ljoin", "ll", "lmax",
    "lmedian", "lmin", "ln", "lo", "load_env",
    "loadenv", "loading", "local_ip", "log", "log10",
    "log2", "log_base", "log_debug", "log_error", "log_info",
    "log_warn", "logfile", "lones", "long", "longest_common",
    "loud", "lower", "lowercase_count", "lowercase_str", "lpad",
    "lpop_front", "lprepend", "lprint", "lproduct", "lremove",
    "lremove_at", "lreplace_all", "lreverse", "lreverse_copy", "lscan",
    "lset", "lshuffle", "lsize", "lsort", "lst",
    "lstddev", "lsum", "lswap", "ltail", "ltake",
    "luminous", "lunique", "lv", "lvariance", "lw",
    "lwindow", "lzeros", "m2ft", "m2h", "m2s",
    "m_per_km", "m_to_ft", "mac_format", "magic_8_ball", "magnitude",
    "make_dir", "man", "manhattan", "map_range", "massive",
    "matrix", "max", "max_byte", "max_signed_byte", "max_signed_dword",
    "max_signed_word", "max_var", "max_word", "maxv", "mb2gb",
    "mb_size", "mb_to_gb", "md", "md5", "md5_hash",
    "median", "meh_meh", "method", "mi2km", "mi_to_km",
    "mib", "micro", "microscopic", "midnight_today", "million",
    "min", "min_byte", "min_signed_byte", "min_signed_dword", "min_signed_word",
    "min_to_hr", "min_to_sec", "min_var", "min_word", "minus",
    "minus1", "minute_now", "minutes_per_hour", "minv", "mkdir",
    "ml2oz", "ml_per_gal", "ml_per_l", "ml_to_floz", "mn",
    "mod_pow", "module", "modulo", "monstrous", "month",
    "monthname", "months_per_year", "move", "move_files", "mph2kmh",
    "mph_to_kmh", "ms_sleep", "mt", "mu", "muffled",
    "multiply_sign", "murky", "mushy", "music_note", "music_notes",
    "mvf", "mx", "nabla", "narrow", "nck",
    "neg", "negate", "new", "next_power_of_2", "nimble",
    "nine", "nmd", "noisy", "noop", "nop",
    "normal_screen", "normalize", "normalize_path", "normalize_ws", "not_equal",
    "note", "now", "now_iso", "now_minus_days", "now_plus_days",
    "now_time", "npd", "npk", "nproc", "nth_prime",
    "nth_root", "nth_word", "nu", "num_digits", "nw",
    "nws", "oa", "oceans", "od", "of",
    "oh_no", "oh_well", "oh_yeah", "ohh", "ol",
    "omega", "omicron", "on2", "one", "only_alnum",
    "only_digits", "only_letters", "oof_loud", "opaque", "ord",
    "os_family", "os_name", "ouch", "output", "ow",
    "oz2g", "oz2ml", "oz_per_lb", "oz_to_g", "p",
    "pad", "pad_left", "panic", "paragraph", "parse_query",
    "partial", "party", "path_exists", "pause", "pause_for",
    "pct", "peace_sign", "pen_alt", "pencil_alt", "percent",
    "percentile", "perms", "pf", "pg", "phew",
    "phi", "phi_letter", "phone_alt", "pi", "pi2",
    "pick", "pid", "ping", "plane_alt", "planets",
    "plat", "platform", "play", "plot_bar", "plot_spark",
    "plus", "plus1", "plusminus", "pop", "port_max",
    "port_min", "port_reserved", "post", "pow", "power",
    "pr", "primary_colors", "prime_factors", "primes_up_to", "print",
    "print_dict", "print_list", "print_var", "printf", "println",
    "product_sign", "progress", "psi", "psnake", "public_ip",
    "push", "put", "puts", "pw", "pwd",
    "pycall", "qo", "quarter_of", "quick", "quiet",
    "r_a", "rad_to_deg", "radiant", "radioactive", "raise",
    "rand_bool", "rand_digit", "rand_float", "rand_hex_char", "rand_letter",
    "rand_uppercase", "rand_uuid", "randint", "random", "random_bytes",
    "random_ipv4", "random_mac", "random_password", "random_port", "range",
    "rapid", "rats", "rb", "rc", "rd",
    "rd2", "rdf", "read_file", "read_first_line", "read_last_line",
    "read_lines", "readfile", "recip", "recycle", "redirect",
    "regex_check", "regex_match", "regex_replace", "regex_sub", "registered",
    "remove_dir", "remove_file", "remove_spaces", "rep", "rep_n",
    "repcall", "repeat", "repeat_call", "repeat_chars", "repeat_print",
    "repeat_str", "repl", "replace", "reset_color", "restore_cursor",
    "restore_screen", "retry", "return", "rev", "reverse",
    "reverse_digits", "reverse_str", "reverse_words", "rf", "rfl",
    "rgb", "rgt", "rgxm", "rgxr", "rho",
    "rhx", "rich_adj", "rickroll", "right", "rip",
    "rl", "rll", "rm", "rm2", "rmdir",
    "rms", "rndd", "rndhx", "rndlt", "rndup",
    "rng", "root", "rot13", "rough", "round",
    "round_to", "rounded", "route", "rpad", "rport",
    "rpw", "rpz", "rsp", "rst", "rty",
    "rubbery", "rw", "s2h", "s2m", "s_off",
    "s_on", "salty_adj", "sav", "save_cursor", "save_screen",
    "savory", "say", "schunk", "scissors_alt", "scorching",
    "scount", "scroll_down", "scroll_up", "seasons", "sec_to_hr",
    "sec_to_min", "second_now", "seconds_per_day", "seconds_per_hour", "seconds_per_minute",
    "seconds_per_week", "section", "selfdestruct", "selfget", "selfset",
    "send", "serve", "servefile", "set_diff", "set_env",
    "set_eq", "set_i", "set_int", "set_intersect", "set_str",
    "set_string", "set_union", "setenv", "setf", "seven",
    "sha1", "sha256", "sha256_hash", "sha512", "sharp",
    "shell_escape", "shell_name", "shesc", "shiny", "shl",
    "shoot", "short", "show", "show2", "show_cursor",
    "show_progress", "shr", "shuf", "sigma", "sign",
    "silent", "sin", "sinh", "sinorules", "six",
    "size", "sk", "skull_alt", "sl", "sleep_ms",
    "sleep_seconds", "slimy", "slines", "slippery", "sloth",
    "slow", "sluggish", "slugify", "sm", "small",
    "smaller", "smallest", "smash", "smiley", "smooth",
    "smooth_move", "sn", "sn2", "snake_to_camel", "snake_to_kebab",
    "snappy", "snowflake_alt", "soaked", "soft", "soggy",
    "solid", "sour", "sp", "space_count", "spacious",
    "spade_card", "sparkle_alt", "sparkline", "sparkling", "spawn",
    "speedy", "spicy", "spin", "splash", "split",
    "split2", "spongy", "sq", "sqrt", "sqrt2",
    "sqrt_sign", "square", "square_filled", "square_outline", "squared",
    "squishy", "star_filled", "star_outline", "starts", "startswith",
    "static", "status", "std_dev", "sticky", "str_chunk",
    "str_eq_ci", "str_is_float", "str_is_int", "str_is_numeric", "str_len",
    "str_lines", "str_pad_zero", "str_size", "strikethrough_off", "strikethrough_on",
    "string_concat", "string_contains", "string_ends_with", "string_length", "string_replace",
    "string_split", "string_starts_with", "string_trim", "strip_left", "strip_right",
    "strlen", "sturdy", "sub", "sub_one", "substr",
    "sum", "sum_sign", "sv", "sw_v", "swap_case",
    "swap_vars", "sweet", "swift", "switch", "table",
    "table_print", "taco", "tall", "tan", "tangy",
    "tanh", "tau", "tb_size", "tbl", "te",
    "tea", "teeny", "teeny_tiny", "ten", "term_name_var",
    "term_size", "test_fail", "test_pass", "test_skip", "tf",
    "th", "theanswer", "therefore", "theta", "thick",
    "thin", "third", "thousand", "three", "thump",
    "ti", "tib", "time_end", "time_start", "times",
    "timestamp_ms", "tiny", "titanic", "title", "title_case",
    "title_t", "titlebar", "tms", "tnv", "to_bin",
    "to_constant", "to_hex", "to_int", "to_oct", "to_pascal",
    "to_str", "to_unix", "today", "todo", "toggle",
    "tomorrow", "tomorrow_iso", "toot", "total", "touch",
    "tp", "tpl", "trademark", "trailing_zeros", "translucent",
    "transparent", "triangle_down", "triangle_left", "triangle_right", "triangle_up",
    "triangular", "trillion", "trim", "trim2", "triple",
    "trunc", "trunc2", "truncate", "truncated", "try",
    "ts", "tsk", "tsz", "ttl", "tu",
    "tutorial", "twelve", "two", "type", "type_of",
    "typeof", "typeof2", "u_off", "u_on", "ucount",
    "uds", "ue2", "ufs", "ugh", "uh",
    "uh_oh", "uhh", "um", "underline_off", "underline_on",
    "unescape_quotes", "unicode_max", "uniq", "unset_var", "up",
    "up2", "up_a", "upper", "uppercase", "uppercase_count",
    "uppercase_str", "upsilon", "uptime", "uq", "uq2",
    "url_escape", "url_host", "url_path", "url_query", "url_scheme",
    "us", "utf8_max_bytes", "uu", "uuid", "uv",
    "v", "var", "variance", "vast", "vcount",
    "version", "victory", "vowel_count", "vprint", "vroom",
    "wait", "waitkey", "warm", "warn", "warning_sign",
    "watchfile", "wd", "wds", "week_of_year", "weekday",
    "weeks_per_year", "welcome_msg", "wet", "wf", "wf2",
    "which", "while", "whispering", "wide", "woohoo",
    "woosh", "word_freq", "words", "woy", "write",
    "write_file", "write_lines", "writefile", "xi", "xn",
    "xy", "xyzzy", "yards_per_mile", "year", "yeehaw",
    "yes_no", "yesterday", "yesterday_iso", "yi", "yikes_alert",
    "yin_yang", "yippee", "yowl", "yowza", "yum",
    "yummy", "z", "zero", "zero_var", "zesty",
    "zeta", "zippy", "zoom_zoom",
    "TO_LOWER", "UPPER", "abort", "abs_n_v_1", "abs_n_v_10",
    "abs_n_v_11", "abs_n_v_12", "abs_n_v_13", "abs_n_v_14", "abs_n_v_15",
    "abs_n_v_2", "abs_n_v_3", "abs_n_v_4", "abs_n_v_5", "abs_n_v_6",
    "abs_n_v_7", "abs_n_v_8", "abs_n_v_9", "abs_v", "absval",
    "accumulate", "add_all_list", "add_n", "add_n_v_1", "add_n_v_10",
    "add_n_v_11", "add_n_v_12", "add_n_v_13", "add_n_v_14", "add_n_v_15",
    "add_n_v_2", "add_n_v_3", "add_n_v_4", "add_n_v_5", "add_n_v_6",
    "add_n_v_7", "add_n_v_8", "add_n_v_9", "add_to_v", "add_val",
    "addby", "addint", "addn", "addto", "addvar",
    "advance", "advance_var", "alias_var", "all_primes_to", "alloc_dict",
    "alloc_list", "alloc_v", "alloc_var", "ansi_color", "any_int",
    "any_n", "any_port", "append_to_file", "append_v", "asc_list",
    "ascii_banner", "assign", "assign_v", "assign_var", "async_run",
    "at_index", "augment", "avg_list", "b64_dec", "b64_enc",
    "b64d_n_1", "b64d_n_10", "b64d_n_11", "b64d_n_12", "b64d_n_13",
    "b64d_n_14", "b64d_n_15", "b64d_n_2", "b64d_n_3", "b64d_n_4",
    "b64d_n_5", "b64d_n_6", "b64d_n_7", "b64d_n_8", "b64d_n_9",
    "b64decode_v", "b64e_n_1", "b64e_n_10", "b64e_n_11", "b64e_n_12",
    "b64e_n_13", "b64e_n_14", "b64e_n_15", "b64e_n_2", "b64e_n_3",
    "b64e_n_4", "b64e_n_5", "b64e_n_6", "b64e_n_7", "b64e_n_8",
    "b64e_n_9", "b64encode_v", "b64ify", "back_add", "back_list",
    "back_list2", "back_remove", "back_v", "backwards", "bail_out",
    "banner_n_1", "banner_n_10", "banner_n_11", "banner_n_12", "banner_n_13",
    "banner_n_14", "banner_n_15", "banner_n_2", "banner_n_3", "banner_n_4",
    "banner_n_5", "banner_n_6", "banner_n_7", "banner_n_8", "banner_n_9",
    "banner_v", "bar", "bars", "basename_v", "begin_v",
    "begins_with", "bestow_v", "bg_run", "bg_v", "big_text",
    "bigger", "bind_var", "blab", "blank_term", "blast_msg",
    "blast_text", "block_for", "block_v", "bn_n_1", "bn_n_10",
    "bn_n_11", "bn_n_12", "bn_n_13", "bn_n_14", "bn_n_2",
    "bn_n_3", "bn_n_4", "bn_n_5", "bn_n_6", "bn_n_7",
    "bn_n_8", "bn_n_9", "boost_by", "boost_var", "bot_list",
    "bottomer", "bound_n", "box_n_1", "box_n_10", "box_n_11",
    "box_n_12", "box_n_13", "box_n_14", "box_n_15", "box_n_2",
    "box_n_3", "box_n_4", "box_n_5", "box_n_6", "box_n_7",
    "box_n_8", "box_n_9", "build_dict", "build_dict_v", "build_dir",
    "build_list", "build_list_v", "bump", "bump_down", "bump_n_1",
    "bump_n_10", "bump_n_11", "bump_n_12", "bump_n_13", "bump_n_14",
    "bump_n_15", "bump_n_2", "bump_n_3", "bump_n_4", "bump_n_5",
    "bump_n_6", "bump_n_7", "bump_n_8", "bump_n_9", "bumpdown",
    "bumpup", "bytes_of", "canonical_path", "card", "card_dict",
    "cat_file", "cat_v", "ceil_n_1", "ceil_n_10", "ceil_n_11",
    "ceil_n_12", "ceil_n_13", "ceil_n_14", "ceil_n_15", "ceil_n_2",
    "ceil_n_3", "ceil_n_4", "ceil_n_5", "ceil_n_6", "ceil_n_7",
    "ceil_n_8", "ceil_n_9", "ceil_v", "center_pad", "center_text",
    "center_v", "checksum_md5", "checksum_sha256", "clear_var", "close_db",
    "clrscr", "coin_flip2", "color_n_1", "color_n_10", "color_n_11",
    "color_n_12", "color_n_13", "color_n_14", "color_n_15", "color_n_2",
    "color_n_3", "color_n_4", "color_n_5", "color_n_6", "color_n_7",
    "color_n_8", "color_n_9", "color_v", "combine_path", "combine_str",
    "common_div", "common_mul2", "compliment_v", "computer_name", "concat_n_1",
    "concat_n_10", "concat_n_11", "concat_n_12", "concat_n_13", "concat_n_14",
    "concat_n_15", "concat_n_2", "concat_n_3", "concat_n_4", "concat_n_5",
    "concat_n_6", "concat_n_7", "concat_n_8", "concat_n_9", "concat_v",
    "constrain_n", "construct_v", "contains_v", "copy_v_p", "copy_var_v",
    "count_dict", "count_list", "cp_file", "create_dict", "create_dir",
    "create_folder", "create_list", "curl_dl", "curl_get", "curl_post",
    "current_date", "cut_var", "d_msg", "date_to_epoch", "datefmt_v",
    "day_of_date", "day_of_today", "day_of_week", "days_apart", "days_diff_v",
    "days_plus", "db_run", "db_select", "dbg_msg", "dec_n_1",
    "dec_n_10", "dec_n_11", "dec_n_12", "dec_n_13", "dec_n_14",
    "dec_n_15", "dec_n_2", "dec_n_3", "dec_n_4", "dec_n_5",
    "dec_n_6", "dec_n_7", "dec_n_8", "dec_n_9", "dec_v",
    "declare_var", "decode_base64", "decrement", "dedupe_list", "define_var",
    "del_path", "delay_secs", "delete_path", "delete_v", "delta_days",
    "deposit_text", "dequeue_back", "destroy_file", "dget_n_1", "dget_n_10",
    "dget_n_11", "dget_n_12", "dget_n_13", "dget_n_14", "dget_n_15",
    "dget_n_2", "dget_n_3", "dget_n_4", "dget_n_5", "dget_n_6",
    "dget_n_7", "dget_n_8", "dget_n_9", "dget_v", "dice20",
    "dice6", "dict_count2", "dict_lookup", "dict_n_1", "dict_n_10",
    "dict_n_11", "dict_n_12", "dict_n_13", "dict_n_14", "dict_n_15",
    "dict_n_2", "dict_n_3", "dict_n_4", "dict_n_5", "dict_n_6",
    "dict_n_7", "dict_n_8", "dict_n_9", "dict_put", "dict_put2",
    "dict_read", "dict_v", "die", "die_now", "digest_md5",
    "digest_sha256", "dir_contents", "dir_q", "dirname_v", "display_n_1",
    "display_n_10", "display_n_11", "display_n_12", "display_n_13", "display_n_14",
    "display_n_15", "display_n_2", "display_n_3", "display_n_4", "display_n_5",
    "display_n_6", "display_n_7", "display_n_8", "display_n_9", "display_text",
    "dist_2d", "dn_n_1", "dn_n_10", "dn_n_11", "dn_n_12",
    "dn_n_13", "dn_n_14", "dn_n_2", "dn_n_3", "dn_n_4",
    "dn_n_5", "dn_n_6", "dn_n_7", "dn_n_8", "dn_n_9",
    "dow", "down_int", "draw_one", "draw_text", "drop_var",
    "dset_n_1", "dset_n_10", "dset_n_11", "dset_n_12", "dset_n_13",
    "dset_n_14", "dset_n_15", "dset_n_2", "dset_n_3", "dset_n_4",
    "dset_n_5", "dset_n_6", "dset_n_7", "dset_n_8", "dset_n_9",
    "dset_v", "dsize_n_1", "dsize_n_10", "dsize_n_11", "dsize_n_12",
    "dsize_n_13", "dsize_n_14", "dsize_n_15", "dsize_n_2", "dsize_n_3",
    "dsize_n_4", "dsize_n_5", "dsize_n_6", "dsize_n_7", "dsize_n_8",
    "dsize_n_9", "dsize_v", "dt_format", "dump_file", "dump_lines",
    "dump_text", "dup_text", "dup_var", "ebb_var", "echo_n_1",
    "echo_n_10", "echo_n_11", "echo_n_12", "echo_n_13", "echo_n_14",
    "echo_n_15", "echo_n_2", "echo_n_3", "echo_n_4", "echo_n_5",
    "echo_n_6", "echo_n_7", "echo_n_8", "echo_n_9", "echo_now",
    "echo_p", "echo_str", "echo_text", "echo_var", "el",
    "el_set", "elem_at", "elements", "emit_file", "emit_n_1",
    "emit_n_10", "emit_n_11", "emit_n_12", "emit_n_13", "emit_n_14",
    "emit_n_15", "emit_n_2", "emit_n_3", "emit_n_4", "emit_n_5",
    "emit_n_6", "emit_n_7", "emit_n_8", "emit_n_9", "encode_base64",
    "end_run", "end_v", "ends_in", "endswith_v", "enqueue",
    "ensure_folder", "env_of", "env_set_var", "env_var", "envget",
    "envput", "epoch_now", "epoch_to_date", "epoch_v", "err_msg",
    "escape_html", "euclid", "even_check", "even_q", "ex_n_1",
    "ex_n_10", "ex_n_11", "ex_n_12", "ex_n_13", "ex_n_14",
    "ex_n_2", "ex_n_3", "ex_n_4", "ex_n_5", "ex_n_6",
    "ex_n_7", "ex_n_8", "ex_n_9", "exchange", "exec_n_v_1",
    "exec_n_v_10", "exec_n_v_11", "exec_n_v_12", "exec_n_v_13", "exec_n_v_14",
    "exec_n_v_15", "exec_n_v_2", "exec_n_v_3", "exec_n_v_4", "exec_n_v_5",
    "exec_n_v_6", "exec_n_v_7", "exec_n_v_8", "exec_n_v_9", "execute_cmd",
    "exists_v", "exit_n_v_1", "exit_n_v_10", "exit_n_v_11", "exit_n_v_12",
    "exit_n_v_13", "exit_n_v_14", "exit_n_v_15", "exit_n_v_2", "exit_n_v_3",
    "exit_n_v_4", "exit_n_v_5", "exit_n_v_6", "exit_n_v_7", "exit_n_v_8",
    "exit_n_v_9", "explode", "exponent", "ext_of_file", "extend_v",
    "extname_v", "fact_n", "fact_n_v_1", "fact_n_v_10", "fact_n_v_11",
    "fact_n_v_12", "fact_n_v_13", "fact_n_v_14", "fact_n_v_2", "fact_n_v_3",
    "fact_n_v_4", "fact_n_v_5", "fact_n_v_6", "fact_n_v_7", "fact_n_v_8",
    "fact_n_v_9", "factorial_n", "factorial_v", "fake_ip", "fetch",
    "fetch_at", "fetch_file", "fetch_file_url", "ffi_n_v_1", "ffi_n_v_10",
    "ffi_n_v_11", "ffi_n_v_12", "ffi_n_v_13", "ffi_n_v_14", "ffi_n_v_15",
    "ffi_n_v_2", "ffi_n_v_3", "ffi_n_v_4", "ffi_n_v_5", "ffi_n_v_6",
    "ffi_n_v_7", "ffi_n_v_8", "ffi_n_v_9", "ffi_run", "fib_n",
    "fib_n_v_1", "fib_n_v_10", "fib_n_v_11", "fib_n_v_12", "fib_n_v_13",
    "fib_n_v_14", "fib_n_v_2", "fib_n_v_3", "fib_n_v_4", "fib_n_v_5",
    "fib_n_v_6", "fib_n_v_7", "fib_n_v_8", "fib_n_v_9", "fibonacci_v",
    "file_append", "file_q", "file_size_human", "file_size_v", "filename_of",
    "filetype", "first_n_1", "first_n_10", "first_n_11", "first_n_12",
    "first_n_13", "first_n_14", "first_n_15", "first_n_2", "first_n_3",
    "first_n_4", "first_n_5", "first_n_6", "first_n_7", "first_n_8",
    "first_n_9", "first_v", "flip_list", "flip_str", "flip_v",
    "floor_n_1", "floor_n_10", "floor_n_11", "floor_n_12", "floor_n_13",
    "floor_n_14", "floor_n_15", "floor_n_2", "floor_n_3", "floor_n_4",
    "floor_n_5", "floor_n_6", "floor_n_7", "floor_n_8", "floor_n_9",
    "floor_v", "fmt_date", "fmt_json", "fmt_str", "folder_of_path",
    "forget_v", "fork_cmd", "fork_v", "form_v", "format_date_str",
    "format_date_v", "format_v", "fortune_v", "frame_text", "fresh",
    "fresh_dict", "fresh_dict_v", "fresh_list", "fresh_list_v", "from_b64",
    "from_json", "front_list", "fst_list", "fsz_n_1", "fsz_n_10",
    "fsz_n_11", "fsz_n_12", "fsz_n_13", "fsz_n_14", "fsz_n_2",
    "fsz_n_3", "fsz_n_4", "fsz_n_5", "fsz_n_6", "fsz_n_7",
    "fsz_n_8", "fsz_n_9", "full_path", "future_days", "gen_guid",
    "gen_range", "getenv_n_1", "getenv_n_10", "getenv_n_11", "getenv_n_12",
    "getenv_n_13", "getenv_n_14", "getenv_n_15", "getenv_n_2", "getenv_n_3",
    "getenv_n_4", "getenv_n_5", "getenv_n_6", "getenv_n_7", "getenv_n_8",
    "getenv_n_9", "getenv_v", "greatest_common", "growvar", "guid_v",
    "halt", "halt_for", "halt_now", "halt_v", "has_substr",
    "has_v_str", "has_var_v", "hash_256", "hash_5", "hcf",
    "he_n_1", "he_n_10", "he_n_11", "he_n_12", "he_n_13",
    "he_n_14", "he_n_2", "he_n_3", "he_n_4", "he_n_5",
    "he_n_6", "he_n_7", "he_n_8", "he_n_9", "head_is",
    "head_list", "heads_or_tails", "hg_n_1", "hg_n_10", "hg_n_11",
    "hg_n_12", "hg_n_13", "hg_n_14", "hg_n_15", "hg_n_2",
    "hg_n_3", "hg_n_4", "hg_n_5", "hg_n_6", "hg_n_7",
    "hg_n_8", "hg_n_9", "high_of", "hist_bar", "hm_get",
    "hm_set", "hold_for", "horiz_chart", "host_name", "host_of_url",
    "hostname_n_1", "hostname_n_10", "hostname_n_11", "hostname_n_12", "hostname_n_13",
    "hostname_n_14", "hostname_n_15", "hostname_n_2", "hostname_n_3", "hostname_n_4",
    "hostname_n_5", "hostname_n_6", "hostname_n_7", "hostname_n_8", "hostname_n_9",
    "hostname_v", "hp_n_1", "hp_n_10", "hp_n_11", "hp_n_12",
    "hp_n_13", "hp_n_14", "hp_n_15", "hp_n_2", "hp_n_3",
    "hp_n_4", "hp_n_5", "hp_n_6", "hp_n_7", "hp_n_8",
    "hp_n_9", "http_fetch2", "http_get_v", "http_post_v", "http_pull",
    "hv_n_1", "hv_n_10", "hv_n_11", "hv_n_12", "hv_n_13",
    "hv_n_14", "hv_n_2", "hv_n_3", "hv_n_4", "hv_n_5",
    "hv_n_6", "hv_n_7", "hv_n_8", "hv_n_9", "i2ip_n_1",
    "i2ip_n_10", "i2ip_n_11", "i2ip_n_12", "i2ip_n_13", "i2ip_n_14",
    "i2ip_n_2", "i2ip_n_3", "i2ip_n_4", "i2ip_n_5", "i2ip_n_6",
    "i2ip_n_7", "i2ip_n_8", "i2ip_n_9", "i_msg", "imbue_v",
    "import_env", "import_file", "inc_n_1", "inc_n_10", "inc_n_11",
    "inc_n_12", "inc_n_13", "inc_n_14", "inc_n_15", "inc_n_2",
    "inc_n_3", "inc_n_4", "inc_n_5", "inc_n_6", "inc_n_7",
    "inc_n_8", "inc_n_9", "inc_v", "incby", "includes",
    "incr_by", "increase", "increase_v", "increment", "indexof_list",
    "info_msg", "init_dict", "init_dict_v", "init_list", "init_list_v",
    "init_v", "init_var", "instil_v", "int_to_ip_v", "interp_fmt",
    "interpolate", "ip2i_n_1", "ip2i_n_10", "ip2i_n_11", "ip2i_n_12",
    "ip2i_n_13", "ip2i_n_14", "ip2i_n_2", "ip2i_n_3", "ip2i_n_4",
    "ip2i_n_5", "ip2i_n_6", "ip2i_n_7", "ip2i_n_8", "ip2i_n_9",
    "ip_to_int_v", "ip_v4_check_v", "ipv4_q", "ipv4_to_n", "iqr",
    "is_dir_v", "is_file_v", "is_set", "is_today_q", "is_up_ping",
    "isd_n_1", "isd_n_10", "isd_n_11", "isd_n_12", "isd_n_13",
    "isd_n_14", "isd_n_2", "isd_n_3", "isd_n_4", "isd_n_5",
    "isd_n_6", "isd_n_7", "isd_n_8", "isd_n_9", "isf_n_1",
    "isf_n_10", "isf_n_11", "isf_n_12", "isf_n_13", "isf_n_14",
    "isf_n_2", "isf_n_3", "isf_n_4", "isf_n_5", "isf_n_6",
    "isf_n_7", "isf_n_8", "isf_n_9", "iso_now", "join_str",
    "joinpath_v", "joke_v", "jp_n_1", "jp_n_10", "jp_n_11",
    "jp_n_12", "jp_n_13", "jp_n_14", "jp_n_2", "jp_n_3",
    "jp_n_4", "jp_n_5", "jp_n_6", "jp_n_7", "jp_n_8",
    "jp_n_9", "js_n_1", "js_n_10", "js_n_11", "js_n_12",
    "js_n_13", "js_n_14", "js_n_2", "js_n_3", "js_n_4",
    "js_n_5", "js_n_6", "js_n_7", "js_n_8", "js_n_9",
    "json_parse_v", "json_stringify_v", "kill_file", "kill_path", "kill_run",
    "kill_v", "kind_of", "kudos", "kv_count", "kv_get",
    "kv_set", "lappend2", "largest_in", "last_n_v_1", "last_n_v_10",
    "last_n_v_11", "last_n_v_12", "last_n_v_13", "last_n_v_14", "last_n_v_15",
    "last_n_v_2", "last_n_v_3", "last_n_v_4", "last_n_v_5", "last_n_v_6",
    "last_n_v_7", "last_n_v_8", "last_n_v_9", "last_v", "lat2",
    "lavg_n_1", "lavg_n_10", "lavg_n_11", "lavg_n_12", "lavg_n_13",
    "lavg_n_14", "lavg_n_15", "lavg_n_2", "lavg_n_3", "lavg_n_4",
    "lavg_n_5", "lavg_n_6", "lavg_n_7", "lavg_n_8", "lavg_n_9",
    "lavg_v", "lay_down", "lchoice_n_1", "lchoice_n_10", "lchoice_n_11",
    "lchoice_n_12", "lchoice_n_13", "lchoice_n_14", "lchoice_n_15", "lchoice_n_2",
    "lchoice_n_3", "lchoice_n_4", "lchoice_n_5", "lchoice_n_6", "lchoice_n_7",
    "lchoice_n_8", "lchoice_n_9", "lchoice_v", "lcumprod", "lcumsum",
    "leads_with", "leaf_of_path", "leap_check", "leap_q", "least_common_mul",
    "least_in", "leave", "leave_run", "len_l", "len_list",
    "let_v", "letvar", "lget_n_1", "lget_n_10", "lget_n_11",
    "lget_n_12", "lget_n_13", "lget_n_14", "lget_n_15", "lget_n_2",
    "lget_n_3", "lget_n_4", "lget_n_5", "lget_n_6", "lget_n_7",
    "lget_n_8", "lget_n_9", "lget_v", "limit_n", "linear_interp",
    "lines_of", "list_add", "list_at", "list_count2", "list_index",
    "list_len2", "list_n_1", "list_n_10", "list_n_11", "list_n_12",
    "list_n_13", "list_n_14", "list_n_15", "list_n_2", "list_n_3",
    "list_n_4", "list_n_5", "list_n_6", "list_n_7", "list_n_8",
    "list_n_9", "list_pop2", "list_push2", "list_put_at", "list_set2",
    "list_v", "listdir_v", "ll_n_1", "ll_n_10", "ll_n_11",
    "ll_n_12", "ll_n_13", "ll_n_14", "ll_n_2", "ll_n_3",
    "ll_n_4", "ll_n_5", "ll_n_6", "ll_n_7", "ll_n_8",
    "ll_n_9", "lmax_n_1", "lmax_n_10", "lmax_n_11", "lmax_n_12",
    "lmax_n_13", "lmax_n_14", "lmax_n_15", "lmax_n_2", "lmax_n_3",
    "lmax_n_4", "lmax_n_5", "lmax_n_6", "lmax_n_7", "lmax_n_8",
    "lmax_n_9", "lmax_v", "lmin_n_1", "lmin_n_10", "lmin_n_11",
    "lmin_n_12", "lmin_n_13", "lmin_n_14", "lmin_n_15", "lmin_n_2",
    "lmin_n_3", "lmin_n_4", "lmin_n_5", "lmin_n_6", "lmin_n_7",
    "lmin_n_8", "lmin_n_9", "lmin_v", "lo_n_1", "lo_n_10",
    "lo_n_11", "lo_n_12", "lo_n_13", "lo_n_14", "lo_n_15",
    "lo_n_2", "lo_n_3", "lo_n_4", "lo_n_5", "lo_n_6",
    "lo_n_7", "lo_n_8", "lo_n_9", "load_dotenv", "load_file",
    "load_file_v", "load_lines", "loader", "log_d", "log_e",
    "log_i", "log_out_msg", "log_w", "logerror", "lookup_key",
    "loud_text", "low_of", "lower_v", "lower_var", "lowervalue",
    "lpartition", "lpop", "lpush", "lreverse_n_1", "lreverse_n_10",
    "lreverse_n_11", "lreverse_n_12", "lreverse_n_13", "lreverse_n_14", "lreverse_n_15",
    "lreverse_n_2", "lreverse_n_3", "lreverse_n_4", "lreverse_n_5", "lreverse_n_6",
    "lreverse_n_7", "lreverse_n_8", "lreverse_n_9", "lreverse_v", "ls_dir",
    "lset_n_1", "lset_n_10", "lset_n_11", "lset_n_12", "lset_n_13",
    "lset_n_14", "lset_n_15", "lset_n_2", "lset_n_3", "lset_n_4",
    "lset_n_5", "lset_n_6", "lset_n_7", "lset_n_8", "lset_n_9",
    "lset_v", "lshuffle_n_1", "lshuffle_n_10", "lshuffle_n_11", "lshuffle_n_12",
    "lshuffle_n_13", "lshuffle_n_14", "lshuffle_n_15", "lshuffle_n_2", "lshuffle_n_3",
    "lshuffle_n_4", "lshuffle_n_5", "lshuffle_n_6", "lshuffle_n_7", "lshuffle_n_8",
    "lshuffle_n_9", "lshuffle_v", "lsize_n_1", "lsize_n_10", "lsize_n_11",
    "lsize_n_12", "lsize_n_13", "lsize_n_14", "lsize_n_15", "lsize_n_2",
    "lsize_n_3", "lsize_n_4", "lsize_n_5", "lsize_n_6", "lsize_n_7",
    "lsize_n_8", "lsize_n_9", "lsize_v", "lsort_n_1", "lsort_n_10",
    "lsort_n_11", "lsort_n_12", "lsort_n_13", "lsort_n_14", "lsort_n_15",
    "lsort_n_2", "lsort_n_3", "lsort_n_4", "lsort_n_5", "lsort_n_6",
    "lsort_n_7", "lsort_n_8", "lsort_n_9", "lsort_v", "lst_list",
    "lsum_n_1", "lsum_n_10", "lsum_n_11", "lsum_n_12", "lsum_n_13",
    "lsum_n_14", "lsum_n_15", "lsum_n_2", "lsum_n_3", "lsum_n_4",
    "lsum_n_5", "lsum_n_6", "lsum_n_7", "lsum_n_8", "lsum_n_9",
    "lsum_v", "lunique_v", "lzip", "machine_name", "mag_of",
    "make_dict", "make_dir_v", "make_folder", "make_list", "make_range",
    "make_uuid", "make_v", "manhattan_dist", "map_get", "map_lookup",
    "map_put", "map_set", "max_of_list", "maybe", "md5_n_1",
    "md5_n_10", "md5_n_11", "md5_n_12", "md5_n_13", "md5_n_14",
    "md5_n_15", "md5_n_2", "md5_n_3", "md5_n_4", "md5_n_5",
    "md5_n_6", "md5_n_7", "md5_n_8", "md5_n_9", "md5_text",
    "md5_v", "md5sum", "mean_list", "merge_str", "middle_pad",
    "midval_list", "millis_sleep", "min_of_list", "mini_chart", "mix_list",
    "mix_n", "mk_dir", "mkd_n_1", "mkd_n_10", "mkd_n_11",
    "mkd_n_12", "mkd_n_13", "mkd_n_14", "mkd_n_15", "mkd_n_2",
    "mkd_n_3", "mkd_n_4", "mkd_n_5", "mkd_n_6", "mkd_n_7",
    "mkd_n_8", "mkd_n_9", "mkdir_v", "mm_dec", "mon_of",
    "month_of", "months_between", "move_v", "msec_pause", "msec_sleep",
    "msleep", "mv_file", "my_pid", "n_copies", "n_elems",
    "n_fact", "n_keys", "n_keys2", "n_th_prime", "n_to_ipv4",
    "nap_for", "nap_n_1", "nap_n_10", "nap_n_11", "nap_n_12",
    "nap_n_13", "nap_n_14", "nap_n_15", "nap_n_2", "nap_n_3",
    "nap_n_4", "nap_n_5", "nap_n_6", "nap_n_7", "nap_n_8",
    "nap_n_9", "nap_v", "nearest_int", "neg_or_pos", "net_ping",
    "new_dict", "new_dir", "new_folder", "new_list", "new_uuid",
    "new_uuid_v2", "next_day", "nice_one", "no_dups", "now_epoch",
    "now_n_v_1", "now_n_v_10", "now_n_v_11", "now_n_v_12", "now_n_v_13",
    "now_n_v_14", "now_n_v_15", "now_n_v_2", "now_n_v_3", "now_n_v_4",
    "now_n_v_5", "now_n_v_6", "now_n_v_7", "now_n_v_8", "now_n_v_9",
    "now_v", "nth_fib", "nudge_down", "nudge_up", "odd_check",
    "odd_q", "open_db", "order_list", "os_kind", "out_file",
    "out_msg", "out_n_1", "out_n_10", "out_n_11", "out_n_12",
    "out_n_13", "out_n_14", "out_n_15", "out_n_2", "out_n_3",
    "out_n_4", "out_n_5", "out_n_6", "out_n_7", "out_n_8",
    "out_n_9", "p_back", "p_back_off", "p_emit", "p_line",
    "p_ln", "p_msg", "p_out", "p_str", "p_text",
    "p_v", "p_val", "pad_text", "pad_v", "parent_of",
    "parse_json", "path_join", "path_of_url", "path_q", "pattern_match",
    "pause_ms", "pause_secs", "pause_v", "pct_encode", "peek_at",
    "percentile_25", "percentile_75", "pick_n", "pick_n_v_1", "pick_n_v_10",
    "pick_n_v_11", "pick_n_v_12", "pick_n_v_13", "pick_n_v_14", "pick_n_v_15",
    "pick_n_v_2", "pick_n_v_3", "pick_n_v_4", "pick_n_v_5", "pick_n_v_6",
    "pick_n_v_7", "pick_n_v_8", "pick_n_v_9", "pick_one", "pickrand",
    "place_at", "place_index", "place_v", "place_var", "platform_v",
    "plus_add", "plus_days", "plus_n_1", "plus_n_10", "plus_n_11",
    "plus_n_12", "plus_n_13", "plus_n_14", "plus_n_15", "plus_n_2",
    "plus_n_3", "plus_n_4", "plus_n_5", "plus_n_6", "plus_n_7",
    "plus_n_8", "plus_n_9", "plus_v", "polarity", "pop_n_v_1",
    "pop_n_v_10", "pop_n_v_11", "pop_n_v_12", "pop_n_v_13", "pop_n_v_14",
    "pop_n_v_15", "pop_n_v_2", "pop_n_v_3", "pop_n_v_4", "pop_n_v_5",
    "pop_n_v_6", "pop_n_v_7", "pop_n_v_8", "pop_n_v_9", "pop_v",
    "positive_of", "post_request", "post_to_term", "post_url", "pow_v",
    "power_of", "pp_inc", "preserve_v", "pretty_json", "prev_day",
    "prime_check", "prime_nth", "prime_q", "primes_below", "print_line",
    "print_ln", "print_msg", "print_n_1", "print_n_10", "print_n_11",
    "print_n_12", "print_n_13", "print_n_14", "print_n_15", "print_n_2",
    "print_n_3", "print_n_4", "print_n_5", "print_n_6", "print_n_7",
    "print_n_8", "print_n_9", "print_out", "print_str", "print_table",
    "print_text", "print_to_screen", "print_to_term", "println_v", "printout",
    "progress_n_v_1", "progress_n_v_10", "progress_n_v_11", "progress_n_v_12", "progress_n_v_13",
    "progress_n_v_14", "progress_n_v_15", "progress_n_v_2", "progress_n_v_3", "progress_n_v_4",
    "progress_n_v_5", "progress_n_v_6", "progress_n_v_7", "progress_n_v_8", "progress_n_v_9",
    "progress_v", "push_n_v_1", "push_n_v_10", "push_n_v_11", "push_n_v_12",
    "push_n_v_13", "push_n_v_14", "push_n_v_15", "push_n_v_2", "push_n_v_3",
    "push_n_v_4", "push_n_v_5", "push_n_v_6", "push_n_v_7", "push_n_v_8",
    "push_n_v_9", "push_v", "put_v", "puts_v", "query_of_url",
    "queue_add", "quiet_text", "quit", "quit_now", "r_file",
    "raise_to", "raise_var", "rand_09", "rand_AZ", "rand_alpha",
    "rand_az", "rand_dec", "rand_digit_v", "rand_elem", "rand_hex",
    "rand_hex_char_v", "rand_in_range", "rand_ip", "rand_letter_v", "rand_n2",
    "rand_n_v_1", "rand_n_v_10", "rand_n_v_11", "rand_n_v_12", "rand_n_v_13",
    "rand_n_v_14", "rand_n_v_15", "rand_n_v_2", "rand_n_v_3", "rand_n_v_4",
    "rand_n_v_5", "rand_n_v_6", "rand_n_v_7", "rand_n_v_8", "rand_n_v_9",
    "rand_p", "rand_real", "rand_uppercase_v", "rand_uuid_v", "rand_v",
    "random_in", "random_int", "random_int_v", "random_ipv4_v", "random_n",
    "random_port_v", "random_v", "randomize_list", "range_n_1", "range_n_10",
    "range_n_11", "range_n_12", "range_n_13", "range_n_14", "range_n_15",
    "range_n_2", "range_n_3", "range_n_4", "range_n_5", "range_n_6",
    "range_n_7", "range_n_8", "range_n_9", "range_stat", "range_v",
    "re_n_1", "re_n_10", "re_n_11", "re_n_12", "re_n_13",
    "re_n_14", "re_n_15", "re_n_2", "re_n_3", "re_n_4",
    "re_n_5", "re_n_6", "re_n_7", "re_n_8", "re_n_9",
    "re_replace", "re_swap", "re_test", "read_at", "read_to_string",
    "real_rand", "reduce_var", "regex_all_matches", "regex_capture", "regex_swap",
    "regex_test", "remember_v", "remember_var", "remove_back", "rename_path",
    "render_fmt", "render_grid", "render_table", "render_text", "repeat_v",
    "replace_v", "request", "res_n_1", "res_n_10", "res_n_11",
    "res_n_12", "res_n_13", "res_n_14", "res_n_15", "res_n_2",
    "res_n_3", "res_n_4", "res_n_5", "res_n_6", "res_n_7",
    "res_n_8", "res_n_9", "reset_screen", "rest_n_1", "rest_n_10",
    "rest_n_11", "rest_n_12", "rest_n_13", "rest_n_14", "rest_n_15",
    "rest_n_2", "rest_n_3", "rest_n_4", "rest_n_5", "rest_n_6",
    "rest_n_7", "rest_n_8", "rest_n_9", "rest_secs", "retreat",
    "rev_list", "rev_n_1", "rev_n_10", "rev_n_11", "rev_n_12",
    "rev_n_13", "rev_n_14", "rev_n_15", "rev_n_2", "rev_n_3",
    "rev_n_4", "rev_n_5", "rev_n_6", "rev_n_7", "rev_n_8",
    "rev_n_9", "rev_str", "rev_v", "rfc3339_now", "rfile_n_1",
    "rfile_n_10", "rfile_n_11", "rfile_n_12", "rfile_n_13", "rfile_n_14",
    "rfile_n_15", "rfile_n_2", "rfile_n_3", "rfile_n_4", "rfile_n_5",
    "rfile_n_6", "rfile_n_7", "rfile_n_8", "rfile_n_9", "right_pad_text",
    "rise_var", "rm_n_v_1", "rm_n_v_10", "rm_n_v_11", "rm_n_v_12",
    "rm_n_v_13", "rm_n_v_14", "rm_n_v_15", "rm_n_v_2", "rm_n_v_3",
    "rm_n_v_4", "rm_n_v_5", "rm_n_v_6", "rm_n_v_7", "rm_n_v_8",
    "rm_n_v_9", "rndi", "rng_n", "rng_n_v_1", "rng_n_v_10",
    "rng_n_v_11", "rng_n_v_12", "rng_n_v_13", "rng_n_v_14", "rng_n_v_15",
    "rng_n_v_2", "rng_n_v_3", "rng_n_v_4", "rng_n_v_5", "rng_n_v_6",
    "rng_n_v_7", "rng_n_v_8", "rng_n_v_9", "roll_d20", "roll_d6",
    "roll_n", "root2", "round_down", "round_n_1", "round_n_10",
    "round_n_11", "round_n_12", "round_n_13", "round_n_14", "round_n_15",
    "round_n_2", "round_n_3", "round_n_4", "round_n_5", "round_n_6",
    "round_n_7", "round_n_8", "round_n_9", "round_to_int", "round_up",
    "round_v", "rpad_text", "rrand", "rreplace", "save_file",
    "save_file_v", "save_lines", "save_n_1", "save_n_10", "save_n_11",
    "save_n_12", "save_n_13", "save_n_14", "save_n_15", "save_n_2",
    "save_n_3", "save_n_4", "save_n_5", "save_n_6", "save_n_7",
    "save_n_8", "save_n_9", "save_to_file", "save_var", "savevar",
    "say_it", "say_n_1", "say_n_10", "say_n_11", "say_n_12",
    "say_n_13", "say_n_14", "say_n_15", "say_n_2", "say_n_3",
    "say_n_4", "say_n_5", "say_n_6", "say_n_7", "say_n_8",
    "say_n_9", "scheme_of_url", "scr_print", "scramble_list", "screen_print",
    "send_post", "send_text", "send_to_screen", "send_to_term", "seq_to",
    "set2", "set_at", "set_color", "set_field_v", "set_int_var",
    "set_n_1", "set_n_10", "set_n_11", "set_n_12", "set_n_13",
    "set_n_14", "set_n_15", "set_n_2", "set_n_3", "set_n_4",
    "set_n_5", "set_n_6", "set_n_7", "set_n_8", "set_n_9",
    "set_str_var", "set_term_color", "set_var", "setenv_n_1", "setenv_n_10",
    "setenv_n_11", "setenv_n_12", "setenv_n_13", "setenv_n_14", "setenv_n_15",
    "setenv_n_2", "setenv_n_3", "setenv_n_4", "setenv_n_5", "setenv_n_6",
    "setenv_n_7", "setenv_n_8", "setenv_n_9", "setenv_v", "sh_capture",
    "sh_grab", "sh_run", "sha256_n_1", "sha256_n_10", "sha256_n_11",
    "sha256_n_12", "sha256_n_13", "sha256_n_14", "sha256_n_15", "sha256_n_2",
    "sha256_n_3", "sha256_n_4", "sha256_n_5", "sha256_n_6", "sha256_n_7",
    "sha256_n_8", "sha256_n_9", "sha256_text", "sha256_v", "sha256sum",
    "shell_capture", "shell_cmd", "shell_run", "shift_back", "shout_msg",
    "shout_text", "shove_back", "show_n_1", "show_n_10", "show_n_11",
    "show_n_12", "show_n_13", "show_n_14", "show_n_15", "show_n_2",
    "show_n_3", "show_n_4", "show_n_5", "show_n_6", "show_n_7",
    "show_n_8", "show_n_9", "show_table", "show_text", "shrink_var",
    "shutdown", "shutdown_now", "siesta_for", "sign_n_1", "sign_n_10",
    "sign_n_11", "sign_n_12", "sign_n_13", "sign_n_14", "sign_n_15",
    "sign_n_2", "sign_n_3", "sign_n_4", "sign_n_5", "sign_n_6",
    "sign_n_7", "sign_n_8", "sign_n_9", "sign_v", "signum",
    "size_of_file", "sleep_ms_v", "sleep_n_1", "sleep_n_10", "sleep_n_11",
    "sleep_n_12", "sleep_n_13", "sleep_n_14", "sleep_n_15", "sleep_n_2",
    "sleep_n_3", "sleep_n_4", "sleep_n_5", "sleep_n_6", "sleep_n_7",
    "sleep_n_8", "sleep_n_9", "slip_var", "slurp_file", "slurp_text",
    "smaller2", "snooze", "snooze_v", "sort_list", "spawn_dir",
    "spawn_sh", "spawn_v", "spawn_var", "speak_str", "speak_text",
    "speak_v", "spin_n_1", "spin_n_10", "spin_n_11", "spin_n_12",
    "spin_n_13", "spin_n_14", "spin_n_15", "spin_n_2", "spin_n_3",
    "spin_n_4", "spin_n_5", "spin_n_6", "spin_n_7", "spin_n_8",
    "spin_n_9", "spin_v", "spinner_show", "spinner_v", "splat",
    "split_n_1", "split_n_10", "split_n_11", "split_n_12", "split_n_13",
    "split_n_14", "split_n_15", "split_n_2", "split_n_3", "split_n_4",
    "split_n_5", "split_n_6", "split_n_7", "split_n_8", "split_n_9",
    "split_v", "sprintf_like", "sq_root", "sql_exec", "sql_query",
    "sqlite_close", "sqlite_open", "sqrt_n_1", "sqrt_n_10", "sqrt_n_11",
    "sqrt_n_12", "sqrt_n_13", "sqrt_n_14", "sqrt_n_15", "sqrt_n_2",
    "sqrt_n_3", "sqrt_n_4", "sqrt_n_5", "sqrt_n_6", "sqrt_n_7",
    "sqrt_n_8", "sqrt_n_9", "sqrt_v", "square_root", "stack_push2",
    "startswith_v", "stash_v", "stash_var", "stdout_print", "stdout_v",
    "stdout_w", "step_down", "step_up", "step_var", "stitch",
    "stop", "stop_run", "store_file", "store_n_1", "store_n_10",
    "store_n_11", "store_n_12", "store_n_13", "store_n_14", "store_n_15",
    "store_n_2", "store_n_3", "store_n_4", "store_n_5", "store_n_6",
    "store_n_7", "store_n_8", "store_n_9", "store_v", "store_var",
    "str_in", "stringify_json", "strip", "strip_v", "sub_re",
    "sub_text", "submit", "subst_fmt", "sum_into", "sum_n_1",
    "sum_n_10", "sum_n_11", "sum_n_12", "sum_n_13", "sum_n_14",
    "sum_n_15", "sum_n_2", "sum_n_3", "sum_n_4", "sum_n_5",
    "sum_n_6", "sum_n_7", "sum_n_8", "sum_n_9", "sum_v",
    "swap_re", "swap_text", "swap_v", "swap_vars_v", "system_kind",
    "system_run", "table_get", "table_n_1", "table_n_10", "table_n_11",
    "table_n_12", "table_n_13", "table_n_14", "table_n_15", "table_n_2",
    "table_n_3", "table_n_4", "table_n_5", "table_n_6", "table_n_7",
    "table_n_8", "table_n_9", "table_set", "table_v", "tail_add",
    "tail_is", "tail_list_end", "tails_with", "tally_in", "tally_v",
    "taxicab", "tell_it", "tell_joke", "tell_n_1", "tell_n_10",
    "tell_n_11", "tell_n_12", "tell_n_13", "tell_n_14", "tell_n_15",
    "tell_n_2", "tell_n_3", "tell_n_4", "tell_n_5", "tell_n_6",
    "tell_n_7", "tell_n_8", "tell_n_9", "tellme", "term_color",
    "term_print", "test_prime", "this_day", "throbber", "tick",
    "tick_n_1", "tick_n_10", "tick_n_11", "tick_n_12", "tick_n_13",
    "tick_n_14", "tick_n_15", "tick_n_2", "tick_n_3", "tick_n_4",
    "tick_n_5", "tick_n_6", "tick_n_7", "tick_n_8", "tick_n_9",
    "tick_v", "tick_var", "tidy_screen", "times_str", "tint",
    "tinybar", "to_b64", "to_int_round", "to_json", "to_lower_text",
    "to_lower_v", "to_parts", "to_upper_text", "to_upper_v", "today_check",
    "today_date", "today_n_v_1", "today_n_v_10", "today_n_v_11", "today_n_v_12",
    "today_n_v_13", "today_n_v_14", "today_n_v_15", "today_n_v_2", "today_n_v_3",
    "today_n_v_4", "today_n_v_5", "today_n_v_6", "today_n_v_7", "today_n_v_8",
    "today_n_v_9", "today_v", "todays_date", "tof_n_1", "tof_n_10",
    "tof_n_11", "tof_n_12", "tof_n_13", "tof_n_14", "tof_n_2",
    "tof_n_3", "tof_n_4", "tof_n_5", "tof_n_6", "tof_n_7",
    "tof_n_8", "tof_n_9", "tokenize", "tomorrow_v", "top_list",
    "topper", "tossbit", "total_list", "totalize", "trade_vars",
    "trash", "trim_n_1", "trim_n_10", "trim_n_11", "trim_n_12",
    "trim_n_13", "trim_n_14", "trim_n_15", "trim_n_2", "trim_n_3",
    "trim_n_4", "trim_n_5", "trim_n_6", "trim_n_7", "trim_n_8",
    "trim_n_9", "trim_spaces", "trim_v", "trim_var", "trim_ws",
    "trunc_down", "trunc_up", "tstamp", "typ_of", "type_msg",
    "type_of_v", "type_str", "type_text", "type_v", "ue_n_1",
    "ue_n_10", "ue_n_11", "ue_n_12", "ue_n_13", "ue_n_14",
    "ue_n_2", "ue_n_3", "ue_n_4", "ue_n_5", "ue_n_6",
    "ue_n_7", "ue_n_8", "ue_n_9", "un_b64", "uniq_list",
    "unix_now", "unlink_file", "unlink_v", "unset_var_v", "unstack",
    "untick", "untick_n_1", "untick_n_10", "untick_n_11", "untick_n_12",
    "untick_n_13", "untick_n_14", "untick_n_15", "untick_n_2", "untick_n_3",
    "untick_n_4", "untick_n_5", "untick_n_6", "untick_n_7", "untick_n_8",
    "untick_n_9", "up_int", "up_n_1", "up_n_10", "up_n_11",
    "up_n_12", "up_n_13", "up_n_14", "up_n_15", "up_n_2",
    "up_n_3", "up_n_4", "up_n_5", "up_n_6", "up_n_7",
    "up_n_8", "up_n_9", "upper_v", "uppervalue", "url_fetch",
    "url_get", "url_host_v", "url_path_v", "url_post", "url_query_v",
    "url_scheme_v", "urlenc", "uuid_n_1", "uuid_n_10", "uuid_n_11",
    "uuid_n_12", "uuid_n_13", "uuid_n_14", "uuid_n_15", "uuid_n_2",
    "uuid_n_3", "uuid_n_4", "uuid_n_5", "uuid_n_6", "uuid_n_7",
    "uuid_n_8", "uuid_n_9", "uuid_v_alt", "v_set", "valid_ipv4",
    "var_exists", "var_set", "w_file", "w_msg", "wait_millis",
    "wait_ms", "warn_msg", "web_get", "weekend_check", "weekend_q",
    "wfile_n_1", "wfile_n_10", "wfile_n_11", "wfile_n_12", "wfile_n_13",
    "wfile_n_14", "wfile_n_15", "wfile_n_2", "wfile_n_3", "wfile_n_4",
    "wfile_n_5", "wfile_n_6", "wfile_n_7", "wfile_n_8", "wfile_n_9",
    "wget_file", "wget_str", "what_is", "whisper_text", "wipe_path",
    "wipescr", "wisdom_text", "write_at", "write_n_1", "write_n_10",
    "write_n_11", "write_n_12", "write_n_13", "write_n_14", "write_n_15",
    "write_n_2", "write_n_3", "write_n_4", "write_n_5", "write_n_6",
    "write_n_7", "write_n_8", "write_n_9", "write_to_file", "writeln",
    "writeln_v", "xchg_vars", "xn_n_1", "xn_n_10", "xn_n_11",
    "xn_n_12", "xn_n_13", "xn_n_14", "xn_n_2", "xn_n_3",
    "xn_n_4", "xn_n_5", "xn_n_6", "xn_n_7", "xn_n_8",
    "xn_n_9", "yank_back", "year_of", "years_between", "yell_msg",
    "yesterday_v", "yr_of", "zzz",
    "p_final", "say_final", "print_final", "write_final",
    "async", "await", "@timed", "@logged", "@once", "@retry", "lambda", "matchv", "ws_broadcast", "ws_last", "pkg_asset_path", "pkg_asset_read", "pkg_db_open", "pkg_run_sql",
    "ws_serve", "ws_send", "ws_clients", "ws_recv", "ws_close_all", "gui_show", "gui_window", "ld_set", "ld_get", "docs", "tostring",
    "gui_native", "gui_clear", "gui_pixel", "gui_fill_rect", "gui_rect", "gui_line", "gui_circle", "gui_fill_circle", "gui_text", "gui_update", "gui_open", "gui_mouse_x", "gui_mouse_y", "gui_mouse_down", "gui_key_down", "gui_close",
    "gui_fill_triangle", "gui_text_big", "gui_get_pixel", "gui_screenshot", "gui_gradient_rect", "gui_alpha_pixel", "gui_set_title", "gui_window_w", "gui_window_h", "gui_mouse_wheel", "gui_is_focused", "gui_polygon", "gui_blit_ppm", "gui_clear_rect", "gui_ellipse", "gui_thick_line", "gui_text_width",
    "gui_3d_add_light", "gui_3d_clear_lights", "gui_3d_fog", "gui_3d_no_fog", "gui_3d_cull", "gui_3d_specular", "gui_3d_cylinder", "gui_3d_cone", "gui_3d_plane",
    "gui_3d_shadow", "gui_3d_load_texture", "gui_3d_textured_quad", "gui_3d_load_obj", "gui_3d_draw_mesh",
    "gui_3d_camera_pos", "gui_3d_camera_yaw", "gui_3d_camera_pitch", "gui_3d_camera_move", "gui_3d_camera_look_at",
    "gui_3d_camera_follow", "gui_3d_billboard", "gui_3d_load_texture_url", "curl",
    "gui_2d_load_image", "gui_2d_load_image_url", "gui_2d_image_size", "gui_2d_draw_image",
    "gui_2d_draw_image_scaled", "gui_2d_draw_image_region", "gui_2d_camera", "gui_2d_camera_reset",
    "gui_2d_color_key", "gui_2d_load_tileset", "gui_2d_draw_tile", "gui_2d_text_outline",
    "gui_2d_smooth", "gui_2d_draw_image_rotated", "gui_2d_draw_image_flipped",
    "gui_2d_draw_image_tinted", "gui_2d_draw_image_ex",
    "fail",
    "aabb_collide", "sphere_collide", "ray_sphere_hit", "distance3d",
    "point_in_aabb", "platform_top",
    "gui_aa_line", "gui_aa_circle", "gui_shade_triangle", "gui_3d_setup", "gui_3d_rotate", "gui_3d_camera", "gui_3d_light", "gui_3d_ambient", "gui_3d_clear", "gui_3d_triangle", "gui_3d_cube", "gui_3d_sphere", "gui_3d_line",
    "gui_particle_spawn", "gui_particle_burst", "gui_particle_update", "gui_particle_draw", "gui_particle_count", "gui_particle_clear", "gui_3d_shade_triangle", "beep_tone", "noise",
    "gl_init", "gl_clear", "gl_rotate", "gl_camera", "gl_triangle", "gl_cube", "gl_swap", "gl_open", "gl_close",
    "gl_frame_time", "gl_fps_actual", "gl_should_fallback", "sys_cpu", "sys_mem",
    "r3d_init", "r3d_clear", "r3d_rotate", "r3d_camera", "r3d_cube", "r3d_swap", "r3d_open", "r3d_close", "r3d_mode",
    "stats_median", "stats_variance", "stats_stddev", "stats_mode", "stats_range", "stats_percentile",
    "vec3_add", "vec3_sub", "vec3_scale", "vec3_dot", "vec3_cross", "vec3_length", "vec3_normalize", "vec3_distance", "vec3_lerp",
    "csv_read", "csv_write",
    "vec2_add", "vec2_sub", "vec2_scale", "vec2_dot", "vec2_length", "vec2_normalize", "vec2_distance", "vec2_angle",
    "smoothstep", "hsv_to_rgb", "rgb_to_hsv", "color_lerp",
    "pad_right", "center_str",
    "list_unique", "list_zip", "list_chunk",
    "tui_box", "tui_progress",
    "gui_fps",
    "echo",
"println",
"print_l",
"write_line",
"p_one",
"outln",
"out_line",
"out_str",
"outmsg",
"p_log",
"log_line",
"log_p",
"log_pr",
"tell",
"say_line",
"say2",
"narrate2",
"render_msg",
"broadcast",
"announce",
"report",
"msg_p",
"msg2",
"msg_out",
"msg_out2",
"alert",
"alert2",
"show_line",
"show_str",
"show3",
"show_msg",
"display",
"display2",
"display_line",
"disp_line",
"disp_msg",
"dispmsg",
"txt_print",
"txt2",
"txt_p",
"txt_w",
"txt_msg",
"p1",
"p2",
"p3",
"p4",
"p5",
"p_msg2",
"psay",
"p_say",
"to_upper2",
"ucase",
"uc_str",
"uppercase_str",
"upcase",
"shout",
"capitalize_all",
"all_upper",
"all_caps",
"to_lower2",
"lcase",
"lc_str",
"string_length",
"char_count",
"char_length",
"str_len2",
"len2",
"size_of_str",
"txt_len",
"list_length",
"list_size2",
"list_count_all",
"num_items",
"item_count2",
"len_of_list",
"dict_length",
"dict_size2",
"dict_count_all",
"num_keys",
"key_count",
"hash_size",
"to_int2",
"parse_int",
"atoi",
"as_int",
"integer_of",
"int_from_str",
"i_of",
"to_float2",
"parse_float",
"atof",
"as_float",
"float_of",
"f_of",
"real_of",
"to_str",
"str_of",
"string_of",
"as_str",
"stringify",
"repr2",
"inspect2",
"rev2",
"string_reverse",
"strip_ws",
"strip2",
"trim_str",
"chomp",
"trim_all",
"string_concat",
"str_append",
"stitch_str",
"str_split",
"string_split",
"tokens_of",
"tokenize2",
"string_replace",
"swap_str",
"substitute",
"subst2",
"str_swap",
"loop_n",
"n_times",
"do_n",
"iter_n",
"times_n",
"rand_int_v",
"randomi",
"rnd_int",
"wait",
"pause2",
"delay",
"hold2",
"sleep_v",
"now_ms_v",
"current_ms",
"millis_now",
"ts_ms",
"epoch_ms_v",
"sin_v",
"sine",
"sin_of",
"cos_v",
"cosine",
"cos_of",
"tan_v",
"tangent",
"tan_of",
"abs2",
"magnitude",
"abs_of",
"modulus_n",
"sqrt2",
"sqrt_of",
"floor2",
"floor_of",
"ceil2",
"ceil_of",
"round2",
"round_off",
"round_of",
"color_rgb",
"from_rgb",
"rgb_color",
"rgb_make",
"mklist",
"list_append",
"list_push",
"append_to",
"add_to_list",
"list_pop",
"remove_last",
"tail_remove",
"list_set",
"set_index",
"assign_at",
"put_at",
"list_get",
"get_at",
"get_index",
"list_clear",
"empty_list",
"clear_list",
"wipe_list",
"reset_list",
"abs_alt",
"abspath_alt",
"add_days_alt",
"append_file_alt",
"arch_name_alt",
"arrow_down_alt",
"arrow_left_alt",
"arrow_right_alt",
"arrow_up_alt",
"askstring_alt",
"askyesno_alt",
"assert_alt",
"assert_eq_alt",
"assert_gt_alt",
"assert_lt_alt",
"assert_ne_alt",
"async_alt",
"atan2_alt",
"atbash_alt",
"avg_alt",
"await_alt",
"backup_file_alt",
"band_alt",
"banner_alt",
"barchart_alt",
"base64_decode_alt",
"base64_encode_alt",
"basename_alt",
"benchmark_alt",
"bgrgb_alt",
"bnot_alt",
"bor_alt",
"box_alt",
"bxor_alt",
"caesar_decode_alt",
"caesar_encode_alt",
"calc_alt",
"call_alt",
"capitalize_alt",
"catch_alt",
"ceil_alt",
"center_alt",
"chars_alt",
"choose_alt",
"chr_alt",
"clamp_alt",
"clamp_int_alt",
"class_alt",
"coin_alt",
"color_alt",
"concat_alt",
"const_alt",
"contains_alt",
"contains_all_alt",
"contains_any_alt",
"copy_alt",
"copy_var_alt",
"countdown_alt",
"count_lines_matching_alt",
"count_substr_alt",
"countup_alt",
"count_words_alt",
"crc32_alt",
"ctype_alt",
"d20_alt",
"d6_alt",
"datefmt_alt",
"date_today_alt",
"date_tomorrow_alt",
"date_yesterday_alt",
"day_alt",
"dayname_alt",
"dayofyear_alt",
"days_in_month_alt",
"days_in_year_alt",
"db_begin_alt",
"db_close_alt",
"db_commit_alt",
"db_count_alt",
"db_exec_alt",
"db_exists_alt",
"db_insert_alt",
"db_open_alt",
"db_query_alt",
"db_rollback_alt",
"db_tables_alt",
"dclear_alt",
"dcount_value_alt",
"ddel_alt",
"decr_alt",
"deg_to_rad_alt",
"delete_alt",
"dget_alt",
"dhas_alt",
"dict_alt",
"diff_days_alt",
"dincr_alt",
"dinvert_alt",
"dir_exists_alt",
"dirname_alt",
"distance_alt",
"divider_alt",
"dkeys_alt",
"dmerge_alt",
"docs_alt",
"domit_alt",
"download_alt",
"dpairs_alt",
"dpick_alt",
"dpop_alt",
"dprint_alt",
"dset_alt",
"dsize_alt",
"dvalues_alt",
"e_alt",
"echo_alt",
"endswith_alt",
"ensure_dir_alt",
"enum_alt",
"env_dict_alt",
"env_list_alt",
"env_size_alt",
"exec_alt",
"exists_alt",
"extname_alt",
"factorial_alt",
"ffi_alt",
"fficall_alt",
"ffiload_alt",
"fibonacci_alt",
"field_alt",
"file_age_alt",
"file_count_in_dir_alt",
"file_empty_alt",
"file_ext_alt",
"file_grep_alt",
"file_hash_alt",
"file_head_alt",
"file_lines_count_alt",
"file_mtime_alt",
"file_replace_alt",
"file_size_alt",
"file_size_human_alt",
"file_stem_alt",
"file_tail_alt",
"file_words_count_alt",
"file_writable_alt",
"find_files_alt",
"find_index_alt",
"first_alt",
"first_word_alt",
"floor_alt",
"fmax_alt",
"fmin_alt",
"foreach_alt",
"format_alt",
"format_bytes_alt",
"format_duration_alt",
"format_number_alt",
"form_encode_alt",
"from_bin_alt",
"from_hex_alt",
"from_unix_alt",
"func_alt",
"gcd_alt",
"gcd3_alt",
"get_alt",
"getenv_alt",
"getf_alt",
"gethome_alt",
"getuser_alt",
"gotoxy_alt",
"gui_alpha_pixel_alt",
"gui_blit_ppm_alt",
"gui_circle_alt",
"gui_clear_alt",
"gui_clear_rect_alt",
"gui_ellipse_alt",
"gui_fill_circle_alt",
"gui_fill_rect_alt",
"gui_fill_triangle_alt",
"gui_fps_alt",
"gui_get_pixel_alt",
"gui_gradient_rect_alt",
"gui_is_focused_alt",
"gui_key_down_alt",
"gui_line_alt",
"gui_mouse_down_alt",
"gui_mouse_wheel_alt",
"gui_mouse_x_alt",
"gui_mouse_y_alt",
"gui_native_alt",
"gui_open_alt",
"gui_pixel_alt",
"gui_polygon_alt",
"gui_rect_alt",
"gui_screenshot_alt",
"gui_set_title_alt",
"gui_show_alt",
"gui_text_alt",
"gui_text_big_alt",
"gui_text_width_alt",
"gui_thick_line_alt",
"gui_window_alt",
"gui_window_h_alt",
"gui_window_w_alt",
"hamming_distance_alt",
"has_var_alt",
"hex_decode_alt",
"hex_encode_alt",
"hmac_sha256_alt",
"hostname_alt",
"hour_now_alt",
"hr_alt",
"html_escape_alt",
"http_delete_alt",
"http_get_alt",
"http_post_alt",
"http_put_alt",
"hypot_alt",
"if_alt",
"implements_alt",
"importayaan_alt",
"importpkg_alt",
"incr_alt",
"inspect_alt",
"instanceof_alt",
"interface_alt",
"int_to_ip_alt",
"ip_to_int_alt",
"ip_v4_check_alt",
"iqr_alt",
"is_alnum_alt",
"is_alpha_alt",
"is_anagram_alt",
"is_ascii_alt",
"is_digit_alt",
"is_dir_alt",
"is_even_alt",
"is_file_alt",
"is_leap_year_alt",
"is_lower_alt",
"is_odd_alt",
"is_palindrome_alt",
"is_prime_alt",
"is_root_alt",
"is_today_alt",
"is_upper_alt",
"is_weekend_alt",
"is_whitespace_alt",
"jaccard_alt",
"joinpath_alt",
"jscall_alt",
"json_alt",
"json_escape_str_alt",
"json_get_path_alt",
"json_parse_alt",
"json_pretty_alt",
"json_stringify_alt",
"lall_neg_alt",
"lall_pos_alt",
"lall_zero_alt",
"lambda_alt",
"lang_env_alt",
"lany_pos_alt",
"lany_zero_alt",
"last_alt",
"last_word_alt",
"lavg_alt",
"lchoice_alt",
"lclear_alt",
"lcm_alt",
"lcompact_alt",
"lconcat_alt",
"lcontains_alt",
"lcopy_alt",
"lcount_eq_alt",
"lcount_neg_alt",
"lcount_pos_alt",
"lcount_zero_alt",
"lcumprod_alt",
"lcumsum_alt",
"ld_get_alt",
"ldiff_lists_alt",
"ldrop_alt",
"ld_set_alt",
"left_alt",
"lerp_alt",
"letter_freq_alt",
"levenshtein_alt",
"lextend_alt",
"lfill_alt",
"lget_alt",
"lindex_alt",
"linit_alt",
"linsert_alt",
"lis_sorted_alt",
"list_alt",
"listdir_alt",
"lis_unique_alt",
"ljoin_alt",
"lmax_alt",
"lmedian_alt",
"lmin_alt",
"loadenv_alt",
"local_ip_alt",
"log_alt",
"log_base_alt",
"logfile_alt",
"lones_alt",
"longest_common_alt",
"lower_alt",
"lpartition_alt",
"lpop_front_alt",
"lprepend_alt",
"lprint_alt",
"lproduct_alt",
"lremove_alt",
"lremove_at_alt",
"lreplace_all_alt",
"lreverse_alt",
"lreverse_copy_alt",
"lscan_alt",
"lset_alt",
"lshuffle_alt",
"lsize_alt",
"lsort_alt",
"lstddev_alt",
"lsum_alt",
"lswap_alt",
"ltail_alt",
"ltake_alt",
"lunique_alt",
"lvariance_alt",
"lwindow_alt",
"lzeros_alt",
"lzip_alt",
"mac_format_alt",
"manhattan_alt",
"map_range_alt",
"matchv_alt",
"max_alt",
"max_var_alt",
"md5_alt",
"method_alt",
"midnight_today_alt",
"min_alt",
"minute_now_alt",
"min_var_alt",
"mkdir_alt",
"mod_pow_alt",
"module_alt",
"month_alt",
"monthname_alt",
"months_between_alt",
"move_alt",
"new_alt",
"noop_alt",
"normalize_alt",
"normalize_path_alt",
"note_alt",
"now_alt",
"now_iso_alt",
"now_minus_days_alt",
"now_plus_days_alt",
"nproc_alt",
"nth_prime_alt",
"nth_root_alt",
"nth_word_alt",
"ord_alt",
"os_family_alt",
"os_name_alt",
"pad_alt",
"pad_left_alt",
"panic_alt",
"parse_query_alt",
"percentile_alt",
"percentile_25_alt",
"percentile_75_alt",
"perms_alt",
"phi_alt",
"pi_alt",
"pid_alt",
"ping_alt",
"pkg_asset_path_alt",
"pkg_asset_read_alt",
"pkg_db_open_alt",
"pkg_run_sql_alt",
"platform_alt",
"play_alt",
"pop_alt",
"post_alt",
"pow_alt",
"prime_factors_alt",
"primes_up_to_alt",
"printf_alt",
"progress_alt",
"public_ip_alt",
"push_alt",
"put_alt",
"pwd_alt",
"pycall_alt",
"quarter_of_alt",
"rad_to_deg_alt",
"raise_alt",
"rand_bool_alt",
"rand_digit_alt",
"rand_float_alt",
"rand_hex_char_alt",
"rand_letter_alt",
"random_bytes_alt",
"random_ipv4_alt",
"random_mac_alt",
"random_password_alt",
"random_port_alt",
"rand_uppercase_alt",
"range_alt",
"range_stat_alt",
"readfile_alt",
"read_first_line_alt",
"read_last_line_alt",
"read_lines_alt",
"redirect_alt",
"regex_all_matches_alt",
"regex_capture_alt",
"regex_match_alt",
"regex_replace_alt",
"repeat_alt",
"repeat_call_alt",
"repeat_print_alt",
"repeat_str_alt",
"replace_alt",
"retry_alt",
"return_alt",
"reverse_alt",
"rgb_alt",
"right_alt",
"rm_alt",
"rmdir_alt",
"rot13_alt",
"round_alt",
"round_to_alt",
"route_alt",
"second_now_alt",
"selfget_alt",
"selfset_alt",
"send_alt",
"serve_alt",
"servefile_alt",
"set_diff_alt",
"setenv_alt",
"set_eq_alt",
"setf_alt",
"set_int_alt",
"set_intersect_alt",
"set_string_alt",
"set_union_alt",
"sha1_alt",
"sha256_alt",
"sha512_alt",
"shell_escape_alt",
"shell_name_alt",
"shl_alt",
"shr_alt",
"sign_alt",
"sleep_ms_alt",
"sparkline_alt",
"spawn_alt",
"spin_alt",
"split_alt",
"sqrt_alt",
"sqrt2_alt",
"startswith_alt",
"static_alt",
"status_alt",
"str_chunk_alt",
"str_eq_ci_alt",
"strip_left_alt",
"strip_right_alt",
"str_is_float_alt",
"str_is_int_alt",
"str_is_numeric_alt",
"strlen_alt",
"str_lines_alt",
"str_pad_zero_alt",
"substr_alt",
"sum_alt",
"swap_vars_alt",
"switch_alt",
"table_alt",
"tau_alt",
"term_name_var_alt",
"term_size_alt",
"test_fail_alt",
"test_pass_alt",
"test_skip_alt",
"time_end_alt",
"times_alt",
"timestamp_ms_alt",
"time_start_alt",
"title_alt",
"titlebar_alt",
"to_bin_alt",
"to_constant_alt",
"todo_alt",
"toggle_alt",
"to_hex_alt",
"to_int_alt",
"tomorrow_iso_alt",
"to_oct_alt",
"to_pascal_alt",
"to_str_alt",
"tostring_alt",
"touch_alt",
"to_unix_alt",
"triangular_alt",
"trim_alt",
"trunc_alt",
"truncate_alt",
"type_of_alt",
"typeof_alt",
"unset_var_alt",
"upper_alt",
"uppercase_alt",
"uptime_alt",
"url_escape_alt",
"url_host_alt",
"url_path_alt",
"url_query_alt",
"url_scheme_alt",
"uuid_alt",
"vprint_alt",
"warn_alt",
"watchfile_alt",
"weekday_alt",
"week_of_year_alt",
"which_alt",
"while_alt",
"word_freq_alt",
"words_alt",
"writefile_alt",
"write_lines_alt",
"ws_broadcast_alt",
"ws_clients_alt",
"ws_last_alt",
"ws_recv_alt",
"ws_send_alt",
"ws_serve_alt",
"year_alt",
"years_between_alt",
"yesterday_iso_alt",
"zero_var_alt",
"abs_alt2",
"abspath_alt2",
"add_days_alt2",
"append_file_alt2",
"arch_name_alt2",
"arrow_down_alt2",
"arrow_left_alt2",
"arrow_right_alt2",
"arrow_up_alt2",
"askstring_alt2",
"askyesno_alt2",
"assert_alt2",
"assert_eq_alt2",
"assert_gt_alt2",
"assert_lt_alt2",
"assert_ne_alt2",
"async_alt2",
"atan2_alt2",
"atbash_alt2",
"avg_alt2",
"await_alt2",
"backup_file_alt2",
"band_alt2",
"banner_alt2",
"barchart_alt2",
"base64_decode_alt2",
"base64_encode_alt2",
"basename_alt2",
"benchmark_alt2",
"bgrgb_alt2",
"bnot_alt2",
"bor_alt2",
"box_alt2",
"bxor_alt2",
"caesar_decode_alt2",
"caesar_encode_alt2",
"calc_alt2",
"call_alt2",
"capitalize_alt2",
"catch_alt2",
"ceil_alt2",
"center_alt2",
"chars_alt2",
"choose_alt2",
"chr_alt2",
"clamp_alt2",
"clamp_int_alt2",
"class_alt2",
"coin_alt2",
"color_alt2",
"concat_alt2",
"const_alt2",
"contains_alt2",
"contains_all_alt2",
"contains_any_alt2",
"copy_alt2",
"copy_var_alt2",
"countdown_alt2",
"count_lines_matching_alt2",
"count_substr_alt2",
"countup_alt2",
"count_words_alt2",
"crc32_alt2",
"ctype_alt2",
"d20_alt2",
"d6_alt2",
"datefmt_alt2",
"date_today_alt2",
"date_tomorrow_alt2",
"date_yesterday_alt2",
"day_alt2",
"dayname_alt2",
"dayofyear_alt2",
"days_in_month_alt2",
"days_in_year_alt2",
"db_begin_alt2",
"db_close_alt2",
"db_commit_alt2",
"db_count_alt2",
"db_exec_alt2",
"db_exists_alt2",
"db_insert_alt2",
"db_open_alt2",
"db_query_alt2",
"db_rollback_alt2",
"db_tables_alt2",
"dclear_alt2",
"dcount_value_alt2",
"ddel_alt2",
"decr_alt2",
"deg_to_rad_alt2",
"delete_alt2",
"dget_alt2",
"dhas_alt2",
"dict_alt2",
"diff_days_alt2",
"dincr_alt2",
"dinvert_alt2",
"dir_exists_alt2",
"dirname_alt2",
"distance_alt2",
"divider_alt2",
"dkeys_alt2",
"dmerge_alt2",
"docs_alt2",
"domit_alt2",
"download_alt2",
"dpairs_alt2",
"dpick_alt2",
"dpop_alt2",
"dprint_alt2",
"dset_alt2",
"dsize_alt2",
"dvalues_alt2",
"e_alt2",
"echo_alt2",
"endswith_alt2",
"ensure_dir_alt2",
"enum_alt2",
"env_dict_alt2",
"env_list_alt2",
"env_size_alt2",
"exec_alt2",
"exists_alt2",
"extname_alt2",
"factorial_alt2",
"ffi_alt2",
"fficall_alt2",
"ffiload_alt2",
"fibonacci_alt2",
"field_alt2",
"file_age_alt2",
"file_count_in_dir_alt2",
"file_empty_alt2",
"file_ext_alt2",
"file_grep_alt2",
"file_hash_alt2",
"file_head_alt2",
"file_lines_count_alt2",
"file_mtime_alt2",
"file_replace_alt2",
"file_size_alt2",
"file_size_human_alt2",
"file_stem_alt2",
"file_tail_alt2",
"file_words_count_alt2",
"file_writable_alt2",
"find_files_alt2",
"find_index_alt2",
"first_alt2",
"first_word_alt2",
"floor_alt2",
"fmax_alt2",
"fmin_alt2",
"foreach_alt2",
"format_alt2",
"format_bytes_alt2",
"format_duration_alt2",
"format_number_alt2",
"form_encode_alt2",
"from_bin_alt2",
"from_hex_alt2",
"from_unix_alt2",
"func_alt2",
"gcd_alt2",
"gcd3_alt2",
"get_alt2",
"getenv_alt2",
"getf_alt2",
"gethome_alt2",
"getuser_alt2",
"gotoxy_alt2",
"gui_alpha_pixel_alt2",
"gui_blit_ppm_alt2",
"gui_circle_alt2",
"gui_clear_alt2",
"gui_clear_rect_alt2",
"gui_ellipse_alt2",
"gui_fill_circle_alt2",
"gui_fill_rect_alt2",
"gui_fill_triangle_alt2",
"gui_fps_alt2",
"gui_get_pixel_alt2",
"gui_gradient_rect_alt2",
"gui_is_focused_alt2",
"gui_key_down_alt2",
"gui_line_alt2",
"gui_mouse_down_alt2",
"gui_mouse_wheel_alt2",
"gui_mouse_x_alt2",
"gui_mouse_y_alt2",
"gui_native_alt2",
"gui_open_alt2",
"gui_pixel_alt2",
"gui_polygon_alt2",
"gui_rect_alt2",
"gui_screenshot_alt2",
"gui_set_title_alt2",
"gui_show_alt2",
"gui_text_alt2",
"gui_text_big_alt2",
"gui_text_width_alt2",
"gui_thick_line_alt2",
"gui_window_alt2",
"gui_window_h_alt2",
"gui_window_w_alt2",
"hamming_distance_alt2",
"has_var_alt2",
"hex_decode_alt2",
"hex_encode_alt2",
"hmac_sha256_alt2",
"hostname_alt2",
"hour_now_alt2",
"hr_alt2",
"html_escape_alt2",
"http_delete_alt2",
"http_get_alt2",
"http_post_alt2",
"http_put_alt2",
"hypot_alt2",
"if_alt2",
"implements_alt2",
"importayaan_alt2",
"importpkg_alt2",
"incr_alt2",
"inspect_alt2",
"instanceof_alt2",
"interface_alt2",
"int_to_ip_alt2",
"ip_to_int_alt2",
"ip_v4_check_alt2",
"iqr_alt2",
"is_alnum_alt2",
"is_alpha_alt2",
"is_anagram_alt2",
"is_ascii_alt2",
"is_digit_alt2",
"is_dir_alt2",
"is_even_alt2",
"is_file_alt2",
"is_leap_year_alt2",
"is_lower_alt2",
"is_odd_alt2",
"is_palindrome_alt2",
"is_prime_alt2",
"is_root_alt2",
"is_today_alt2",
"is_upper_alt2",
"is_weekend_alt2",
"is_whitespace_alt2",
"jaccard_alt2",
"joinpath_alt2",
"jscall_alt2",
"json_alt2",
"json_escape_str_alt2",
"json_get_path_alt2",
"json_parse_alt2",
"json_pretty_alt2",
"json_stringify_alt2",
"lall_neg_alt2",
"lall_pos_alt2",
"lall_zero_alt2",
"lambda_alt2",
];

fn levenshtein(a: &str, b: &str) -> usize {
    let av: Vec<char> = a.chars().collect();
    let bv: Vec<char> = b.chars().collect();
    let (m, n) = (av.len(), bv.len());
    if m == 0 {
        return n;
    }
    if n == 0 {
        return m;
    }
    let mut dp = vec![vec![0usize; n + 1]; m + 1];
    for i in 0..=m {
        dp[i][0] = i;
    }
    for j in 0..=n {
        dp[0][j] = j;
    }
    for i in 1..=m {
        for j in 1..=n {
            let cost = if av[i - 1] == bv[j - 1] { 0 } else { 1 };
            dp[i][j] = std::cmp::min(
                std::cmp::min(dp[i - 1][j] + 1, dp[i][j - 1] + 1),
                dp[i - 1][j - 1] + cost,
            );
        }
    }
    dp[m][n]
}

fn find_similar(input: &str) -> Option<&'static str> {
    if input.is_empty() {
        return None;
    }
    let target = input.to_lowercase();
    let mut best: Option<(&'static str, usize)> = None;
    for cmd in KNOWN_COMMANDS {
        let d = levenshtein(&target, cmd);
        let threshold: usize = if cmd.len() <= 4 {
            1
        } else if cmd.len() <= 8 {
            2
        } else {
            3
        };
        if d <= threshold {
            match best {
                None => best = Some((cmd, d)),
                Some((_, bd)) if d < bd => best = Some((cmd, d)),
                _ => {}
            }
        }
    }
    best.map(|(c, _)| c)
}

fn print_command_help() {
    let y = "\x1b[1;33m";
    let c = "\x1b[36m";
    let d = "\x1b[2m";
    let r = "\x1b[0m";

    println!();
    println!("  {y}AyaanScript+ command reference{r}");
    println!();
    println!("  {c}Output / strings{r}");
    println!("    psyska -/ \"text\"        print");
    println!("    reverse \"text\"          reverse and print");
    println!("    uppercase \"text\"        uppercase and print");
    println!("    clear                   clear screen");
    println!("    sleep N                 sleep N seconds");
    println!();
    println!("  {c}Variables / math{r}");
    println!("    set var = N             assign int");
    println!("    add var, N              increment");
    println!("    calc EXPR               evaluate and print");
    println!("    rand var min max        random int in range");
    println!();
    println!("  {c}Input{r}");
    println!("    asknum var [write]      prompt int; 'write' bakes value into file");
    println!("    pause                   wait for Enter");
    println!("    waitkey [var]           wait for any keypress");
    println!();
    println!("  {c}Files / imports{r}");
    println!("    writefile \"file\" \"content\"   write a file");
    println!("    readfile var \"file\"          read and print");
    println!("    importayaan \"path\"           run another .ayaan file");
    println!("    importpkg name               run an installed aspkg");
    println!();
    println!("  {c}Classes / OOP{r}");
    println!("    class Name [extends Parent] … endclass   define class");
    println!("    field name = default                     instance field");
    println!("    static field name = default              class-level field");
    println!("    method name p1 p2 … endmethod            instance method");
    println!("    static method name p1 … endmethod        class-level method");
    println!("    new inst = Class(arg1, arg2)             instantiate w/ init args");
    println!("    setf inst.field = value                  set field");
    println!("    getf inst.field                          print field");
    println!("    call inst.method args                    invoke method");
    println!("    call inst.method args -> result          capture return value");
    println!("    call super.method args                   call parent method");
    println!("    call Class.staticmethod args             call static");
    println!("    return value                             return from func/method");
    println!("    selfget / selfset                        inside methods");
    println!("    instanceof inst Class [-> var]           runtime type check");
    println!("    typeof name [-> var]                     get class/type of name");
    println!("    {d}Inside methods, bare field names auto-resolve to self.{r}");
    println!();
    println!("  {c}Control flow{r}");
    println!("    if EXPR … else … endif       conditional");
    println!("    repeat N [var] … endrepeat   loop N times");
    println!("    while EXPR … endwhile        loop while true");
    println!("    break / continue             skip / exit loops");
    println!("    func name p1 p2 … endfunc    define function");
    println!("    call name arg1 arg2          run function");
    println!("    exit                         stop the script");
    println!();
    println!("  {c}FFI / external{r}");
    println!("    exec \"cmd\"                   run shell command");
    println!("    ffi var = \"cmd\"              capture shell output");
    println!("    pycall var = \"code\"          run Python expression");
    println!("    jscall var = \"code\"          run JS expression");
    println!("    ffiload alias \"path.so\"      load C library");
    println!("    fficall alias.fn args -> r   call C function");
    println!();
    println!("  {c}HTTP server{r}");
    println!("    serport = N                  start config");
    println!("    route/get/post/put/delete \"/p\"  pick route");
    println!("    serve / servefile / json / redirect");
    println!("    static \"dir\"   end           static dir / start");
    println!();
    println!("  {d}Strings use {{interpolation}} with math/format. Try {y}.help{d} for REPL commands.{r}");
    println!();
}

fn merge_multiline_strings(content: &str) -> Vec<String> {
    let mut out: Vec<String> = Vec::new();
    let mut buf: Option<String> = None;
    for line in content.lines() {
        if let Some(b) = buf.as_mut() {
            b.push('\n');
            b.push_str(line);
            if line.contains("\"\"\"") {
                let merged = b.replacen("\"\"\"", "\"", 1);
                let final_str = if let Some(idx) = merged.rfind("\"\"\"") {
                    let before = &merged[..idx];
                    let after = &merged[idx + 3..];
                    format!("{}\"{}", before, after)
                } else {
                    merged
                };
                out.push(final_str);
                buf = None;
            }
            continue;
        }
        let open_count = line.matches("\"\"\"").count();
        if open_count == 1 {
            buf = Some(line.to_string());
        } else if open_count >= 2 {
            let mut transformed = line.replacen("\"\"\"", "\"", 1);
            if let Some(idx) = transformed.find("\"\"\"") {
                transformed = format!("{}\"{}", &transformed[..idx], &transformed[idx + 3..]);
            }
            out.push(transformed);
        } else {
            out.push(line.to_string());
        }
    }
    if let Some(b) = buf {
        out.push(b);
    }
    out
}

fn run_script_content(
    content: &str,
    dir: PathBuf,
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
) -> bool {
    oop.script_dir_stack.push(dir);
    let mut keep_going = true;
    let lines = merge_multiline_strings(content);
    let saved_line = oop.current_line_no;
    for (idx, l) in lines.iter().enumerate() {
        oop.current_line_no = (idx + 1) as u32;
        if !execute(l, vars, server_cfg, oop) {
            keep_going = false;
            break;
        }
    }
    oop.current_line_no = saved_line;
    oop.script_dir_stack.pop();
    keep_going
}

fn run_script_file(
    path: &Path,
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
) -> bool {
    let data = match fs::read_to_string(path) {
        Ok(d) => d,
        Err(e) => {
            println!("Import failed: {} ({})", path.display(), e);
            return true;
        }
    };

    let dir = path
        .parent()
        .map(|p| p.to_path_buf())
        .unwrap_or_else(|| PathBuf::from("."));

    // Remember the source path so error messages can reference it.
    let saved_file = oop.current_file.take();
    oop.current_file = Some(path.display().to_string());
    let result = run_top_level(&data, dir, vars, server_cfg, oop);
    oop.current_file = saved_file;
    result
}

fn is_bundle(text: &str) -> bool {
    text.lines().any(|l| l.trim().starts_with("---file:"))
}

fn parse_bundle(content: &str) -> (HashMap<String, String>, Option<String>) {
    let mut files: HashMap<String, String> = HashMap::new();
    let mut main_name: Option<String> = None;
    let mut current_file: Option<String> = None;
    let mut current_content = String::new();

    for line in content.lines() {
        let trimmed = line.trim();

        if let Some(after) = trimmed.strip_prefix("---file:") {
            let name = after.trim_end_matches("---").trim().to_string();
            if let Some(prev) = current_file.take() {
                files.insert(prev, current_content.clone());
            }
            current_content.clear();
            current_file = Some(name);
            continue;
        }

        if current_file.is_none() {
            if let Some(rest) = trimmed.strip_prefix("@main ") {
                main_name = Some(rest.trim().to_string());
            }
            continue;
        }

        current_content.push_str(line);
        current_content.push('\n');
    }

    if let Some(name) = current_file {
        files.insert(name, current_content);
    }

    (files, main_name)
}

fn run_top_level(
    text: &str,
    dir: PathBuf,
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
) -> bool {
    if is_bundle(text) {
        let (files, main_name) = parse_bundle(text);
        let main = main_name.unwrap_or_else(|| "main.ayaan".to_string());
        let main_content = match files.get(&main).cloned() {
            Some(c) => c,
            None => {
                println!("Bundle missing main file '{}'", main);
                return true;
            }
        };
        oop.bundle_stack.push(VirtualBundle { files });
        let ok = run_script_content(&main_content, dir, vars, server_cfg, oop);
        oop.bundle_stack.pop();
        ok
    } else {
        run_script_content(text, dir, vars, server_cfg, oop)
    }
}

fn first_quoted(s: &str) -> Option<String> {
    let start = s.find('"')?;
    let rest = &s[start + 1..];
    let end = rest.find('"')?;
    Some(rest[..end].to_string())
}

fn find_method_in_chain(
    classes: &HashMap<String, ClassDef>,
    class_name: &str,
    method_name: &str,
    start_above: Option<&str>,
) -> Option<(String, MethodDef)> {
    let mut current = if let Some(skip) = start_above {
        classes.get(skip).and_then(|c| c.parent.clone())
    } else {
        Some(class_name.to_string())
    };

    while let Some(cname) = current {
        if let Some(c) = classes.get(&cname) {
            if let Some(m) = c.methods.get(method_name) {
                return Some((cname.clone(), m.clone()));
            }
            current = c.parent.clone();
        } else {
            return None;
        }
    }
    None
}

fn collect_inherited_fields(
    classes: &HashMap<String, ClassDef>,
    class_name: &str,
) -> Vec<(String, String)> {
    let mut chain: Vec<&ClassDef> = Vec::new();
    let mut current = Some(class_name.to_string());
    while let Some(cname) = current {
        if let Some(c) = classes.get(&cname) {
            chain.push(c);
            current = c.parent.clone();
        } else {
            break;
        }
    }
    let mut out = Vec::new();
    for c in chain.iter().rev() {
        for (n, v) in &c.fields {
            if !out.iter().any(|(en, _): &(String, String)| en == n) {
                out.push((n.clone(), v.clone()));
            }
        }
    }
    out
}

fn apply_return(
    vars: &mut Vars,
    oop: &mut OopState,
    result_var: Option<String>,
    value: Option<String>,
) {
    let target = match result_var {
        Some(v) => v,
        None => return,
    };
    let v = value.unwrap_or_default();
    if let Ok(n) = v.parse::<i64>() {
        vars.insert(target.clone(), n);
        oop.string_vars.remove(&target);
    } else if v.parse::<f64>().is_ok() {
        // preserve float precision as a string var — truncating to i64
        // here breaks float accumulation when scripts read lists with
        // velocities like 3.5 or angles like 0.012
        oop.string_vars.insert(target.clone(), v);
        vars.remove(&target);
    } else {
        oop.string_vars.insert(target.clone(), v);
        vars.remove(&target);
    }
}

// v2.0 helpers for functional list operations (map/filter/reduce).
// Call a top-level `func` by name with a single argument, return its `result`.
fn call_named_func_1arg(
    fn_name: &str,
    arg: &str,
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
) -> Option<String> {
    call_named_func_n(fn_name, &[arg.to_string()], vars, server_cfg, oop)
}

fn call_named_func_2arg(
    fn_name: &str,
    a: &str,
    b: &str,
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
) -> Option<String> {
    call_named_func_n(fn_name, &[a.to_string(), b.to_string()], vars, server_cfg, oop)
}

// Generic n-arg named function invoker. Binds args to the function's declared
// params, runs the body, and returns the value of `result` (or `return`) at
// completion. Cleans up param bindings whether or not the call succeeded.
fn call_named_func_n(
    fn_name: &str,
    args: &[String],
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
) -> Option<String> {
    let func = oop.functions.get(fn_name).cloned()?;
    let mut saved: Vec<(String, Option<String>)> = Vec::new();
    for (i, param) in func.params.iter().enumerate() {
        saved.push((param.clone(), oop.string_vars.get(param).cloned()));
        let val = args.get(i).cloned().unwrap_or_default();
        oop.string_vars.insert(param.clone(), val);
    }
    // Also clear any lingering `result` from a previous call so we can
    // distinguish "func didn't set result" from stale state. Clean both
    // storages — `result` may be int (vars) or string (string_vars).
    let prev_result_str = oop.string_vars.remove("result");
    let prev_result_int = vars.remove("result");
    let save_return = oop.return_flag;
    let save_retval = oop.return_value.take();
    oop.return_flag = false;
    for body_line in &func.body {
        if !execute(body_line, vars, server_cfg, oop) {
            break;
        }
        if oop.return_flag {
            break;
        }
    }
    // Prefer explicit `return X`, fall back to `result` variable.
    // `result` may live in `vars` (integer) OR `string_vars` (string/float).
    let captured = oop.return_value.take()
        .or_else(|| oop.string_vars.get("result").cloned())
        .or_else(|| vars.get("result").map(|n| n.to_string()));
    oop.return_flag = save_return;
    oop.return_value = save_retval;
    // Restore params
    for (name, prev) in saved {
        match prev {
            Some(v) => { oop.string_vars.insert(name, v); }
            None => { oop.string_vars.remove(&name); }
        }
    }
    // Restore prior result state in both storages.
    oop.string_vars.remove("result");
    vars.remove("result");
    if let Some(v) = prev_result_str { oop.string_vars.insert("result".to_string(), v); }
    if let Some(n) = prev_result_int { vars.insert("result".to_string(), n); }
    captured
}

fn capture_call_return(
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
    self_name: Option<String>,
    method: &MethodDef,
    raw_args: &[String],
    method_owner: Option<String>,
) -> (bool, Option<String>) {
    let mut saved: Vec<(String, Option<String>)> = Vec::new();
    for (i, param) in method.params.iter().enumerate() {
        saved.push((param.clone(), oop.string_vars.get(param).cloned()));
        let arg_raw = raw_args.get(i).cloned().unwrap_or_default();
        let resolved = resolve_arg(&arg_raw, vars, oop);
        oop.string_vars.insert(param.clone(), resolved);
    }

    let save_break = oop.break_flag;
    let save_continue = oop.continue_flag;
    let save_return = oop.return_flag;
    let save_retval = oop.return_value.take();
    oop.break_flag = false;
    oop.continue_flag = false;
    oop.return_flag = false;

    if let Some(sn) = self_name.clone() {
        oop.self_stack.push(sn.clone());
        let owner_name = method_owner.as_deref().unwrap_or("?");
        oop.call_trace.push(format!("{}.<method on {}>", owner_name, sn));
    } else {
        let owner_name = method_owner.as_deref().unwrap_or("?");
        oop.call_trace.push(format!("{}.<static>", owner_name));
    }
    let pushed_owner = method_owner.is_some();
    if let Some(o) = method_owner {
        oop.method_owner_stack.push(o);
    }

    let mut keep_going = true;
    for body_line in &method.body {
        if !execute(body_line, vars, server_cfg, oop) {
            keep_going = false;
            break;
        }
        if oop.return_flag {
            break;
        }
    }

    if pushed_owner {
        oop.method_owner_stack.pop();
    }
    if self_name.is_some() {
        oop.self_stack.pop();
    }
    oop.call_trace.pop();

    let captured = oop.return_value.take();
    oop.return_flag = save_return;
    oop.return_value = save_retval;
    oop.break_flag = save_break;
    oop.continue_flag = save_continue;

    for (name, prev) in saved {
        match prev {
            Some(v) => {
                oop.string_vars.insert(name, v);
            }
            None => {
                oop.string_vars.remove(&name);
            }
        }
    }

    (keep_going, captured)
}

fn json_to_str(v: &serde_json::Value) -> String {
    match v {
        serde_json::Value::Null => String::new(),
        serde_json::Value::Bool(b) => b.to_string(),
        serde_json::Value::Number(n) => n.to_string(),
        serde_json::Value::String(s) => s.clone(),
        other => other.to_string(),
    }
}

fn print_progress(n: i64, total: i64, label: &str) {
    let width: usize = 30;
    let pct = (n as f64 / total as f64).max(0.0).min(1.0);
    let filled = (pct * width as f64).round() as usize;
    let bar: String = "█".repeat(filled) + &"░".repeat(width - filled);
    print!("\r{} [{}] {}/{} ({:>3.0}%)", label, bar, n, total, pct * 100.0);
    let _ = io::stdout().flush();
    if n >= total {
        println!();
    }
}

fn print_box(title: &str, content: &str) {
    let lines: Vec<&str> = content.lines().collect();
    let mut max_w = title.chars().count();
    for l in &lines {
        max_w = max_w.max(l.chars().count());
    }
    let inner = max_w + 2;
    let bar: String = "═".repeat(inner);
    println!("╔{}╗", bar);
    let t_pad = inner.saturating_sub(title.chars().count());
    let lp = t_pad / 2;
    let rp = t_pad - lp;
    println!("║{}{}{}║", " ".repeat(lp), title, " ".repeat(rp));
    println!("╠{}╣", bar);
    for l in &lines {
        let pad = inner.saturating_sub(l.chars().count() + 1);
        println!("║ {}{}║", l, " ".repeat(pad));
    }
    println!("╚{}╝", bar);
}

fn print_banner(text: &str) {
    let glyphs: HashMap<char, &[&str; 5]> = [
        ('A', &[" █████ ", "██   ██", "███████", "██   ██", "██   ██"]),
        ('B', &["██████ ", "██   ██", "██████ ", "██   ██", "██████ "]),
        ('C', &[" █████ ", "██     ", "██     ", "██     ", " █████ "]),
        ('D', &["██████ ", "██   ██", "██   ██", "██   ██", "██████ "]),
        ('E', &["███████", "██     ", "█████  ", "██     ", "███████"]),
        ('F', &["███████", "██     ", "█████  ", "██     ", "██     "]),
        ('G', &[" █████ ", "██     ", "██  ███", "██   ██", " █████ "]),
        ('H', &["██   ██", "██   ██", "███████", "██   ██", "██   ██"]),
        ('I', &["██", "██", "██", "██", "██"]),
        ('J', &["     ██", "     ██", "     ██", "██   ██", " █████ "]),
        ('K', &["██   ██", "██  ██ ", "█████  ", "██  ██ ", "██   ██"]),
        ('L', &["██     ", "██     ", "██     ", "██     ", "███████"]),
        ('M', &["███    ███", "████  ████", "██ ████ ██", "██  ██  ██", "██      ██"]),
        ('N', &["███    ██", "████   ██", "██ ██  ██", "██  ██ ██", "██   ████"]),
        ('O', &[" █████ ", "██   ██", "██   ██", "██   ██", " █████ "]),
        ('P', &["██████ ", "██   ██", "██████ ", "██     ", "██     "]),
        ('Q', &[" █████ ", "██   ██", "██   ██", "██ █ ██", " ███ ██"]),
        ('R', &["██████ ", "██   ██", "██████ ", "██   ██", "██   ██"]),
        ('S', &[" █████ ", "██     ", " █████ ", "     ██", " █████ "]),
        ('T', &["████████", "   ██   ", "   ██   ", "   ██   ", "   ██   "]),
        ('U', &["██   ██", "██   ██", "██   ██", "██   ██", " █████ "]),
        ('V', &["██   ██", "██   ██", "██   ██", " ██ ██ ", "  ███  "]),
        ('W', &["██     ██", "██     ██", "██  █  ██", "██ ███ ██", " ███ ███ "]),
        ('X', &["██   ██", " ██ ██ ", "  ███  ", " ██ ██ ", "██   ██"]),
        ('Y', &["██   ██", " ██ ██ ", "  ███  ", "   █   ", "   █   "]),
        ('Z', &["███████", "    ██ ", "   ██  ", "  ██   ", "███████"]),
        ('0', &[" ████  ", "██  ██ ", "██  ██ ", "██  ██ ", " ████  "]),
        ('1', &["  ██  ", " ███  ", "  ██  ", "  ██  ", "██████"]),
        ('2', &[" ████ ", "██  ██", "   ██ ", "  ██  ", "██████"]),
        ('3', &["█████ ", "    ██", " ████ ", "    ██", "█████ "]),
        ('4', &["██  ██", "██  ██", "██████", "    ██", "    ██"]),
        ('5', &["██████", "██    ", "█████ ", "    ██", "█████ "]),
        ('6', &[" ████ ", "██    ", "█████ ", "██  ██", " ████ "]),
        ('7', &["██████", "    ██", "   ██ ", "  ██  ", " ██   "]),
        ('8', &[" ████ ", "██  ██", " ████ ", "██  ██", " ████ "]),
        ('9', &[" ████ ", "██  ██", " █████", "    ██", " ████ "]),
        (' ', &["   ", "   ", "   ", "   ", "   "]),
        ('!', &["██", "██", "██", "  ", "██"]),
        ('?', &["█████ ", "    ██", "   ██ ", "      ", "  ██  "]),
        ('.', &["  ", "  ", "  ", "  ", "██"]),
        (',', &["  ", "  ", "  ", "██", "█ "]),
        ('-', &["    ", "    ", "████", "    ", "    "]),
        ('+', &["   ", " █ ", "███", " █ ", "   "]),
    ]
    .iter()
    .cloned()
    .collect();

    let upper = text.to_uppercase();
    let chars: Vec<char> = upper.chars().collect();
    for row in 0..5 {
        let mut line = String::new();
        for c in &chars {
            let g = glyphs.get(c).copied().unwrap_or(&["?","?","?","?","?"]);
            line.push_str(g[row]);
            line.push(' ');
        }
        println!("{}", line);
    }
}

fn resolve_arg(arg: &str, vars: &Vars, oop: &OopState) -> String {
    let trimmed = arg.trim();
    if trimmed.is_empty() {
        return String::new();
    }
    if trimmed.starts_with('"') && trimmed.ends_with('"') && trimmed.len() >= 2 {
        let inner = unescape_string(&trimmed[1..trimmed.len() - 1]);
        return interpolate(&inner, vars, oop);
    }
    if trimmed.contains('{') {
        return interpolate(trimmed, vars, oop);
    }
    if let Ok(n) = trimmed.parse::<i64>() {
        return n.to_string();
    }
    if let Ok(f) = trimmed.parse::<f64>() {
        return f.to_string();
    }
    if let Some(v) = lookup_simple(trimmed, vars, oop) {
        return v;
    }
    if let Some(v) = eval_expression(trimmed, vars, oop) {
        return v;
    }
    trimmed.to_string()
}

// ===== NATIVE GUI (minifb) =====
use std::cell::{Cell, RefCell};
thread_local! {
    static GUI_WIN: RefCell<Option<minifb::Window>> = const { RefCell::new(None) };
    static GUI_BUF: RefCell<Vec<u32>> = const { RefCell::new(Vec::new()) };
    static GUI_W: Cell<usize> = const { Cell::new(0) };
    static GUI_H: Cell<usize> = const { Cell::new(0) };
    static GUI_FPS: Cell<u32> = const { Cell::new(60) };
    static GUI_LAST_FRAME: Cell<Option<std::time::Instant>> = const { Cell::new(None) };

    // === 3D pipeline state ===
    // Z-buffer matching framebuffer; larger = farther.
    static GUI_ZBUF: RefCell<Vec<f32>> = const { RefCell::new(Vec::new()) };
    // Projection focal length and screen center
    static GUI_3D_FOCAL: Cell<f32> = const { Cell::new(600.0) };
    static GUI_3D_CX: Cell<f32> = const { Cell::new(400.0) };
    static GUI_3D_CY: Cell<f32> = const { Cell::new(400.0) };
    // World rotation (Euler XYZ in radians)
    static GUI_3D_AX: Cell<f32> = const { Cell::new(0.0) };
    static GUI_3D_AY: Cell<f32> = const { Cell::new(0.0) };
    static GUI_3D_AZ: Cell<f32> = const { Cell::new(0.0) };
    // Camera world position. cam_z is preserved as "distance behind origin"
    // for backwards compat (positive cam_z → camera at world z = -cam_z).
    static GUI_3D_CAM_X: Cell<f32> = const { Cell::new(0.0) };
    static GUI_3D_CAM_Y: Cell<f32> = const { Cell::new(0.0) };
    static GUI_3D_CAM_Z: Cell<f32> = const { Cell::new(5.0) };
    // Camera look direction. Yaw = rotation around Y axis (horizontal turn).
    // Pitch = rotation around X axis (vertical look). 0/0 = looking down +Z.
    static GUI_3D_CAM_YAW: Cell<f32> = const { Cell::new(0.0) };
    static GUI_3D_CAM_PITCH: Cell<f32> = const { Cell::new(0.0) };
    // Light direction (normalized, points FROM light TO scene origin)
    static GUI_3D_LX: Cell<f32> = const { Cell::new(-0.5) };
    static GUI_3D_LY: Cell<f32> = const { Cell::new(-0.7) };
    static GUI_3D_LZ: Cell<f32> = const { Cell::new(-0.5) };
    // Ambient light fraction (0..1)
    static GUI_3D_AMBIENT: Cell<f32> = const { Cell::new(0.25) };
    // Extra lights beyond the primary GUI_3D_L* one. Each is (dx,dy,dz,r,g,b).
    // Direction is normalized at insert time.
    static GUI_3D_EXTRA_LIGHTS: RefCell<Vec<(f32, f32, f32, f32, f32, f32)>> = const { RefCell::new(Vec::new()) };
    // Fog: when enabled, triangle color is lerped toward FOG_COLOR based on depth.
    static GUI_3D_FOG_ENABLED: Cell<bool> = const { Cell::new(false) };
    static GUI_3D_FOG_NEAR: Cell<f32> = const { Cell::new(5.0) };
    static GUI_3D_FOG_FAR: Cell<f32> = const { Cell::new(25.0) };
    static GUI_3D_FOG_COLOR: Cell<u32> = const { Cell::new(0x000010) };
    // Backface culling. Default ON for performance.
    static GUI_3D_CULL: Cell<bool> = const { Cell::new(true) };
    // Specular intensity (Phong) — 0 disables. Higher = sharper highlights.
    static GUI_3D_SPECULAR: Cell<f32> = const { Cell::new(0.0) };
    static GUI_3D_SHININESS: Cell<f32> = const { Cell::new(16.0) };
    // Loaded textures: name -> (pixels as 0xRRGGBB, width, height)
    static GUI_3D_TEXTURES: RefCell<std::collections::HashMap<String, (Vec<u32>, usize, usize)>> =
        RefCell::new(std::collections::HashMap::new());
    // Loaded meshes: name -> list of triangles, each triangle is 9 floats (x1,y1,z1,x2,y2,z2,x3,y3,z3)
    static GUI_3D_MESHES: RefCell<std::collections::HashMap<String, Vec<[f32; 9]>>> =
        RefCell::new(std::collections::HashMap::new());
    // Shadow projection plane (Y level). Objects cast a flat shadow onto this plane.
    static GUI_3D_SHADOW_ENABLED: Cell<bool> = const { Cell::new(false) };
    static GUI_3D_SHADOW_Y: Cell<f32> = const { Cell::new(-2.0) };
    static GUI_3D_SHADOW_COLOR: Cell<u32> = const { Cell::new(0x101020) };

    // === 2D ENGINE STATE ===
    // Loaded 2D images: name -> (pixels, w, h)
    static GUI_2D_IMAGES: RefCell<std::collections::HashMap<String, (Vec<u32>, usize, usize)>> =
        RefCell::new(std::collections::HashMap::new());
    // Tilesets: name -> (image_name, tile_w, tile_h)
    static GUI_2D_TILESETS: RefCell<std::collections::HashMap<String, (String, usize, usize)>> =
        RefCell::new(std::collections::HashMap::new());
    // 2D camera (pan + zoom) — applied to gui_2d_* draw commands
    static GUI_2D_CAM_X: Cell<f32> = const { Cell::new(0.0) };
    static GUI_2D_CAM_Y: Cell<f32> = const { Cell::new(0.0) };
    static GUI_2D_CAM_ZOOM: Cell<f32> = const { Cell::new(1.0) };
    // Transparent color key — pixels matching this aren't drawn (default: magenta)
    static GUI_2D_COLOR_KEY: Cell<u32> = const { Cell::new(0xFF00FF) };
    static GUI_2D_COLOR_KEY_ENABLED: Cell<bool> = const { Cell::new(true) };
    // When true, gui_2d_draw_image_* uses bilinear sampling for smooth scaling.
    static GUI_2D_SMOOTH: Cell<bool> = const { Cell::new(false) };

    // === Native particle system ===
    // Each particle: x, y, vx, vy, ax, ay, life (frames left), color
    static GUI_PARTICLES: RefCell<Vec<Particle>> = const { RefCell::new(Vec::new()) };

    // === OpenGL state ===
    static GL_STATE: RefCell<Option<GlState>> = const { RefCell::new(None) };

    // === Unified renderer state ===
    // Used by the r3d_* commands which auto-dispatch CPU↔GPU.
    // Backend: 0 = uninitialized, 1 = GPU (gl_*), 2 = CPU (gui_*).
    static R3D_BACKEND: Cell<u32> = const { Cell::new(0) };
    static R3D_W: Cell<u32> = const { Cell::new(0) };
    static R3D_H: Cell<u32> = const { Cell::new(0) };
    static R3D_TITLE: RefCell<String> = const { RefCell::new(String::new()) };
}

// OpenGL context + cached resources for hardware-accelerated 3D rendering.
// Lives alongside the minifb-based gui_* commands — both work independently.
struct GlState {
    event_loop: winit::event_loop::EventLoop<()>,
    window: winit::window::Window,
    surface: glutin::surface::Surface<glutin::surface::WindowSurface>,
    context: glutin::context::PossiblyCurrentContext,
    gl: glow::Context,
    program: glow::NativeProgram,
    vao: glow::NativeVertexArray,
    vbo: glow::NativeBuffer,
    open: bool,
    // Pending vertex data for current frame: x,y,z,r,g,b per vertex
    verts: Vec<f32>,
    // Camera + rotation
    ax: f32, ay: f32, az: f32,
    cam_z: f32,
    focal: f32,
    aspect: f32,
    // Frame-time tracking — last frame duration in ms, rolling window of 30
    last_swap: Option<std::time::Instant>,
    last_frame_ms: f64,
    recent_ms: std::collections::VecDeque<f64>,
}

// Returns CPU load 0-100%. Linux reads /proc/stat. Windows queries the
// performance counter via WMI through PowerShell. macOS falls back to 0.0.
fn read_cpu_load() -> f64 {
    #[cfg(target_os = "linux")]
    {
        fn snapshot() -> Option<(u64, u64)> {
            let s = std::fs::read_to_string("/proc/stat").ok()?;
            let line = s.lines().next()?;
            let parts: Vec<u64> = line.split_whitespace()
                .skip(1).filter_map(|t| t.parse().ok()).collect();
            if parts.len() < 4 { return None; }
            let idle = parts[3];
            let total: u64 = parts.iter().sum();
            Some((idle, total))
        }
        let (i1, t1) = match snapshot() { Some(v) => v, None => return 0.0 };
        std::thread::sleep(std::time::Duration::from_millis(50));
        let (i2, t2) = match snapshot() { Some(v) => v, None => return 0.0 };
        let didle = i2.saturating_sub(i1) as f64;
        let dtotal = t2.saturating_sub(t1) as f64;
        return if dtotal <= 0.0 { 0.0 } else { 100.0 * (1.0 - didle / dtotal) };
    }
    #[cfg(target_os = "windows")]
    {
        // Get-CimInstance Win32_Processor exposes LoadPercentage.
        let out = std::process::Command::new("powershell")
            .args(["-NoProfile", "-Command",
                "(Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average"])
            .output();
        if let Ok(o) = out {
            let s = String::from_utf8_lossy(&o.stdout);
            return s.trim().parse::<f64>().unwrap_or(0.0);
        }
        return 0.0;
    }
    #[cfg(not(any(target_os = "linux", target_os = "windows")))]
    {
        0.0
    }
}

// Memory used %. Linux reads /proc/meminfo. Windows queries WMI.
fn read_mem_load() -> f64 {
    #[cfg(target_os = "linux")]
    {
        let s = match std::fs::read_to_string("/proc/meminfo") { Ok(s) => s, Err(_) => return 0.0 };
        let mut total = 0u64; let mut avail = 0u64;
        for line in s.lines() {
            let parts: Vec<&str> = line.split_whitespace().collect();
            if parts.len() < 2 { continue; }
            let v: u64 = parts[1].parse().unwrap_or(0);
            match parts[0] {
                "MemTotal:" => total = v,
                "MemAvailable:" => avail = v,
                _ => {}
            }
        }
        return if total == 0 { 0.0 } else { 100.0 * (1.0 - avail as f64 / total as f64) };
    }
    #[cfg(target_os = "windows")]
    {
        let out = std::process::Command::new("powershell")
            .args(["-NoProfile", "-Command",
                "$os = Get-CimInstance Win32_OperatingSystem; \
                 [math]::Round((($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) / $os.TotalVisibleMemorySize) * 100, 1)"])
            .output();
        if let Ok(o) = out {
            let s = String::from_utf8_lossy(&o.stdout);
            return s.trim().parse::<f64>().unwrap_or(0.0);
        }
        return 0.0;
    }
    #[cfg(not(any(target_os = "linux", target_os = "windows")))]
    {
        0.0
    }
}

const GL_VERTEX_SHADER: &str = r#"#version 330 core
layout (location = 0) in vec3 in_pos;
layout (location = 1) in vec3 in_col;
out vec3 v_col;
uniform mat4 u_mvp;
void main() {
    gl_Position = u_mvp * vec4(in_pos, 1.0);
    v_col = in_col;
}
"#;

const GL_FRAGMENT_SHADER: &str = r#"#version 330 core
in vec3 v_col;
out vec4 frag;
void main() { frag = vec4(v_col, 1.0); }
"#;

// Compile a vertex+fragment shader into a glow program.
unsafe fn gl_compile_program(gl: &glow::Context) -> Result<glow::NativeProgram, String> {
    use glow::HasContext as _;
    let vs = gl.create_shader(glow::VERTEX_SHADER)?;
    gl.shader_source(vs, GL_VERTEX_SHADER);
    gl.compile_shader(vs);
    if !gl.get_shader_compile_status(vs) {
        return Err(format!("vertex shader: {}", gl.get_shader_info_log(vs)));
    }
    let fs = gl.create_shader(glow::FRAGMENT_SHADER)?;
    gl.shader_source(fs, GL_FRAGMENT_SHADER);
    gl.compile_shader(fs);
    if !gl.get_shader_compile_status(fs) {
        return Err(format!("fragment shader: {}", gl.get_shader_info_log(fs)));
    }
    let p = gl.create_program()?;
    gl.attach_shader(p, vs);
    gl.attach_shader(p, fs);
    gl.link_program(p);
    if !gl.get_program_link_status(p) {
        return Err(format!("link: {}", gl.get_program_info_log(p)));
    }
    gl.delete_shader(vs);
    gl.delete_shader(fs);
    Ok(p)
}

// Build a 4x4 perspective MVP matrix for our scene (column-major).
fn gl_mvp(ax: f32, ay: f32, az: f32, cam_z: f32, focal_deg: f32, aspect: f32) -> [f32; 16] {
    // Perspective projection
    let fov = focal_deg.to_radians();
    let near = 0.1f32;
    let far = 100.0f32;
    let f = 1.0 / (fov / 2.0).tan();
    let proj = [
        f / aspect, 0.0, 0.0, 0.0,
        0.0, f, 0.0, 0.0,
        0.0, 0.0, (far + near) / (near - far), -1.0,
        0.0, 0.0, (2.0 * far * near) / (near - far), 0.0,
    ];
    // Rotation X, Y, Z
    let (sa, ca) = ax.sin_cos();
    let (sb, cb) = ay.sin_cos();
    let (sc, cc) = az.sin_cos();
    // Combined rotation R = Rz * Ry * Rx
    let m00 = cc*cb;
    let m01 = cc*sb*sa - sc*ca;
    let m02 = cc*sb*ca + sc*sa;
    let m10 = sc*cb;
    let m11 = sc*sb*sa + cc*ca;
    let m12 = sc*sb*ca - cc*sa;
    let m20 = -sb;
    let m21 = cb*sa;
    let m22 = cb*ca;
    // model-view: R then translate (-cam_z)
    let mv = [
        m00, m10, m20, 0.0,
        m01, m11, m21, 0.0,
        m02, m12, m22, 0.0,
        0.0, 0.0, -cam_z, 1.0,
    ];
    // mvp = proj * mv  (both column-major)
    let mut out = [0.0f32; 16];
    for col in 0..4 {
        for row in 0..4 {
            let mut s = 0.0;
            for k in 0..4 {
                s += proj[k * 4 + row] * mv[col * 4 + k];
            }
            out[col * 4 + row] = s;
        }
    }
    out
}

// Initialize the GL window + context.
fn gl_init_state(width: u32, height: u32, title: &str) -> Result<GlState, String> {
    use glow::HasContext as _;
    use glutin::config::ConfigTemplateBuilder;
    use glutin::context::{ContextApi, ContextAttributesBuilder, Version};
    use glutin::display::GetGlDisplay;
    use glutin::prelude::*;
    use glutin::surface::SurfaceAttributesBuilder;
    use glutin_winit::DisplayBuilder;
    use raw_window_handle::HasRawWindowHandle;
    use std::num::NonZeroU32;
    use winit::dpi::LogicalSize;
    use winit::event_loop::EventLoopBuilder;
    use winit::window::WindowBuilder;

    let event_loop = EventLoopBuilder::new().build().map_err(|e| e.to_string())?;
    let window_builder = WindowBuilder::new()
        .with_title(title)
        .with_inner_size(LogicalSize::new(width, height));
    let template = ConfigTemplateBuilder::new().with_alpha_size(8);
    let display_builder = DisplayBuilder::new().with_window_builder(Some(window_builder));
    let (window, gl_config) = display_builder
        .build(&event_loop, template, |configs| {
            configs.reduce(|a, b| if b.num_samples() > a.num_samples() { b } else { a }).unwrap()
        })
        .map_err(|e| format!("config: {}", e))?;
    let window = window.ok_or_else(|| "no window".to_string())?;
    let raw_handle = window.raw_window_handle();
    let gl_display = gl_config.display();

    let context_attrs = ContextAttributesBuilder::new()
        .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3))))
        .build(Some(raw_handle));
    let not_current = unsafe {
        gl_display.create_context(&gl_config, &context_attrs).map_err(|e| e.to_string())?
    };
    let surface_attrs = SurfaceAttributesBuilder::<glutin::surface::WindowSurface>::new()
        .build(raw_handle,
               NonZeroU32::new(width).unwrap(),
               NonZeroU32::new(height).unwrap());
    let surface = unsafe {
        gl_display.create_window_surface(&gl_config, &surface_attrs).map_err(|e| e.to_string())?
    };
    let context = not_current.make_current(&surface).map_err(|e| e.to_string())?;
    // Enable vsync — limits to monitor refresh rate, stops wasting GPU when
    // another app is using resources. Massively reduces jank under load.
    use glutin::surface::SwapInterval;
    let _ = surface.set_swap_interval(&context,
        SwapInterval::Wait(std::num::NonZeroU32::new(1).unwrap()));
    let gl = unsafe {
        glow::Context::from_loader_function(|s| {
            let cs = std::ffi::CString::new(s).unwrap();
            gl_display.get_proc_address(&cs) as *const _
        })
    };

    let program = unsafe { gl_compile_program(&gl).map_err(|e| e)? };
    let vao = unsafe { gl.create_vertex_array().map_err(|e| e)? };
    let vbo = unsafe { gl.create_buffer().map_err(|e| e)? };

    unsafe {
        gl.bind_vertex_array(Some(vao));
        gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo));
        let stride = 6 * std::mem::size_of::<f32>() as i32;
        gl.enable_vertex_attrib_array(0);
        gl.vertex_attrib_pointer_f32(0, 3, glow::FLOAT, false, stride, 0);
        gl.enable_vertex_attrib_array(1);
        gl.vertex_attrib_pointer_f32(1, 3, glow::FLOAT, false, stride,
            3 * std::mem::size_of::<f32>() as i32);
        gl.enable(glow::DEPTH_TEST);
    }

    Ok(GlState {
        event_loop, window, surface, context, gl,
        program, vao, vbo, open: true, verts: Vec::new(),
        ax: 0.0, ay: 0.0, az: 0.0, cam_z: 5.0,
        focal: 60.0, aspect: width as f32 / height as f32,
        last_swap: None,
        last_frame_ms: 0.0,
        recent_ms: std::collections::VecDeque::with_capacity(30),
    })
}

#[derive(Clone, Copy)]
struct Particle {
    x: f32, y: f32,
    vx: f32, vy: f32,
    ax: f32, ay: f32,
    life: i32,
    max_life: i32,
    color: u32,
    size: i32,
}

// --- Perlin noise (2D, 256-entry permutation, scaled output [-1, 1]) ---
static PERLIN_PERM: [u8; 256] = [
    151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,
    23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,
    174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,
    133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,
    89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,
    202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,
    248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,
    178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,
    14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,
    93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
];

fn perlin_fade(t: f32) -> f32 { t*t*t*(t*(t*6.0 - 15.0) + 10.0) }
fn perlin_grad(hash: u8, x: f32, y: f32) -> f32 {
    let h = hash & 3;
    let u = if h < 2 { x } else { y };
    let v = if h < 2 { y } else { x };
    (if h & 1 == 0 { u } else { -u }) + (if h & 2 == 0 { v } else { -v })
}
// Generate a sine-wave WAV in memory and play via aplay/paplay (Linux) or
// stdout BEL (fallback). Returns Err if no player available.
fn play_tone(freq_hz: f32, dur_ms: u64) -> std::io::Result<()> {
    let sample_rate: u32 = 22050;
    let n_samples = (sample_rate as u64 * dur_ms / 1000) as u32;
    let mut data: Vec<u8> = Vec::with_capacity(44 + n_samples as usize * 2);
    let data_size = n_samples * 2;
    let chunk_size = 36 + data_size;
    data.extend_from_slice(b"RIFF");
    data.extend_from_slice(&chunk_size.to_le_bytes());
    data.extend_from_slice(b"WAVE");
    data.extend_from_slice(b"fmt ");
    data.extend_from_slice(&16u32.to_le_bytes());     // PCM chunk size
    data.extend_from_slice(&1u16.to_le_bytes());      // PCM format
    data.extend_from_slice(&1u16.to_le_bytes());      // mono
    data.extend_from_slice(&sample_rate.to_le_bytes());
    data.extend_from_slice(&(sample_rate * 2).to_le_bytes()); // byte rate
    data.extend_from_slice(&2u16.to_le_bytes());      // block align
    data.extend_from_slice(&16u16.to_le_bytes());     // bits per sample
    data.extend_from_slice(b"data");
    data.extend_from_slice(&data_size.to_le_bytes());
    for i in 0..n_samples {
        let t = i as f32 / sample_rate as f32;
        let v = (t * freq_hz * std::f32::consts::TAU).sin();
        // Apply 5ms attack/release envelope to avoid pops
        let env = {
            let attack = (sample_rate as f32 * 0.005) as f32;
            if (i as f32) < attack { i as f32 / attack }
            else if (n_samples - i) as f32 <= attack { (n_samples - i) as f32 / attack }
            else { 1.0 }
        };
        let s = (v * env * 32000.0) as i16;
        data.extend_from_slice(&s.to_le_bytes());
    }
    use std::io::Write;
    use std::process::{Command, Stdio};

    // Windows: route to PowerShell's [Console]::Beep. It only supports one tone
    // at a time and is synchronous; we discard the WAV data we built and beep
    // with the requested freq/duration.
    #[cfg(target_os = "windows")]
    {
        let _ = data; // wav data not used on this path
        let freq = freq_hz.max(37.0).min(32767.0) as u32;  // valid Beep range
        let dur = dur_ms.min(60000);
        let ps = format!("[console]::Beep({}, {})", freq, dur);
        let _ = Command::new("powershell")
            .args(["-NoProfile", "-Command", &ps])
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn();
        return Ok(());
    }

    // macOS: afplay reads files; pipe the WAV through a temp file.
    #[cfg(target_os = "macos")]
    {
        let tmp = std::env::temp_dir().join(format!("aspkg_tone_{}.wav", std::process::id()));
        let _ = std::fs::write(&tmp, &data);
        let _ = Command::new("afplay")
            .arg(&tmp)
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn();
        return Ok(());
    }

    // Linux: pipe to aplay then paplay.
    #[cfg(all(unix, not(target_os = "macos")))]
    {
        for cmd in &["aplay", "paplay"] {
            if let Ok(mut child) = Command::new(cmd)
                .arg("-q")
                .stdin(Stdio::piped())
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .spawn()
            {
                if let Some(mut stdin) = child.stdin.take() {
                    let _ = stdin.write_all(&data);
                }
                let _ = child.wait();
                return Ok(());
            }
        }
    }

    // Last-resort fallback: terminal bell
    print!("\x07");
    let _ = std::io::stdout().flush();
    Ok(())
}

// Parse "x,y,z" into (f64, f64, f64). Tolerant of whitespace.
fn parse_vec3(s: &str) -> (f64, f64, f64) {
    let nums: Vec<f64> = s.split(',')
        .map(|t| t.trim().parse::<f64>().unwrap_or(0.0))
        .collect();
    (
        nums.first().copied().unwrap_or(0.0),
        nums.get(1).copied().unwrap_or(0.0),
        nums.get(2).copied().unwrap_or(0.0),
    )
}

fn perlin2(x: f32, y: f32) -> f32 {
    let xi = (x.floor() as i32 & 255) as usize;
    let yi = (y.floor() as i32 & 255) as usize;
    let xf = x - x.floor();
    let yf = y - y.floor();
    let u = perlin_fade(xf);
    let v = perlin_fade(yf);
    let aa = PERLIN_PERM[(PERLIN_PERM[xi] as usize + yi) & 255];
    let ab = PERLIN_PERM[(PERLIN_PERM[xi] as usize + yi + 1) & 255];
    let ba = PERLIN_PERM[(PERLIN_PERM[(xi + 1) & 255] as usize + yi) & 255];
    let bb = PERLIN_PERM[(PERLIN_PERM[(xi + 1) & 255] as usize + yi + 1) & 255];
    let x1 = perlin_grad(aa, xf, yf) * (1.0 - u) + perlin_grad(ba, xf - 1.0, yf) * u;
    let x2 = perlin_grad(ab, xf, yf - 1.0) * (1.0 - u) + perlin_grad(bb, xf - 1.0, yf - 1.0) * u;
    x1 * (1.0 - v) + x2 * v
}

// Lambertian shading: returns brightness [ambient, 1.0]
// Per-channel shaded color from a face with normal (nx,ny,nz) and base color.
// Accumulates contributions from the primary light + all extra lights, adds
// ambient, optionally adds Phong specular highlight. Returns (r,g,b) in 0..255.
fn shade_face(nx: f32, ny: f32, nz: f32, base_r: u8, base_g: u8, base_b: u8) -> (u32, u32, u32) {
    let amb = GUI_3D_AMBIENT.with(|c| c.get());
    let m = (nx*nx + ny*ny + nz*nz).sqrt().max(1e-9);
    let (nxn, nyn, nzn) = (nx/m, ny/m, nz/m);

    // Accumulate diffuse lit color across all lights (RGB normalized to 0..1)
    let mut r_lit = 0.0f32;
    let mut g_lit = 0.0f32;
    let mut b_lit = 0.0f32;

    // Primary light (white-ish)
    let lx = GUI_3D_LX.with(|c| c.get());
    let ly = GUI_3D_LY.with(|c| c.get());
    let lz = GUI_3D_LZ.with(|c| c.get());
    let d = -(nxn*lx + nyn*ly + nzn*lz);
    let lit = d.max(0.0);
    r_lit += lit; g_lit += lit; b_lit += lit;

    // Extra colored lights
    GUI_3D_EXTRA_LIGHTS.with(|el| {
        for (dx, dy, dz, cr, cg, cb) in el.borrow().iter() {
            let d2 = -(nxn*dx + nyn*dy + nzn*dz);
            let l2 = d2.max(0.0);
            r_lit += l2 * cr;
            g_lit += l2 * cg;
            b_lit += l2 * cb;
        }
    });

    // Mix ambient + diffuse, multiply by base color
    let mix_ch = |lit: f32, base: u8| -> u32 {
        let v = (amb + (1.0 - amb) * lit.min(1.0)) * (base as f32);
        v.min(255.0).max(0.0) as u32
    };
    let r_out = mix_ch(r_lit, base_r);
    let g_out = mix_ch(g_lit, base_g);
    let b_out = mix_ch(b_lit, base_b);

    // Optional specular highlight (Phong; view assumed to look down +Z from origin)
    let spec = GUI_3D_SPECULAR.with(|c| c.get());
    if spec > 0.0 {
        // reflection direction: R = 2*(N.L)*N - L  (with L = -lightdir)
        let l = (-lx, -ly, -lz);
        let nl = nxn*l.0 + nyn*l.1 + nzn*l.2;
        let rx = 2.0 * nl * nxn - l.0;
        let ry = 2.0 * nl * nyn - l.1;
        let rz = 2.0 * nl * nzn - l.2;
        // view vector: from face toward camera. Camera is at z = -cam_z roughly.
        // Use a simple v = (0,0,-1).
        let dot_rv = (-rz).max(0.0);
        let shine = GUI_3D_SHININESS.with(|c| c.get());
        let s = dot_rv.powf(shine) * spec;
        let r_out = (r_out as f32 + s * 255.0).min(255.0) as u32;
        let g_out = (g_out as f32 + s * 255.0).min(255.0) as u32;
        let b_out = (b_out as f32 + s * 255.0).min(255.0) as u32;
        return (r_out, g_out, b_out);
    }

    (r_out, g_out, b_out)
}

// Apply fog to an already-shaded color, based on average depth of the triangle
// (post-rotation Z, before perspective). Returns the same color if fog is off.
fn apply_fog(r: u32, g: u32, b: u32, depth: f32) -> (u32, u32, u32) {
    if !GUI_3D_FOG_ENABLED.with(|c| c.get()) { return (r, g, b); }
    let n = GUI_3D_FOG_NEAR.with(|c| c.get());
    let f = GUI_3D_FOG_FAR.with(|c| c.get());
    let fog = GUI_3D_FOG_COLOR.with(|c| c.get());
    let t = ((depth - n) / (f - n).max(1e-6)).clamp(0.0, 1.0);
    let fr = (fog >> 16) & 0xFF;
    let fg = (fog >> 8) & 0xFF;
    let fb = fog & 0xFF;
    let lerp = |a: u32, b: u32| -> u32 {
        let v = a as f32 + (b as f32 - a as f32) * t;
        v.clamp(0.0, 255.0) as u32
    };
    (lerp(r, fr), lerp(g, fg), lerp(b, fb))
}

// Returns true if the face is facing away from the camera (should be culled).
// Camera is at (0, 0, -cam_z) in our coordinate system, looking toward +Z.
// A face faces away if its normal has positive Z component (faces away from us).
fn is_backface(nx: f32, _ny: f32, nz: f32) -> bool {
    if !GUI_3D_CULL.with(|c| c.get()) { return false; }
    let _ = nx;
    nz > 0.0
}

// Backwards-compatible: returns the shade as a single brightness factor for
// places that still call lambert_shade. Computed by averaging RGB shade.
fn lambert_shade(nx: f32, ny: f32, nz: f32) -> f32 {
    let (r, g, b) = shade_face(nx, ny, nz, 255, 255, 255);
    (r as f32 + g as f32 + b as f32) / (3.0 * 255.0)
}

// High-level helper used by new primitives (cylinder, cone, plane). Takes 3
// world-space vertices + base color, applies world rotation, computes face
// normal, runs the full shading pipeline (multi-light + specular + fog),
// performs backface culling, projects, and rasterizes with z-buffer.
fn draw_3d_face(
    a: (f32, f32, f32), b: (f32, f32, f32), c: (f32, f32, f32),
    base_r: u8, base_g: u8, base_b: u8,
) {
    let v1 = rotate_xyz(a.0, a.1, a.2);
    let v2 = rotate_xyz(b.0, b.1, b.2);
    let v3 = rotate_xyz(c.0, c.1, c.2);
    // face normal (cross of two edges)
    let ex = v2.0 - v1.0; let ey = v2.1 - v1.1; let ez = v2.2 - v1.2;
    let fx = v3.0 - v1.0; let fy = v3.1 - v1.1; let fz = v3.2 - v1.2;
    let nx = ey*fz - ez*fy;
    let ny = ez*fx - ex*fz;
    let nz = ex*fy - ey*fx;
    if is_backface(nx, ny, nz) { return; }
    let (r, g, bc) = shade_face(nx, ny, nz, base_r, base_g, base_b);
    // average depth for fog
    let avg_depth = (v1.2 + v2.2 + v3.2) / 3.0
        + GUI_3D_CAM_Z.with(|c| c.get());
    let (r, g, bc) = apply_fog(r, g, bc, avg_depth);
    let color = (r << 16) | (g << 8) | bc;
    // shadow first (behind the actual geometry)
    cast_shadow_tri(a, b, c);
    let p1 = project_3d(v1.0, v1.1, v1.2);
    let p2 = project_3d(v2.0, v2.1, v2.2);
    let p3 = project_3d(v3.0, v3.1, v3.2);
    if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
        raster_tri_z(p1, p2, p3, color);
    }
}

// Apply XYZ rotation to a 3D point and return rotated coords.
fn rotate_xyz(x: f32, y: f32, z: f32) -> (f32, f32, f32) {
    let ax = GUI_3D_AX.with(|c| c.get());
    let ay = GUI_3D_AY.with(|c| c.get());
    let az = GUI_3D_AZ.with(|c| c.get());
    let (sx, cx) = ax.sin_cos();
    let (sy, cy) = ay.sin_cos();
    let (sz, cz) = az.sin_cos();
    // Rotate X
    let y1 = y*cx - z*sx;
    let z1 = y*sx + z*cx;
    let x1 = x;
    // Rotate Y
    let x2 = x1*cy + z1*sy;
    let z2 = -x1*sy + z1*cy;
    let y2 = y1;
    // Rotate Z
    let x3 = x2*cz - y2*sz;
    let y3 = x2*sz + y2*cz;
    let z3 = z2;
    (x3, y3, z3)
}

// Project a world point to screen + depth using the full camera transform:
// translate world -> camera-relative, apply inverse camera rotation
// (yaw around Y, then pitch around X), then perspective projection.
// Returns (sx, sy, depth) where depth is camera-space z. None if behind camera.
//
// When cam_x = cam_y = yaw = pitch = 0, behaves identically to the old
// "camera at (0, 0, -cam_z)" pipeline for back-compat with existing demos.
fn project_3d(x: f32, y: f32, z: f32) -> Option<(f32, f32, f32)> {
    let cam_x = GUI_3D_CAM_X.with(|c| c.get());
    let cam_y = GUI_3D_CAM_Y.with(|c| c.get());
    let cam_z = GUI_3D_CAM_Z.with(|c| c.get());
    let yaw = GUI_3D_CAM_YAW.with(|c| c.get());
    let pitch = GUI_3D_CAM_PITCH.with(|c| c.get());

    // Translate world -> camera-relative. Camera is at world position
    // (cam_x, cam_y, -cam_z) by convention (cam_z is "distance behind origin").
    let dx = x - cam_x;
    let dy = y - cam_y;
    let dz = z - (-cam_z);  // = z + cam_z when cam pos is 0

    // Inverse yaw (around Y axis)
    let (sy_, cy_) = yaw.sin_cos();
    let yx = dx * cy_ - dz * sy_;
    let yz = dx * sy_ + dz * cy_;
    let yy = dy;

    // Inverse pitch (around X axis)
    let (sp_, cp_) = pitch.sin_cos();
    let py_ = yy * cp_ + yz * sp_;
    let pz_ = -yy * sp_ + yz * cp_;
    let px_ = yx;

    if pz_ <= 0.1 { return None; }
    let focal = GUI_3D_FOCAL.with(|c| c.get());
    let scx = GUI_3D_CX.with(|c| c.get());
    let scy = GUI_3D_CY.with(|c| c.get());
    Some((scx + px_ * focal / pz_, scy + py_ * focal / pz_, pz_))
}

// Z-buffered, optionally shaded triangle rasterizer. Fills triangle (in 2D
// screen coords with depth-per-vertex) using barycentric interpolation for
// per-pixel depth, and applies a single solid color (already shaded).
fn raster_tri_z(
    p1: (f32, f32, f32),
    p2: (f32, f32, f32),
    p3: (f32, f32, f32),
    color: u32,
) {
    let bw = GUI_W.with(|c| c.get());
    let bh = GUI_H.with(|c| c.get());
    if bw == 0 || bh == 0 { return; }
    // Bounding box
    let min_x = p1.0.min(p2.0).min(p3.0).max(0.0) as i32;
    let max_x = p1.0.max(p2.0).max(p3.0).min(bw as f32 - 1.0) as i32;
    let min_y = p1.1.min(p2.1).min(p3.1).max(0.0) as i32;
    let max_y = p1.1.max(p2.1).max(p3.1).min(bh as f32 - 1.0) as i32;
    if min_x > max_x || min_y > max_y { return; }

    // Edge function denom
    let denom = (p2.1 - p3.1) * (p1.0 - p3.0) + (p3.0 - p2.0) * (p1.1 - p3.1);
    if denom.abs() < 1e-9 { return; }

    GUI_BUF.with(|b| {
        GUI_ZBUF.with(|zb| {
            let mut buf = b.borrow_mut();
            let mut zbuf = zb.borrow_mut();
            if zbuf.len() != bw * bh { return; }
            for y in min_y..=max_y {
                for x in min_x..=max_x {
                    let px = x as f32 + 0.5;
                    let py = y as f32 + 0.5;
                    let w1 = ((p2.1 - p3.1) * (px - p3.0) + (p3.0 - p2.0) * (py - p3.1)) / denom;
                    let w2 = ((p3.1 - p1.1) * (px - p3.0) + (p1.0 - p3.0) * (py - p3.1)) / denom;
                    let w3 = 1.0 - w1 - w2;
                    if w1 < 0.0 || w2 < 0.0 || w3 < 0.0 { continue; }
                    let depth = w1 * p1.2 + w2 * p2.2 + w3 * p3.2;
                    let idx = (y as usize) * bw + (x as usize);
                    if depth < zbuf[idx] {
                        zbuf[idx] = depth;
                        buf[idx] = color;
                    }
                }
            }
        });
    });
}

// Same but with Gouraud (per-vertex RGB) shading.
fn raster_tri_z_gouraud(
    p1: (f32, f32, f32), c1: (u8, u8, u8),
    p2: (f32, f32, f32), c2: (u8, u8, u8),
    p3: (f32, f32, f32), c3: (u8, u8, u8),
) {
    let bw = GUI_W.with(|c| c.get());
    let bh = GUI_H.with(|c| c.get());
    if bw == 0 || bh == 0 { return; }
    let min_x = p1.0.min(p2.0).min(p3.0).max(0.0) as i32;
    let max_x = p1.0.max(p2.0).max(p3.0).min(bw as f32 - 1.0) as i32;
    let min_y = p1.1.min(p2.1).min(p3.1).max(0.0) as i32;
    let max_y = p1.1.max(p2.1).max(p3.1).min(bh as f32 - 1.0) as i32;
    if min_x > max_x || min_y > max_y { return; }
    let denom = (p2.1 - p3.1) * (p1.0 - p3.0) + (p3.0 - p2.0) * (p1.1 - p3.1);
    if denom.abs() < 1e-9 { return; }

    GUI_BUF.with(|b| GUI_ZBUF.with(|zb| {
        let mut buf = b.borrow_mut();
        let mut zbuf = zb.borrow_mut();
        if zbuf.len() != bw * bh { return; }
        for y in min_y..=max_y {
            for x in min_x..=max_x {
                let px = x as f32 + 0.5;
                let py = y as f32 + 0.5;
                let w1 = ((p2.1 - p3.1) * (px - p3.0) + (p3.0 - p2.0) * (py - p3.1)) / denom;
                let w2 = ((p3.1 - p1.1) * (px - p3.0) + (p1.0 - p3.0) * (py - p3.1)) / denom;
                let w3 = 1.0 - w1 - w2;
                if w1 < 0.0 || w2 < 0.0 || w3 < 0.0 { continue; }
                let depth = w1 * p1.2 + w2 * p2.2 + w3 * p3.2;
                let idx = (y as usize) * bw + (x as usize);
                if depth < zbuf[idx] {
                    zbuf[idx] = depth;
                    let r = (w1 * c1.0 as f32 + w2 * c2.0 as f32 + w3 * c3.0 as f32) as u32;
                    let g = (w1 * c1.1 as f32 + w2 * c2.1 as f32 + w3 * c3.1 as f32) as u32;
                    let b3 = (w1 * c1.2 as f32 + w2 * c2.2 as f32 + w3 * c3.2 as f32) as u32;
                    buf[idx] = (r << 16) | (g << 8) | b3;
                }
            }
        }
    }));
}

// Z-buffered, UV-interpolated TEXTURED triangle rasterizer.
// Each vertex carries (sx, sy, depth) and (u, v) in [0..1] texture space.
// Sampling is nearest-neighbor for simplicity + speed.
fn raster_tri_z_textured(
    p1: (f32, f32, f32), uv1: (f32, f32),
    p2: (f32, f32, f32), uv2: (f32, f32),
    p3: (f32, f32, f32), uv3: (f32, f32),
    tex: &[u32], tex_w: usize, tex_h: usize,
) {
    let bw = GUI_W.with(|c| c.get());
    let bh = GUI_H.with(|c| c.get());
    if bw == 0 || bh == 0 || tex_w == 0 || tex_h == 0 || tex.is_empty() { return; }
    let min_x = p1.0.min(p2.0).min(p3.0).max(0.0) as i32;
    let max_x = p1.0.max(p2.0).max(p3.0).min(bw as f32 - 1.0) as i32;
    let min_y = p1.1.min(p2.1).min(p3.1).max(0.0) as i32;
    let max_y = p1.1.max(p2.1).max(p3.1).min(bh as f32 - 1.0) as i32;
    if min_x > max_x || min_y > max_y { return; }
    let denom = (p2.1 - p3.1) * (p1.0 - p3.0) + (p3.0 - p2.0) * (p1.1 - p3.1);
    if denom.abs() < 1e-9 { return; }
    GUI_BUF.with(|b| GUI_ZBUF.with(|zb| {
        let mut buf = b.borrow_mut();
        let mut zbuf = zb.borrow_mut();
        if zbuf.len() != bw * bh { return; }
        for y in min_y..=max_y {
            for x in min_x..=max_x {
                let px = x as f32 + 0.5;
                let py = y as f32 + 0.5;
                let w1 = ((p2.1 - p3.1) * (px - p3.0) + (p3.0 - p2.0) * (py - p3.1)) / denom;
                let w2 = ((p3.1 - p1.1) * (px - p3.0) + (p1.0 - p3.0) * (py - p3.1)) / denom;
                let w3 = 1.0 - w1 - w2;
                if w1 < 0.0 || w2 < 0.0 || w3 < 0.0 { continue; }
                let depth = w1 * p1.2 + w2 * p2.2 + w3 * p3.2;
                let idx = (y as usize) * bw + (x as usize);
                if depth < zbuf[idx] {
                    zbuf[idx] = depth;
                    let u = w1*uv1.0 + w2*uv2.0 + w3*uv3.0;
                    let v = w1*uv1.1 + w2*uv2.1 + w3*uv3.1;
                    let tu = ((u * tex_w as f32) as i32).rem_euclid(tex_w as i32) as usize;
                    let tv = ((v * tex_h as f32) as i32).rem_euclid(tex_h as i32) as usize;
                    buf[idx] = tex[tv * tex_w + tu];
                }
            }
        }
    }));
}

// Project a 3D point onto the shadow plane (Y level) and return rotated+projected
// screen coords. Returns None if behind camera.
fn project_shadow(x: f32, y: f32, z: f32) -> Option<(f32, f32, f32)> {
    let _ = y;
    let plane_y = GUI_3D_SHADOW_Y.with(|c| c.get());
    // Light is overhead (0, big-positive, 0). Shadow is projection straight down
    // onto y = plane_y. So just take (x, plane_y, z) and project.
    let v = rotate_xyz(x, plane_y, z);
    project_3d(v.0, v.1, v.2)
}

// Cast a flat shadow triangle (3 world-space points) onto the shadow plane.
fn cast_shadow_tri(a: (f32, f32, f32), b: (f32, f32, f32), c: (f32, f32, f32)) {
    if !GUI_3D_SHADOW_ENABLED.with(|c| c.get()) { return; }
    let color = GUI_3D_SHADOW_COLOR.with(|c| c.get());
    let p1 = project_shadow(a.0, a.1, a.2);
    let p2 = project_shadow(b.0, b.1, b.2);
    let p3 = project_shadow(c.0, c.1, c.2);
    if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
        raster_tri_z(p1, p2, p3, color);
    }
}

// Parse a Wavefront .OBJ file. Returns a list of triangles (each is 9 floats:
// 3 vertices × xyz). Only v + f directives are read. Triangulates n-gons
// using a simple fan.
// Draw a stored 2D image into the framebuffer.
//   x, y          screen position (top-left)
//   dst_w, dst_h  -1 = use source size, else stretch/shrink
//   name          image name in GUI_2D_IMAGES
//   src_rect      optional source crop (sx, sy, sw, sh)
// Honors gui_2d_camera (pan + zoom) and gui_2d_color_key (transparent pixels).
// Sample image at (u, v) source coordinates with optional bilinear smoothing.
// Returns None if (u,v) is outside the source rect.
#[inline]
fn sample_image(pixels: &[u32], iw: usize, ih: usize,
                u: f32, v: f32, smooth: bool) -> Option<u32> {
    if u < 0.0 || v < 0.0 || u >= iw as f32 || v >= ih as f32 { return None; }
    if !smooth {
        let su = u as usize;
        let sv = v as usize;
        return Some(pixels[sv * iw + su]);
    }
    // Bilinear: blend 4 neighboring pixels by fractional weights
    let x0 = u.floor() as i32;
    let y0 = v.floor() as i32;
    let fx = u - x0 as f32;
    let fy = v - y0 as f32;
    let clamp = |a: i32, hi: i32| a.max(0).min(hi - 1) as usize;
    let p00 = pixels[clamp(y0, ih as i32) * iw + clamp(x0, iw as i32)];
    let p10 = pixels[clamp(y0, ih as i32) * iw + clamp(x0 + 1, iw as i32)];
    let p01 = pixels[clamp(y0 + 1, ih as i32) * iw + clamp(x0, iw as i32)];
    let p11 = pixels[clamp(y0 + 1, ih as i32) * iw + clamp(x0 + 1, iw as i32)];
    let blend = |a: u32, b: u32, c: u32, d: u32| -> u32 {
        let mix = |a: u32, b: u32, c: u32, d: u32, shift: u32| -> u32 {
            let av = ((a >> shift) & 0xFF) as f32;
            let bv = ((b >> shift) & 0xFF) as f32;
            let cv = ((c >> shift) & 0xFF) as f32;
            let dv = ((d >> shift) & 0xFF) as f32;
            let top = av * (1.0 - fx) + bv * fx;
            let bot = cv * (1.0 - fx) + dv * fx;
            (top * (1.0 - fy) + bot * fy).clamp(0.0, 255.0) as u32
        };
        (mix(a, b, c, d, 16) << 16) | (mix(a, b, c, d, 8) << 8) | mix(a, b, c, d, 0)
    };
    Some(blend(p00, p10, p01, p11))
}

// Apply an RGB tint multiplier (each channel * tint_chan / 255) to a color.
#[inline]
fn apply_tint(color: u32, tint: u32) -> u32 {
    let mul = |c: u32, t: u32, shift: u32| {
        let cv = (c >> shift) & 0xFF;
        let tv = (t >> shift) & 0xFF;
        (cv * tv / 255) & 0xFF
    };
    (mul(color, tint, 16) << 16) | (mul(color, tint, 8) << 8) | mul(color, tint, 0)
}

// Flags for the extended draw routine.
#[derive(Default, Clone, Copy)]
struct DrawFlags {
    flip_x: bool,
    flip_y: bool,
    rotation: f32,   // radians around the image center
    tint: Option<u32>,
}

// Full-featured image blit: scale, crop, flip, rotate, tint, optional bilinear.
fn draw_image_extended(x: i32, y: i32, dst_w: i32, dst_h: i32,
                       name: &str,
                       src_rect: Option<(i32, i32, i32, i32)>,
                       flags: DrawFlags) {
    let cam_x = GUI_2D_CAM_X.with(|c| c.get());
    let cam_y = GUI_2D_CAM_Y.with(|c| c.get());
    let zoom = GUI_2D_CAM_ZOOM.with(|c| c.get());
    let key_on = GUI_2D_COLOR_KEY_ENABLED.with(|c| c.get());
    let key = GUI_2D_COLOR_KEY.with(|c| c.get());
    let smooth = GUI_2D_SMOOTH.with(|c| c.get());
    let bw = GUI_W.with(|c| c.get());
    let bh = GUI_H.with(|c| c.get());

    let img = GUI_2D_IMAGES.with(|m| m.borrow().get(name).cloned());
    let (img_pixels, img_w, img_h) = match img { Some(t) => t, None => return };
    if img_w == 0 || img_h == 0 { return; }

    let (sx, sy, sw, sh) = src_rect.unwrap_or((0, 0, img_w as i32, img_h as i32));
    if sw <= 0 || sh <= 0 { return; }
    let (final_w, final_h) = if dst_w < 0 || dst_h < 0 { (sw, sh) } else { (dst_w, dst_h) };
    if final_w <= 0 || final_h <= 0 { return; }

    let scx = bw as f32 * 0.5;
    let scy = bh as f32 * 0.5;
    // Top-left of the destination in screen coords (camera-adjusted)
    let dx = (((x as f32 - cam_x) * zoom + scx) - (final_w as f32 * 0.5 * (zoom - 1.0))) as f32;
    let dy = (((y as f32 - cam_y) * zoom + scy) - (final_h as f32 * 0.5 * (zoom - 1.0))) as f32;
    let zfw = (final_w as f32 * zoom).max(1.0) as i32;
    let zfh = (final_h as f32 * zoom).max(1.0) as i32;

    // Rotation pivot is the center of the destination rectangle.
    let cx = dx + zfw as f32 * 0.5;
    let cy = dy + zfh as f32 * 0.5;
    let (sin_r, cos_r) = flags.rotation.sin_cos();

    // Iterate over a bounding box around the rotated destination so we cover
    // every pixel the rotated image touches.
    let half_diag = ((zfw * zfw + zfh * zfh) as f32).sqrt() * 0.5 + 1.0;
    let bb_min_x = (cx - half_diag) as i32;
    let bb_max_x = (cx + half_diag) as i32;
    let bb_min_y = (cy - half_diag) as i32;
    let bb_max_y = (cy + half_diag) as i32;

    GUI_BUF.with(|b| {
        let mut buf = b.borrow_mut();
        for gy in bb_min_y..=bb_max_y {
            if gy < 0 || gy as usize >= bh { continue; }
            for gx in bb_min_x..=bb_max_x {
                if gx < 0 || gx as usize >= bw { continue; }
                // Inverse-rotate (gx, gy) around the center to find which
                // destination pixel this maps to (lx, ly in [0, zfw|zfh]).
                let rx = gx as f32 - cx;
                let ry = gy as f32 - cy;
                let lx = rx * cos_r + ry * sin_r + zfw as f32 * 0.5;
                let ly = -rx * sin_r + ry * cos_r + zfh as f32 * 0.5;
                if lx < 0.0 || ly < 0.0 || lx >= zfw as f32 || ly >= zfh as f32 { continue; }

                // Map destination pixel to source (with flips).
                let tx_norm = if flags.flip_x { 1.0 - lx / zfw as f32 } else { lx / zfw as f32 };
                let ty_norm = if flags.flip_y { 1.0 - ly / zfh as f32 } else { ly / zfh as f32 };
                let src_u = sx as f32 + tx_norm * sw as f32;
                let src_v = sy as f32 + ty_norm * sh as f32;

                let mut color = match sample_image(&img_pixels, img_w, img_h, src_u, src_v, smooth) {
                    Some(c) => c,
                    None => continue,
                };
                if key_on && color == key { continue; }
                if let Some(t) = flags.tint { color = apply_tint(color, t); }
                buf[gy as usize * bw + gx as usize] = color;
            }
        }
    });
}

// Thin compat shim — old call sites still expect this name.
fn draw_image_internal(x: i32, y: i32, dst_w: i32, dst_h: i32,
                       name: &str, src_rect: Option<(i32, i32, i32, i32)>) {
    draw_image_extended(x, y, dst_w, dst_h, name, src_rect, DrawFlags::default());
}

// Decode texture from raw bytes — handles PNG and PPM (P6) automatically.
// Returns (pixels in 0xRRGGBB, width, height) or None.
fn load_texture_bytes(data: &[u8]) -> Option<(Vec<u32>, usize, usize)> {
    // PNG starts with: 89 50 4E 47 0D 0A 1A 0A
    if data.len() >= 8 && data[..8] == [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A] {
        let decoder = png::Decoder::new(data);
        let mut reader = decoder.read_info().ok()?;
        let mut buf = vec![0u8; reader.output_buffer_size()];
        let info = reader.next_frame(&mut buf).ok()?;
        let w = info.width as usize;
        let h = info.height as usize;
        let bpp = match info.color_type {
            png::ColorType::Rgb => 3,
            png::ColorType::Rgba => 4,
            png::ColorType::Grayscale => 1,
            png::ColorType::GrayscaleAlpha => 2,
            png::ColorType::Indexed => return None,
        };
        let mut pixels = Vec::with_capacity(w * h);
        for py in 0..h {
            for px in 0..w {
                let i = (py * w + px) * bpp;
                let (r, g, b) = match bpp {
                    1 => (buf[i], buf[i], buf[i]),
                    2 => (buf[i], buf[i], buf[i]),
                    3 => (buf[i], buf[i+1], buf[i+2]),
                    4 => (buf[i], buf[i+1], buf[i+2]),
                    _ => (0, 0, 0),
                };
                pixels.push(((r as u32) << 16) | ((g as u32) << 8) | (b as u32));
            }
        }
        return Some((pixels, w, h));
    }
    // PPM P6
    let mut i = 0usize;
    let mut tokens: Vec<String> = Vec::new();
    while tokens.len() < 4 && i < data.len() {
        while i < data.len() && (data[i] == b'\n' || data[i] == b' '
            || data[i] == b'\r' || data[i] == b'\t') { i += 1; }
        if i < data.len() && data[i] == b'#' {
            while i < data.len() && data[i] != b'\n' { i += 1; }
            continue;
        }
        let s = i;
        while i < data.len() && data[i] != b'\n' && data[i] != b' '
            && data[i] != b'\r' && data[i] != b'\t' { i += 1; }
        if s < i { tokens.push(String::from_utf8_lossy(&data[s..i]).to_string()); }
    }
    if tokens.len() < 4 || tokens[0] != "P6" { return None; }
    let w: usize = tokens[1].parse().ok()?;
    let h: usize = tokens[2].parse().ok()?;
    let pixels_raw = if i < data.len() { &data[i + 1..] } else { return None; };
    let mut pixels = Vec::with_capacity(w * h);
    for py in 0..h {
        for px in 0..w {
            let pi = (py * w + px) * 3;
            if pi + 2 >= pixels_raw.len() { pixels.push(0); continue; }
            pixels.push(((pixels_raw[pi] as u32) << 16)
                | ((pixels_raw[pi+1] as u32) << 8)
                | (pixels_raw[pi+2] as u32));
        }
    }
    Some((pixels, w, h))
}

fn parse_obj(text: &str) -> Vec<[f32; 9]> {
    let mut verts: Vec<(f32, f32, f32)> = Vec::new();
    let mut tris: Vec<[f32; 9]> = Vec::new();
    for raw_line in text.lines() {
        let line = raw_line.trim();
        if line.starts_with("v ") {
            let parts: Vec<&str> = line.split_whitespace().collect();
            if parts.len() >= 4 {
                let x = parts[1].parse::<f32>().unwrap_or(0.0);
                let y = parts[2].parse::<f32>().unwrap_or(0.0);
                let z = parts[3].parse::<f32>().unwrap_or(0.0);
                verts.push((x, y, z));
            }
        } else if line.starts_with("f ") {
            // face — indices can be "i", "i/t", "i/t/n", or "i//n"; take first
            let parts: Vec<&str> = line[2..].split_whitespace().collect();
            let mut idxs: Vec<usize> = Vec::new();
            for p in &parts {
                let i_str = p.split('/').next().unwrap_or("0");
                let i: i64 = i_str.parse().unwrap_or(0);
                // .obj indices are 1-based; negative means relative
                let idx = if i > 0 { (i - 1) as usize }
                          else if i < 0 { (verts.len() as i64 + i) as usize }
                          else { 0 };
                idxs.push(idx);
            }
            // fan triangulation
            for i in 1..idxs.len().saturating_sub(1) {
                let a = idxs[0];
                let b = idxs[i];
                let c = idxs[i + 1];
                if a < verts.len() && b < verts.len() && c < verts.len() {
                    let va = verts[a];
                    let vb = verts[b];
                    let vc = verts[c];
                    tris.push([va.0, va.1, va.2, vb.0, vb.1, vb.2, vc.0, vc.1, vc.2]);
                }
            }
        }
    }
    tris
}

// Xiaolin Wu's anti-aliased line.
fn wu_line(x0: f32, y0: f32, x1: f32, y1: f32, color: u32) {
    let bw = GUI_W.with(|c| c.get());
    let bh = GUI_H.with(|c| c.get());
    if bw == 0 || bh == 0 { return; }
    let steep = (y1 - y0).abs() > (x1 - x0).abs();
    let (mut x0, mut y0, mut x1, mut y1) = if steep {
        (y0, x0, y1, x1)
    } else { (x0, y0, x1, y1) };
    if x0 > x1 {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }
    let dx = x1 - x0;
    let dy = y1 - y0;
    let gradient = if dx.abs() < 1e-9 { 1.0 } else { dy / dx };
    let mut intery = y0 + gradient * (x0.round() - x0);
    let plot = |buf: &mut [u32], x: i32, y: i32, c: u32, a: f32| {
        if x < 0 || y < 0 || x >= bw as i32 || y >= bh as i32 { return; }
        let idx = y as usize * bw + x as usize;
        let old = buf[idx];
        let inv = 1.0 - a;
        let nr = (((old >> 16) & 0xFF) as f32 * inv + ((c >> 16) & 0xFF) as f32 * a) as u32;
        let ng = (((old >> 8) & 0xFF) as f32 * inv + ((c >> 8) & 0xFF) as f32 * a) as u32;
        let nb = ((old & 0xFF) as f32 * inv + (c & 0xFF) as f32 * a) as u32;
        buf[idx] = (nr << 16) | (ng << 8) | nb;
    };
    GUI_BUF.with(|b| {
        let mut buf = b.borrow_mut();
        let x_start = x0.round() as i32;
        let x_end = x1.round() as i32;
        for x in x_start..=x_end {
            let iy = intery.floor() as i32;
            let frac = intery - intery.floor();
            if steep {
                plot(&mut buf, iy, x, color, 1.0 - frac);
                plot(&mut buf, iy + 1, x, color, frac);
            } else {
                plot(&mut buf, x, iy, color, 1.0 - frac);
                plot(&mut buf, x, iy + 1, color, frac);
            }
            intery += gradient;
        }
    });
}

// Parse a string as an integer, accepting either "42" or "42.7" (truncates to 42).
fn parse_i64_loose(s: &str) -> i64 {
    s.trim().parse::<i64>().unwrap_or_else(|_| {
        s.trim().parse::<f64>().map(|f| f as i64).unwrap_or(0)
    })
}

// Silences both stdout and stderr for the duration of a block. minifb prints the
// "Failed to create server-side surface decoration" Wayland warning via println!
// (so it goes to fd 1, not fd 2). We scope the redirect so user-facing prints
// after this still work.
#[cfg(unix)]
fn suppress_stderr<R>(f: impl FnOnce() -> R) -> R {
    use std::io::Write;
    use std::os::unix::io::AsRawFd;
    extern "C" {
        fn dup(fd: i32) -> i32;
        fn dup2(src: i32, dst: i32) -> i32;
        fn close(fd: i32) -> i32;
    }
    let _ = std::io::stdout().flush();
    let _ = std::io::stderr().flush();
    let null = match std::fs::OpenOptions::new().write(true).open("/dev/null") {
        Ok(f) => f,
        Err(_) => return f(),
    };
    unsafe {
        let saved_out = dup(1);
        let saved_err = dup(2);
        if saved_out < 0 || saved_err < 0 { return f(); }
        dup2(null.as_raw_fd(), 1);
        dup2(null.as_raw_fd(), 2);
        let result = f();
        let _ = std::io::stdout().flush();
        let _ = std::io::stderr().flush();
        dup2(saved_out, 1);
        dup2(saved_err, 2);
        close(saved_out);
        close(saved_err);
        result
    }
}

#[cfg(not(unix))]
fn suppress_stderr<R>(f: impl FnOnce() -> R) -> R { f() }

// Map a key name (case-insensitive) to a minifb::Key. Supports letters, digits,
// arrows, modifiers, function keys, punctuation, and common synonyms ("+", "plus",
// "minus", "esc", "return", "enter", etc).
fn parse_minifb_key(name: &str) -> Option<minifb::Key> {
    use minifb::Key as K;
    let s = name.trim().to_lowercase();
    Some(match s.as_str() {
        // letters
        "a" => K::A, "b" => K::B, "c" => K::C, "d" => K::D, "e" => K::E,
        "f" => K::F, "g" => K::G, "h" => K::H, "i" => K::I, "j" => K::J,
        "k" => K::K, "l" => K::L, "m" => K::M, "n" => K::N, "o" => K::O,
        "p" => K::P, "q" => K::Q, "r" => K::R, "s" => K::S, "t" => K::T,
        "u" => K::U, "v" => K::V, "w" => K::W, "x" => K::X, "y" => K::Y,
        "z" => K::Z,
        // digits (top row)
        "0" => K::Key0, "1" => K::Key1, "2" => K::Key2, "3" => K::Key3,
        "4" => K::Key4, "5" => K::Key5, "6" => K::Key6, "7" => K::Key7,
        "8" => K::Key8, "9" => K::Key9,
        // numpad
        "num0" | "kp0" => K::NumPad0, "num1" | "kp1" => K::NumPad1,
        "num2" | "kp2" => K::NumPad2, "num3" | "kp3" => K::NumPad3,
        "num4" | "kp4" => K::NumPad4, "num5" | "kp5" => K::NumPad5,
        "num6" | "kp6" => K::NumPad6, "num7" | "kp7" => K::NumPad7,
        "num8" | "kp8" => K::NumPad8, "num9" | "kp9" => K::NumPad9,
        "numdot" | "kpdot" => K::NumPadDot,
        "numplus" | "kpplus" => K::NumPadPlus,
        "numminus" | "kpminus" => K::NumPadMinus,
        "numstar" | "kpstar" | "nummul" => K::NumPadAsterisk,
        "numslash" | "kpslash" | "numdiv" => K::NumPadSlash,
        "numenter" | "kpenter" => K::NumPadEnter,
        // arrows
        "up" | "uparrow" | "arrow_up" => K::Up,
        "down" | "downarrow" | "arrow_down" => K::Down,
        "left" | "leftarrow" | "arrow_left" => K::Left,
        "right" | "rightarrow" | "arrow_right" => K::Right,
        // whitespace + control
        "space" | "spc" => K::Space,
        "enter" | "return" | "ret" => K::Enter,
        "escape" | "esc" => K::Escape,
        "tab" => K::Tab,
        "backspace" | "bksp" => K::Backspace,
        "delete" | "del" => K::Delete,
        "insert" | "ins" => K::Insert,
        "home" => K::Home,
        "end" => K::End,
        "pageup" | "pgup" => K::PageUp,
        "pagedown" | "pgdn" => K::PageDown,
        // modifiers
        "lshift" | "shift" => K::LeftShift,
        "rshift" => K::RightShift,
        "lctrl" | "ctrl" | "control" => K::LeftCtrl,
        "rctrl" => K::RightCtrl,
        "lalt" | "alt" => K::LeftAlt,
        "ralt" => K::RightAlt,
        "lsuper" | "super" | "meta" | "win" | "cmd" => K::LeftSuper,
        "rsuper" => K::RightSuper,
        "capslock" | "caps" => K::CapsLock,
        "numlock" => K::NumLock,
        "scrolllock" | "scroll" => K::ScrollLock,
        // function keys
        "f1" => K::F1, "f2" => K::F2, "f3" => K::F3, "f4" => K::F4,
        "f5" => K::F5, "f6" => K::F6, "f7" => K::F7, "f8" => K::F8,
        "f9" => K::F9, "f10" => K::F10, "f11" => K::F11, "f12" => K::F12,
        // punctuation — minifb uses the Equal key for both '=' and '+'
        // since they're the same physical key (shifted)
        "=" | "equal" | "equals" | "+" | "plus" => K::Equal,
        "-" | "minus" | "_" | "underscore" | "dash" => K::Minus,
        "," | "comma" => K::Comma,
        "." | "period" | "dot" => K::Period,
        "/" | "slash" | "?" | "question" => K::Slash,
        "\\" | "backslash" | "|" | "pipe" => K::Backslash,
        ";" | "semicolon" | ":" | "colon" => K::Semicolon,
        "'" | "apostrophe" | "\"" | "quote" => K::Apostrophe,
        "[" | "leftbracket" | "lbracket" | "{" | "leftbrace" => K::LeftBracket,
        "]" | "rightbracket" | "rbracket" | "}" | "rightbrace" => K::RightBracket,
        "`" | "backtick" | "grave" | "~" | "tilde" => K::Backquote,
        _ => return None,
    })
}

fn color_to_u32(s: &str) -> u32 {
    let s = s.trim().to_lowercase();
    match s.as_str() {
        "black" => 0x000000,
        "white" => 0xFFFFFF,
        "red" => 0xFF0000,
        "green" => 0x00FF00,
        "blue" => 0x0000FF,
        "yellow" => 0xFFFF00,
        "cyan" => 0x00FFFF,
        "magenta" | "purple" => 0xFF00FF,
        "orange" => 0xFFA500,
        "pink" => 0xFFC0CB,
        "gray" | "grey" => 0x808080,
        "darkgray" => 0x404040,
        "lightgray" => 0xC0C0C0,
        "brown" => 0x8B4513,
        "navy" => 0x000080,
        "teal" => 0x008080,
        "olive" => 0x808000,
        "lime" => 0x00FF00,
        "maroon" => 0x800000,
        "silver" => 0xC0C0C0,
        "gold" => 0xFFD700,
        _ => {
            let hex = s.trim_start_matches('#').trim_start_matches("0x");
            u32::from_str_radix(hex, 16).unwrap_or(0)
        }
    }
}

fn font_5x7(ch: char) -> [u8; 7] {
    match ch {
        '0'..='9' => {
            let n = (ch as u8 - b'0') as usize;
            const DIGITS: [[u8;7]; 10] = [
                [0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110],
                [0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110],
                [0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b01000, 0b11111],
                [0b11111, 0b00010, 0b00100, 0b00010, 0b00001, 0b10001, 0b01110],
                [0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010],
                [0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110],
                [0b00110, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110],
                [0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000],
                [0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110],
                [0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b01100],
            ];
            DIGITS[n]
        }
        'A'..='Z' | 'a'..='z' => {
            let n = (ch.to_ascii_uppercase() as u8 - b'A') as usize;
            const LETTERS: [[u8;7]; 26] = [
                [0b01110, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001],
                [0b11110, 0b10001, 0b10001, 0b11110, 0b10001, 0b10001, 0b11110],
                [0b01110, 0b10001, 0b10000, 0b10000, 0b10000, 0b10001, 0b01110],
                [0b11110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11110],
                [0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b11111],
                [0b11111, 0b10000, 0b10000, 0b11110, 0b10000, 0b10000, 0b10000],
                [0b01110, 0b10001, 0b10000, 0b10111, 0b10001, 0b10001, 0b01110],
                [0b10001, 0b10001, 0b10001, 0b11111, 0b10001, 0b10001, 0b10001],
                [0b01110, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110],
                [0b00111, 0b00010, 0b00010, 0b00010, 0b00010, 0b10010, 0b01100],
                [0b10001, 0b10010, 0b10100, 0b11000, 0b10100, 0b10010, 0b10001],
                [0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b11111],
                [0b10001, 0b11011, 0b10101, 0b10101, 0b10001, 0b10001, 0b10001],
                [0b10001, 0b10001, 0b11001, 0b10101, 0b10011, 0b10001, 0b10001],
                [0b01110, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110],
                [0b11110, 0b10001, 0b10001, 0b11110, 0b10000, 0b10000, 0b10000],
                [0b01110, 0b10001, 0b10001, 0b10001, 0b10101, 0b10010, 0b01101],
                [0b11110, 0b10001, 0b10001, 0b11110, 0b10100, 0b10010, 0b10001],
                [0b01111, 0b10000, 0b10000, 0b01110, 0b00001, 0b00001, 0b11110],
                [0b11111, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100, 0b00100],
                [0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01110],
                [0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b01010, 0b00100],
                [0b10001, 0b10001, 0b10001, 0b10101, 0b10101, 0b10101, 0b01010],
                [0b10001, 0b10001, 0b01010, 0b00100, 0b01010, 0b10001, 0b10001],
                [0b10001, 0b10001, 0b01010, 0b00100, 0b00100, 0b00100, 0b00100],
                [0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b10000, 0b11111],
            ];
            LETTERS[n]
        }
        '.' => [0,0,0,0,0,0,0b00100],
        ',' => [0,0,0,0,0,0b00100,0b01000],
        ':' => [0,0b00100,0,0,0b00100,0,0],
        '!' => [0b00100, 0b00100, 0b00100, 0b00100, 0b00000, 0b00000, 0b00100],
        '?' => [0b01110, 0b10001, 0b00010, 0b00100, 0b00100, 0b00000, 0b00100],
        '-' => [0,0,0,0b11111,0,0,0],
        '+' => [0,0b00100,0b00100,0b11111,0b00100,0b00100,0],
        '/' => [0b00001,0b00010,0b00100,0b00100,0b01000,0b10000,0],
        '*' => [0,0b10101,0b01110,0b11111,0b01110,0b10101,0],
        '=' => [0,0,0b11111,0,0b11111,0,0],
        '(' => [0b00010,0b00100,0b01000,0b01000,0b01000,0b00100,0b00010],
        ')' => [0b01000,0b00100,0b00010,0b00010,0b00010,0b00100,0b01000],
        ' ' => [0;7],
        _ => [0b11111, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11111],
    }
}

fn gui_put_pixel(buf: &mut [u32], w: usize, h: usize, x: i64, y: i64, color: u32) {
    if x < 0 || y < 0 || x as usize >= w || y as usize >= h { return; }
    buf[y as usize * w + x as usize] = color;
}

fn gui_draw_text_at(buf: &mut [u32], w: usize, h: usize, x: i64, y: i64, text: &str, color: u32) {
    let mut cx = x;
    for ch in text.chars() {
        let g = font_5x7(ch);
        for (row, byte) in g.iter().enumerate() {
            for col in 0..5 {
                if byte & (1 << (4 - col)) != 0 {
                    gui_put_pixel(buf, w, h, cx + col as i64, y + row as i64, color);
                }
            }
        }
        cx += 6;
    }
}

// Global WebSocket state — shared between ws_serve thread and main thread
struct WsState {
    clients: Arc<Mutex<Vec<Arc<Mutex<tungstenite::WebSocket<TcpStream>>>>>>,
    incoming: Arc<Mutex<VecDeque<String>>>,
}

static WS_STATE: OnceLock<WsState> = OnceLock::new();

fn ws_global() -> &'static WsState {
    WS_STATE.get_or_init(|| WsState {
        clients: Arc::new(Mutex::new(Vec::new())),
        incoming: Arc::new(Mutex::new(VecDeque::new())),
    })
}

fn html_escape_str(s: &str) -> String {
    s.chars().map(|c| match c {
        '&' => "&amp;".to_string(),
        '<' => "&lt;".to_string(),
        '>' => "&gt;".to_string(),
        '"' => "&quot;".to_string(),
        '\'' => "&#39;".to_string(),
        _ => c.to_string(),
    }).collect()
}

fn builtin_doc(name: &str) -> &'static str {
    match name {
        "psyska" => "psyska -/ \"text\"  — print line. Supports {var} interpolation.",
        "set" => "set var = value  — assign a variable (int or string).",
        "add" => "add var, n  — increment numeric var by n (or by another var).",
        "asknum" => "asknum var [write]  — prompt for int. `write` bakes value into source.",
        "if" => "if expr op expr ... endif  — conditional. Operators: > < == != >= <=",
        "repeat" => "repeat N [counter_var] ... endrepeat  — loop N times.",
        "while" => "while expr ... endwhile  — loop while condition true.",
        "func" => "func name p1 p2 ... endfunc  — define function. Call with `call name args`.",
        "class" => "class Name [extends Parent] ... endclass  — define class.",
        "new" => "new inst = Class(args)  — instantiate class. Runs init() if defined.",
        "call" => "call inst.method args [-> result]  — invoke method or function.",
        "return" => "return value  — exit function/method, optionally with value.",
        "ws_serve" => "ws_serve PORT  — start WebSocket server on port.",
        "ws_send" => "ws_send \"msg\"  — broadcast message to all connected WS clients.",
        "ws_recv" => "ws_recv -> var  — pull next incoming WS message from queue.",
        "ws_clients" => "ws_clients var  — get count of connected WS clients.",
        "gui_show" => "gui_show \"<html>\"  — open default browser with given HTML.",
        "gui_window" => "gui_window \"Title\"  — open browser window with centered title.",
        "ld_set" => "ld_set list idx field value  — set field on idx'th record.",
        "ld_get" => "ld_get list idx field -> var  — read field from idx'th record.",
        "lambda" => "lambda name(p1, p2) body  — define anonymous-style function inline.",
        "matchv" => "matchv val c1 r1 c2 r2 [default] -> var  — pattern match.",
        "@timed" => "@timed call f args  — time the call, print elapsed.",
        "@retry" => "@retry N command  — retry up to N times on error.",
        "@once" => "@once key command  — run only first time per session.",
        "@logged" => "@logged command  — print before running.",
        "async" => "async name \"shell cmd\"  — run shell command in background.",
        "await" => "await name -> var  — collect result of async task.",
        "docs" => "docs commandname  — show usage for a built-in command (this!).",
        _ => "(no doc available — try `help` for full reference)",
    }
}

fn split_args(s: &str) -> Vec<String> {
    let mut out = Vec::new();
    let mut buf = String::new();
    let mut in_quote = false;
    let mut brace_depth: i32 = 0;
    let mut paren_depth: i32 = 0;
    for c in s.chars() {
        if c == '"' {
            in_quote = !in_quote;
            buf.push(c);
            continue;
        }
        if !in_quote {
            if c == '{' {
                brace_depth += 1;
                buf.push(c);
                continue;
            }
            if c == '}' {
                brace_depth -= 1;
                buf.push(c);
                continue;
            }
            if c == '(' {
                paren_depth += 1;
                buf.push(c);
                continue;
            }
            if c == ')' {
                paren_depth -= 1;
                buf.push(c);
                continue;
            }
        }
        if c.is_whitespace() && !in_quote && brace_depth == 0 && paren_depth == 0 {
            if !buf.is_empty() {
                out.push(std::mem::take(&mut buf));
            }
            continue;
        }
        buf.push(c);
    }
    if !buf.is_empty() {
        out.push(buf);
    }
    out
}

fn strip_outer_quotes(s: &str) -> &str {
    if s.len() >= 2 && s.starts_with('"') && s.ends_with('"') {
        &s[1..s.len() - 1]
    } else {
        s
    }
}

fn strip_trailing_comment(s: &str) -> String {
    let mut in_quote = false;
    let mut prev: Option<char> = None;
    let mut prev_ws = true;
    let mut cut: Option<usize> = None;
    for (i, c) in s.char_indices() {
        if c == '"' && prev != Some('\\') {
            in_quote = !in_quote;
        }
        if !in_quote && c == ':' && prev_ws {
            cut = Some(i);
            break;
        }
        prev_ws = c.is_whitespace();
        prev = Some(c);
    }
    match cut {
        Some(i) if i > 0 => s[..i].to_string(),
        _ => s.to_string(),
    }
}

fn unescape_string(s: &str) -> String {
    let mut out = String::with_capacity(s.len());
    let mut chars = s.chars().peekable();
    while let Some(c) = chars.next() {
        if c == '\\' {
            match chars.next() {
                Some('"') => out.push('"'),
                Some('\\') => out.push('\\'),
                Some('n') => out.push('\n'),
                Some('t') => out.push('\t'),
                Some('r') => out.push('\r'),
                Some('0') => out.push('\0'),
                Some(other) => {
                    out.push('\\');
                    out.push(other);
                }
                None => out.push('\\'),
            }
        } else {
            out.push(c);
        }
    }
    out
}

fn interpolate(s: &str, vars: &Vars, oop: &OopState) -> String {
    let mut out = String::with_capacity(s.len());
    let bytes = s.as_bytes();
    let mut i = 0;

    while i < bytes.len() {
        let b = bytes[i];

        if b == b'{' && i + 1 < bytes.len() && bytes[i + 1] == b'{' {
            out.push('{');
            i += 2;
            continue;
        }

        if b == b'}' && i + 1 < bytes.len() && bytes[i + 1] == b'}' {
            out.push('}');
            i += 2;
            continue;
        }

        if b == b'{' {
            if let Some(rel_end) = s[i + 1..].find('}') {
                let key_slice = &s[i + 1..i + 1 + rel_end];
                if key_slice.contains('{') {
                    out.push('{');
                    i += 1;
                    continue;
                }
                let key = key_slice.trim();
                let resolved = resolve_interp_key(key, vars, oop);
                match resolved {
                    Some(v) => out.push_str(&v),
                    None => {
                        out.push('{');
                        out.push_str(key);
                        out.push('}');
                    }
                }
                i = i + 1 + rel_end + 1;
                continue;
            }
        }

        let ch_end = next_char_boundary(s, i);
        out.push_str(&s[i..ch_end]);
        i = ch_end;
    }

    out
}

fn next_char_boundary(s: &str, start: usize) -> usize {
    let bytes = s.as_bytes();
    let mut end = start + 1;
    while end < bytes.len() && !s.is_char_boundary(end) {
        end += 1;
    }
    end
}

fn resolve_interp_key(key: &str, vars: &Vars, oop: &OopState) -> Option<String> {
    if key.is_empty() {
        return None;
    }

    // Find the rightmost ':' that is NOT inside a [...] slice expression,
    // so that `{s[0:5]}` doesn't collide with `{var:fmt}`. Walks the key
    // tracking bracket depth.
    let (expr_part, fmt_part) = {
        let mut depth: i32 = 0;
        let mut colon_pos: Option<usize> = None;
        for (i, c) in key.char_indices() {
            match c {
                '[' => depth += 1,
                ']' => depth -= 1,
                ':' if depth == 0 => { colon_pos = Some(i); }
                _ => {}
            }
        }
        match colon_pos {
            Some(i) => (key[..i].trim(), Some(key[i + 1..].trim())),
            None => (key, None),
        }
    };

    let value = lookup_simple(expr_part, vars, oop)
        .or_else(|| eval_expression(expr_part, vars, oop))
        .or_else(|| {
            if expr_part.parse::<f64>().is_ok() {
                Some(expr_part.to_string())
            } else {
                None
            }
        })?;

    Some(apply_format(&value, fmt_part))
}

// Slice / index helper for string and list vars. Supports:
//   s[2:5]   chars 2..5 (exclusive end)
//   s[2:]    from 2 to end
//   s[:5]    start to 4
//   s[2]     single character (string) / single element (list)
//   s[-3:]   last 3
//   s[:-2]   all but last 2
// Returns None if `var_name` doesn't resolve to a sliceable value.
fn try_slice_or_index(var_name: &str, inside: &str, vars: &Vars, oop: &OopState) -> Option<String> {
    let var_name = var_name.trim();
    if var_name.is_empty() {
        return None;
    }

    // Convert a possibly-negative index expression (or empty) into a clamped
    // usize index, given the container length.
    let to_index = |s: &str, len: usize| -> Option<i64> {
        let s = s.trim();
        if s.is_empty() {
            return None;
        }
        // Allow indices to be variables themselves (e.g. s[i])
        let n: i64 = match s.parse() {
            Ok(v) => v,
            Err(_) => {
                let resolved = vars.get(s).copied()
                    .or_else(|| oop.string_vars.get(s).and_then(|v| v.parse().ok()))?;
                resolved
            }
        };
        if n < 0 {
            Some(((len as i64) + n).max(0))
        } else {
            Some((n as usize).min(len) as i64)
        }
    };

    // Determine if this is a range slice (has a colon) or single index.
    let (raw_start, raw_end, is_range) = if let Some(colon) = inside.find(':') {
        (&inside[..colon], &inside[colon + 1..], true)
    } else {
        (inside, "", false)
    };

    // String variable path.
    if let Some(s) = oop.string_vars.get(var_name).cloned()
        .or_else(|| vars.get(var_name).map(|n| n.to_string()))
    {
        let chars: Vec<char> = s.chars().collect();
        let len = chars.len();
        if is_range {
            let start = to_index(raw_start, len).unwrap_or(0).max(0) as usize;
            let end = to_index(raw_end, len)
                .map(|n| n.max(0) as usize)
                .unwrap_or(len);
            let start = start.min(len);
            let end = end.min(len).max(start);
            return Some(chars[start..end].iter().collect());
        } else {
            let idx = to_index(raw_start, len)?;
            if idx < 0 || (idx as usize) >= len { return Some(String::new()); }
            return Some(chars[idx as usize].to_string());
        }
    }

    // List variable path.
    if let Some(l) = oop.lists.get(var_name) {
        let len = l.len();
        if is_range {
            let start = to_index(raw_start, len).unwrap_or(0).max(0) as usize;
            let end = to_index(raw_end, len)
                .map(|n| n.max(0) as usize)
                .unwrap_or(len);
            let start = start.min(len);
            let end = end.min(len).max(start);
            return Some(l[start..end].join(", "));
        } else {
            let idx = to_index(raw_start, len)?;
            if idx < 0 || (idx as usize) >= len { return Some(String::new()); }
            return Some(l[idx as usize].clone());
        }
    }

    None
}

fn lookup_simple(key: &str, vars: &Vars, oop: &OopState) -> Option<String> {
    if key.is_empty() {
        return None;
    }

    // Slicing / indexing: name[a:b], name[a:], name[:b], name[a]. Negative
    // indices count from the end. Works on string vars (chars) and lists
    // (elements joined with ", " for ranges; single element raw).
    if let Some(open) = key.find('[') {
        if key.ends_with(']') {
            if let Some(result) = try_slice_or_index(&key[..open], &key[open + 1..key.len() - 1], vars, oop) {
                return Some(result);
            }
        }
    }

    if let Some(ctx) = oop.request_context_stack.last() {
        if let Some(v) = ctx.get(key) {
            return Some(v.clone());
        }
    }

    if let Some(dot) = key.find('.') {
        let inst_name = key[..dot].trim();
        let field = key[dot + 1..].trim();
        let actual = if inst_name == "self" {
            oop.self_stack.last().map(|s| s.as_str())
        } else {
            Some(inst_name)
        }?;
        if let Some(instance) = oop.instances.get(actual) {
            return instance.fields.get(field).cloned();
        }
        if let Some(class_def) = oop.classes.get(actual) {
            if let Some(v) = class_def.static_fields.get(field) {
                return Some(v.clone());
            }
        }
        return None;
    }

    if let Some(instance) = oop.instances.get(key) {
        let class_name = instance.class_name.clone();
        if find_method_in_chain(&oop.classes, &class_name, "tostring", None).is_some() {
            return Some(format!("<{}:{}>", class_name, key));
        }
        return Some(format!("<{}:{}>", class_name, key));
    }

    if let Some(v) = oop.string_vars.get(key) {
        return Some(v.clone());
    }

    if let Some(v) = vars.get(key) {
        return Some(v.to_string());
    }

    if let Some(self_name) = oop.self_stack.last() {
        if let Some(inst) = oop.instances.get(self_name) {
            if let Some(v) = inst.fields.get(key) {
                return Some(v.clone());
            }
        }
    }

    // Lists render as comma-joined items so `{xs}` works in interpolation.
    if let Some(l) = oop.lists.get(key) {
        return Some(l.join(", "));
    }

    None
}

fn eval_expression(expr: &str, vars: &Vars, oop: &OopState) -> Option<String> {
    if !expr
        .chars()
        .any(|c| matches!(c, '+' | '-' | '*' | '/' | '%' | '(' | ')' | '^'))
    {
        return None;
    }

    let substituted = substitute_idents(expr, vars, oop);

    match fasteval::ez_eval(&substituted, &mut math_ns()) {
        Ok(n) => {
            if n.is_finite() && n.fract() == 0.0 && n.abs() < 1e18 {
                Some((n as i64).to_string())
            } else {
                Some(format!("{}", n))
            }
        }
        Err(_) => None,
    }
}

// Custom fasteval namespace adding sqrt/ln/log10/log2/pow/atan2 and
// floor/ceil/round (with 0-decimal default) to match the old meval API.
fn math_ns() -> impl fasteval::EvalNamespace {
    move |name: &str, args: Vec<f64>| -> Option<f64> {
        match (name, args.as_slice()) {
            ("sqrt", [x]) => Some(x.sqrt()),
            ("ln", [x]) => Some(x.ln()),
            ("log10", [x]) => Some(x.log10()),
            ("log2", [x]) => Some(x.log2()),
            ("pow", [x, y]) => Some(x.powf(*y)),
            ("atan2", [y, x]) => Some(y.atan2(*x)),
            ("hypot", [a, b]) => Some(a.hypot(*b)),
            ("cbrt", [x]) => Some(x.cbrt()),
            _ => None,
        }
    }
}

fn substitute_idents(expr: &str, vars: &Vars, oop: &OopState) -> String {
    let mut out = String::new();
    let chars: Vec<char> = expr.chars().collect();
    let mut i = 0;

    while i < chars.len() {
        let c = chars[i];

        if c.is_alphabetic() || c == '_' {
            let start = i;
            while i < chars.len()
                && (chars[i].is_alphanumeric() || chars[i] == '_' || chars[i] == '.')
            {
                i += 1;
            }
            let ident: String = chars[start..i].iter().collect();

            match lookup_simple(&ident, vars, oop) {
                Some(v) if v.parse::<f64>().is_ok() => out.push_str(&v),
                _ => out.push_str(&ident),
            }
        } else {
            out.push(c);
            i += 1;
        }
    }

    out
}

fn eval_condition(expr: &str, vars: &Vars, oop: &OopState) -> bool {
    let ops = ["==", "!=", ">=", "<=", ">", "<", "="];
    for op in ops.iter() {
        if let Some(idx) = find_op_outside_quotes(expr, op) {
            let left = &expr[..idx];
            let right = &expr[idx + op.len()..];
            let lval = eval_side(left, vars, oop);
            let rval = eval_side(right, vars, oop);

            if let (Ok(ln), Ok(rn)) = (lval.parse::<f64>(), rval.parse::<f64>()) {
                return match *op {
                    "==" | "=" => ln == rn,
                    "!=" => ln != rn,
                    ">=" => ln >= rn,
                    "<=" => ln <= rn,
                    ">" => ln > rn,
                    "<" => ln < rn,
                    _ => false,
                };
            }

            return match *op {
                "==" | "=" => lval == rval,
                "!=" => lval != rval,
                ">=" => lval >= rval,
                "<=" => lval <= rval,
                ">" => lval > rval,
                "<" => lval < rval,
                _ => false,
            };
        }
    }

    let val = eval_side(expr, vars, oop);
    if let Ok(n) = val.parse::<f64>() {
        return n != 0.0;
    }
    !val.is_empty()
}

fn eval_side(s: &str, vars: &Vars, oop: &OopState) -> String {
    let trimmed = s.trim();
    if trimmed.len() >= 2 && trimmed.starts_with('"') && trimmed.ends_with('"') {
        return interpolate(&trimmed[1..trimmed.len() - 1], vars, oop);
    }
    if let Some(v) = lookup_simple(trimmed, vars, oop) {
        return v;
    }
    if let Some(v) = eval_expression(trimmed, vars, oop) {
        return v;
    }
    trimmed.to_string()
}

fn find_op_outside_quotes(s: &str, op: &str) -> Option<usize> {
    let bytes = s.as_bytes();
    let op_bytes = op.as_bytes();
    let mut in_quote = false;
    let mut i = 0;
    while i + op_bytes.len() <= bytes.len() {
        if bytes[i] == b'"' {
            in_quote = !in_quote;
            i += 1;
            continue;
        }
        if !in_quote && &bytes[i..i + op_bytes.len()] == op_bytes {
            return Some(i);
        }
        i += 1;
    }
    None
}

fn apply_format(value: &str, spec: Option<&str>) -> String {
    let spec = match spec {
        Some(s) if !s.is_empty() => s,
        _ => return value.to_string(),
    };

    if let Some(prec_str) = spec.strip_suffix('f') {
        let trimmed = prec_str.trim_start_matches('0').trim_start_matches('.');
        if let (Ok(n), Ok(p)) = (value.parse::<f64>(), trimmed.parse::<usize>()) {
            return format!("{:.*}", p, n);
        }
    }

    if let Some(width_str) = spec.strip_prefix('0') {
        if let (Ok(n), Ok(w)) = (value.parse::<i64>(), width_str.parse::<usize>()) {
            return format!("{:0width$}", n, width = w);
        }
    }

    if let Ok(w) = spec.parse::<usize>() {
        return format!("{:>width$}", value, width = w);
    }

    value.to_string()
}

fn execute(
    line: &str,
    vars: &mut Vars,
    server_cfg: &mut Option<ServerConfig>,
    oop: &mut OopState,
) -> bool {
    let line_stripped = strip_trailing_comment(line);
    let line = line_stripped.trim();

    if line.is_empty() || line.starts_with(":") {
        return true;
    }

    // Known decorators pass through; other @-lines are metadata (skipped)
    const DECORATORS: &[&str] = &["@timed ", "@logged ", "@once ", "@retry "];
    let is_decorator = DECORATORS.iter().any(|d| line.starts_with(d));
    if !is_decorator && (line.starts_with('@') || line.eq_ignore_ascii_case("---code---")) {
        return true;
    }

    if let Some(cfg) = server_cfg.as_mut() {
        if cfg.capturing_route_body.is_some() {
            if line == "endroute" {
                let body = cfg.capturing_route_body.take().unwrap_or_default();
                if let Some((m, p)) = cfg.current_route.clone() {
                    let segments: Vec<String> =
                        p.trim_start_matches('/').split('/').map(String::from).collect();
                    cfg.dynamic_routes.push((
                        (m, p),
                        DynamicRoute {
                            pattern_segments: segments,
                            body,
                        },
                    ));
                }
                return true;
            }
            cfg.capturing_route_body
                .as_mut()
                .unwrap()
                .push(line.to_string());
            return true;
        }
    }

    if let Some(class_name) = oop.current_class.clone() {
        if let Some(method_name) = oop.current_method.clone() {
            if line == "endmethod" {
                oop.current_method = None;
                oop.method_static_flag = false;
                return true;
            }
            let is_static = oop.method_static_flag;
            if let Some(c) = oop.classes.get_mut(&class_name) {
                let target = if is_static {
                    c.static_methods.get_mut(&method_name)
                } else {
                    c.methods.get_mut(&method_name)
                };
                if let Some(m) = target {
                    m.body.push(line.to_string());
                }
            }
            return true;
        }

        if line == "endclass" {
            oop.current_class = None;
            return true;
        }

        if let Some(rest) = line.strip_prefix("static field ") {
            let parts: Vec<&str> = rest.splitn(2, '=').collect();
            if parts.len() == 2 {
                let name = parts[0].trim().to_string();
                let value = strip_outer_quotes(parts[1].trim()).to_string();
                if let Some(c) = oop.classes.get_mut(&class_name) {
                    c.static_fields.insert(name, value);
                }
            }
            return true;
        }

        if let Some(rest) = line.strip_prefix("field ") {
            let parts: Vec<&str> = rest.splitn(2, '=').collect();
            if parts.len() == 2 {
                let name = parts[0].trim().to_string();
                let value = strip_outer_quotes(parts[1].trim()).to_string();
                if let Some(c) = oop.classes.get_mut(&class_name) {
                    c.fields.push((name, value));
                }
            }
            return true;
        }

        if let Some(m) = line.strip_prefix("static method ") {
            let tokens: Vec<&str> = m.split_whitespace().collect();
            if let Some(name) = tokens.first() {
                let params: Vec<String> =
                    tokens[1..].iter().map(|s| s.to_string()).collect();
                if let Some(c) = oop.classes.get_mut(&class_name) {
                    c.static_methods.insert(
                        name.to_string(),
                        MethodDef {
                            params,
                            body: Vec::new(),
                        },
                    );
                }
                oop.current_method = Some(name.to_string());
                oop.method_static_flag = true;
            }
            return true;
        }

        if let Some(m) = line.strip_prefix("method ") {
            let tokens: Vec<&str> = m.split_whitespace().collect();
            if let Some(name) = tokens.first() {
                let params: Vec<String> =
                    tokens[1..].iter().map(|s| s.to_string()).collect();
                if let Some(c) = oop.classes.get_mut(&class_name) {
                    c.methods.insert(
                        name.to_string(),
                        MethodDef {
                            params,
                            body: Vec::new(),
                        },
                    );
                }
                oop.current_method = Some(name.to_string());
                oop.method_static_flag = false;
            }
            return true;
        }

        return true;
    }

    if let Some(func_name) = oop.current_func.clone() {
        if line == "endfunc" {
            oop.current_func = None;
            return true;
        }
        if let Some(f) = oop.functions.get_mut(&func_name) {
            f.body.push(line.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("func ") {
        let tokens: Vec<&str> = rest.split_whitespace().collect();
        if tokens.is_empty() {
            println!("func: missing name");
            return true;
        }
        let raw_name = tokens[0].to_string();
        let fn_name = match &oop.current_module {
            Some(m) => format!("{}.{}", m, raw_name),
            None => raw_name,
        };
        let params: Vec<String> = tokens[1..].iter().map(|s| s.to_string()).collect();
        oop.functions.insert(
            fn_name.clone(),
            FuncDef {
                params,
                body: Vec::new(),
            },
        );
        oop.current_func = Some(fn_name);
        return true;
    }

    if !oop.while_stack.is_empty() {
        if line == "endwhile" {
            let top_depth = oop.while_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.while_stack.last_mut().unwrap();
                top.depth -= 1;
                top.body.push(line.to_string());
                return true;
            }
            let def = oop.while_stack.pop().unwrap();
            let mut max_iter: u32 = 1_000_000;
            while max_iter > 0 && eval_condition(&def.condition, vars, oop) {
                max_iter -= 1;
                let mut should_break = false;
                for body_line in &def.body {
                    if !execute(body_line, vars, server_cfg, oop) {
                        return false;
                    }
                    if oop.break_flag {
                        oop.break_flag = false;
                        should_break = true;
                        break;
                    }
                    if oop.continue_flag {
                        oop.continue_flag = false;
                        break;
                    }
                }
                if should_break {
                    break;
                }
            }
            if max_iter == 0 {
                println!("\x1b[33mwhile: max iterations hit (safety limit)\x1b[0m");
            }
            return true;
        }
        if line.starts_with("while ") {
            let top = oop.while_stack.last_mut().unwrap();
            top.depth += 1;
            top.body.push(line.to_string());
            return true;
        }
        oop.while_stack
            .last_mut()
            .unwrap()
            .body
            .push(line.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("while ") {
        oop.while_stack.push(WhileDef {
            condition: rest.to_string(),
            body: Vec::new(),
            depth: 0,
        });
        return true;
    }

    if !oop.foreach_stack.is_empty() {
        if line == "endforeach" {
            let top_depth = oop.foreach_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.foreach_stack.last_mut().unwrap();
                top.depth -= 1;
                top.body.push(line.to_string());
                return true;
            }
            let def = oop.foreach_stack.pop().unwrap();
            // v2.0: allow ranges like `foreach i in 0..10` — generate items
            // on the fly. `a..b` = [a, a+1, ..., b-1]. Both endpoints may
            // resolve from variables. If parsing fails, falls back to list.
            let items: Vec<String> = if let Some(dotdot) = def.list_name.find("..") {
                let a_s = def.list_name[..dotdot].trim();
                let b_s = def.list_name[dotdot + 2..].trim();
                let resolve_num = |s: &str| -> Option<i64> {
                    s.parse::<i64>().ok()
                        .or_else(|| vars.get(s).copied())
                        .or_else(|| oop.string_vars.get(s).and_then(|v| v.parse().ok()))
                };
                match (resolve_num(a_s), resolve_num(b_s)) {
                    (Some(a), Some(b)) if a <= b => (a..b).map(|n| n.to_string()).collect(),
                    (Some(a), Some(b)) => (b..a).rev().map(|n| n.to_string()).collect(),
                    _ => oop.lists.get(&def.list_name).cloned().unwrap_or_default(),
                }
            } else {
                oop.lists.get(&def.list_name).cloned().unwrap_or_default()
            };
            let mut broke = false;
            for item in items {
                let prev = oop.string_vars.insert(def.var.clone(), item.clone());
                for body_line in &def.body {
                    if !execute(body_line, vars, server_cfg, oop) {
                        return false;
                    }
                    if oop.break_flag {
                        oop.break_flag = false;
                        broke = true;
                        break;
                    }
                    if oop.continue_flag {
                        oop.continue_flag = false;
                        break;
                    }
                }
                match prev {
                    Some(v) => {
                        oop.string_vars.insert(def.var.clone(), v);
                    }
                    None => {
                        oop.string_vars.remove(&def.var);
                    }
                }
                if broke {
                    break;
                }
            }
            return true;
        }
        if line.starts_with("foreach ") {
            let top = oop.foreach_stack.last_mut().unwrap();
            top.depth += 1;
            top.body.push(line.to_string());
            return true;
        }
        oop.foreach_stack
            .last_mut()
            .unwrap()
            .body
            .push(line.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("foreach ") {
        let toks: Vec<&str> = rest.split_whitespace().collect();
        if toks.len() >= 3 && toks[1] == "in" {
            oop.foreach_stack.push(ForeachDef {
                var: toks[0].to_string(),
                list_name: toks[2].to_string(),
                body: Vec::new(),
                depth: 0,
            });
        }
        return true;
    }

    if !oop.switch_stack.is_empty() {
        // v2.0: accept `endmatch` alongside `endswitch`.
        if line == "endswitch" || line == "endmatch" {
            let top_depth = oop.switch_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.switch_stack.last_mut().unwrap();
                top.depth -= 1;
                if top.in_case {
                    top.current_body.push(line.to_string());
                }
                return true;
            }
            let mut def = oop.switch_stack.pop().unwrap();
            if def.in_default && !def.has_matched_ever {
                def.matched_body = std::mem::take(&mut def.current_body);
            } else if def.matched && def.matched_body.is_empty() {
                def.matched_body = std::mem::take(&mut def.current_body);
            }
            for body_line in &def.matched_body {
                if !execute(body_line, vars, server_cfg, oop) {
                    return false;
                }
                if oop.break_flag {
                    oop.break_flag = false;
                    break;
                }
            }
            return true;
        }
        if line.starts_with("case ") {
            let case_val = resolve_arg(line[5..].trim(), vars, oop);
            let top = oop.switch_stack.last_mut().unwrap();
            if top.depth > 0 {
                top.current_body.push(line.to_string());
                return true;
            }
            if top.matched && !top.has_matched_ever {
                top.matched_body = std::mem::take(&mut top.current_body);
                top.has_matched_ever = true;
            }
            top.current_body.clear();
            top.in_case = true;
            top.in_default = false;
            top.matched = case_val == top.value && !top.has_matched_ever;
            return true;
        }
        if line == "default" {
            let top = oop.switch_stack.last_mut().unwrap();
            if top.depth > 0 {
                top.current_body.push(line.to_string());
                return true;
            }
            if top.matched && !top.has_matched_ever {
                top.matched_body = std::mem::take(&mut top.current_body);
                top.has_matched_ever = true;
            }
            top.current_body.clear();
            top.in_case = true;
            top.in_default = true;
            top.matched = false;
            return true;
        }
        if line.starts_with("switch ") {
            let top = oop.switch_stack.last_mut().unwrap();
            top.depth += 1;
            top.current_body.push(line.to_string());
            return true;
        }
        let top = oop.switch_stack.last_mut().unwrap();
        if top.in_case {
            top.current_body.push(line.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("switch ") {
        let val = resolve_arg(rest.trim(), vars, oop);
        oop.switch_stack.push(SwitchDef {
            value: val,
            ..SwitchDef::default()
        });
        return true;
    }

    // v2.0: `match x` / `case ...` / `endmatch` — friendlier alias for the
    // existing switch construct. Same body semantics, cleaner keyword.
    if let Some(rest) = line.strip_prefix("match ") {
        let val = resolve_arg(rest.trim(), vars, oop);
        oop.switch_stack.push(SwitchDef {
            value: val,
            ..SwitchDef::default()
        });
        return true;
    }

    if !oop.try_stack.is_empty() {
        if line == "endtry" {
            let top_depth = oop.try_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.try_stack.last_mut().unwrap();
                top.depth -= 1;
                if top.in_catch {
                    top.catch_body.push(line.to_string());
                } else {
                    top.try_body.push(line.to_string());
                }
                return true;
            }
            let def = oop.try_stack.pop().unwrap();
            let prev_err = oop.error_message.take();
            for body_line in &def.try_body {
                if !execute(body_line, vars, server_cfg, oop) {
                    break;
                }
                if oop.error_message.is_some() {
                    break;
                }
            }
            if let Some(err) = oop.error_message.take() {
                if !def.err_var.is_empty() {
                    oop.string_vars.insert(def.err_var.clone(), err);
                }
                for body_line in &def.catch_body {
                    if !execute(body_line, vars, server_cfg, oop) {
                        return false;
                    }
                }
            }
            oop.error_message = prev_err;
            return true;
        }
        if line.starts_with("catch") {
            let top_depth = oop.try_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.try_stack.last_mut().unwrap();
                if top.in_catch {
                    top.catch_body.push(line.to_string());
                } else {
                    top.try_body.push(line.to_string());
                }
                return true;
            }
            let var = if let Some(rest) = line.strip_prefix("catch ") {
                rest.trim().to_string()
            } else {
                String::new()
            };
            let top = oop.try_stack.last_mut().unwrap();
            top.err_var = var;
            top.in_catch = true;
            return true;
        }
        if line.starts_with("try") && (line.len() == 3 || line.chars().nth(3).map(|c| c.is_whitespace()).unwrap_or(false)) {
            let top = oop.try_stack.last_mut().unwrap();
            top.depth += 1;
            if top.in_catch {
                top.catch_body.push(line.to_string());
            } else {
                top.try_body.push(line.to_string());
            }
            return true;
        }
        let top = oop.try_stack.last_mut().unwrap();
        if top.in_catch {
            top.catch_body.push(line.to_string());
        } else {
            top.try_body.push(line.to_string());
        }
        return true;
    }

    if line == "try" {
        oop.try_stack.push(TryDef::default());
        return true;
    }

    if let Some(rest) = line.strip_prefix("raise ") {
        oop.error_message = Some(resolve_arg(rest.trim(), vars, oop));
        return true;
    }

    if !oop.repeat_stack.is_empty() {
        if line == "endrepeat" {
            let top_depth = oop.repeat_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.repeat_stack.last_mut().unwrap();
                top.depth -= 1;
                top.body.push(line.to_string());
                return true;
            }
            let def = oop.repeat_stack.pop().unwrap();
            let mut broke = false;
            for iter in 1..=def.count {
                if let Some(var) = &def.counter_var {
                    vars.insert(var.clone(), iter);
                }
                for body_line in &def.body {
                    if !execute(body_line, vars, server_cfg, oop) {
                        return false;
                    }
                    if oop.break_flag {
                        oop.break_flag = false;
                        broke = true;
                        break;
                    }
                    if oop.continue_flag {
                        oop.continue_flag = false;
                        break;
                    }
                }
                if broke {
                    break;
                }
            }
            return true;
        }

        if line.starts_with("repeat ") {
            let top = oop.repeat_stack.last_mut().unwrap();
            top.depth += 1;
            top.body.push(line.to_string());
            return true;
        }

        oop.repeat_stack
            .last_mut()
            .unwrap()
            .body
            .push(line.to_string());
        return true;
    }

    if !oop.if_stack.is_empty() {
        if line == "endif" {
            let top_depth = oop.if_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.if_stack.last_mut().unwrap();
                top.depth -= 1;
                if top.in_else {
                    top.else_body.push(line.to_string());
                } else {
                    top.then_body.push(line.to_string());
                }
                return true;
            }
            let def = oop.if_stack.pop().unwrap();
            let body = if def.condition {
                def.then_body
            } else {
                def.else_body
            };
            for body_line in &body {
                if !execute(body_line, vars, server_cfg, oop) {
                    return false;
                }
            }
            return true;
        }

        if line == "else" {
            let top_depth = oop.if_stack.last().unwrap().depth;
            if top_depth > 0 {
                let top = oop.if_stack.last_mut().unwrap();
                if top.in_else {
                    top.else_body.push(line.to_string());
                } else {
                    top.then_body.push(line.to_string());
                }
                return true;
            }
            oop.if_stack.last_mut().unwrap().in_else = true;
            return true;
        }

        if line.starts_with("if ") {
            let top = oop.if_stack.last_mut().unwrap();
            top.depth += 1;
            if top.in_else {
                top.else_body.push(line.to_string());
            } else {
                top.then_body.push(line.to_string());
            }
            return true;
        }

        let top = oop.if_stack.last_mut().unwrap();
        if top.in_else {
            top.else_body.push(line.to_string());
        } else {
            top.then_body.push(line.to_string());
        }
        return true;
    }

    if line == "break" {
        oop.break_flag = true;
        return true;
    }

    if line == "continue" {
        oop.continue_flag = true;
        return true;
    }

    if line == "return" {
        oop.return_flag = true;
        oop.return_value = None;
        return true;
    }

    if let Some(rest) = line.strip_prefix("return ") {
        let resolved = resolve_arg(rest.trim(), vars, oop);
        oop.return_flag = true;
        oop.return_value = Some(resolved);
        return true;
    }

    if let Some(rest) = line.strip_prefix("send ") {
        let body = interpolate(strip_outer_quotes(rest), vars, oop);
        let existing = oop
            .string_vars
            .get("__response_body__")
            .cloned()
            .unwrap_or_default();
        let combined = if existing.is_empty() {
            body
        } else {
            format!("{}{}", existing, body)
        };
        oop.string_vars
            .insert("__response_body__".into(), combined);
        return true;
    }

    if let Some(rest) = line.strip_prefix("status ") {
        let val = interpolate(strip_outer_quotes(rest.trim()), vars, oop);
        oop.string_vars.insert("__response_status__".into(), val);
        return true;
    }

    if let Some(rest) = line.strip_prefix("ctype ") {
        let val = interpolate(strip_outer_quotes(rest.trim()), vars, oop);
        oop.string_vars.insert("__response_ctype__".into(), val);
        return true;
    }

    if let Some(rest) = line.strip_prefix("instanceof ") {
        let tokens: Vec<&str> = rest.split_whitespace().collect();
        if tokens.len() >= 2 {
            let inst_name = tokens[0];
            let class_name = tokens[1];
            let result_var = tokens.iter().position(|t| *t == "->").and_then(|i| tokens.get(i + 1));
            let result = match oop.instances.get(inst_name) {
                Some(inst) => {
                    let mut cur = Some(inst.class_name.clone());
                    let mut found = false;
                    while let Some(c) = cur {
                        if c == class_name {
                            found = true;
                            break;
                        }
                        cur = oop.classes.get(&c).and_then(|cd| cd.parent.clone());
                    }
                    if found { "true" } else { "false" }
                }
                None => "false",
            };
            if let Some(v) = result_var {
                apply_return(vars, oop, Some(v.to_string()), Some(result.to_string()));
            } else {
                println!("{}", result);
            }
        }
        return true;
    }

    // clone <instance> -> <newvar>  — deep-copy an instance into a new name.
    if let Some(rest) = line.strip_prefix("clone ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        if parts.len() == 2 {
            let src = parts[0].trim();
            let dst = parts[1].trim().to_string();
            if let Some(inst) = oop.instances.get(src).cloned() {
                oop.instances.insert(dst, inst);
            } else {
                println!("clone: '{}' is not an instance", src);
            }
        }
        return true;
    }

    // classname <instance> -> <var>  — returns the class name of an instance.
    if let Some(rest) = line.strip_prefix("classname ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let name = parts[0].trim();
        let cn = oop.instances.get(name).map(|i| i.class_name.clone());
        apply_return(vars, oop, result_var, cn.or_else(|| Some(String::new())));
        return true;
    }

    // is_subclass <child> <parent> -> <var>  — returns 1 if child extends parent
    // (transitively). Both args are class names, not instances.
    if let Some(rest) = line.strip_prefix("is_subclass ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let toks: Vec<&str> = parts[0].split_whitespace().collect();
        let mut is_sub = 0;
        if toks.len() >= 2 {
            let child = toks[0];
            let parent = toks[1];
            if child == parent { is_sub = 1; }
            else {
                let mut cur = oop.classes.get(child).and_then(|c| c.parent.clone());
                while let Some(p) = cur {
                    if p == parent { is_sub = 1; break; }
                    cur = oop.classes.get(&p).and_then(|c| c.parent.clone());
                }
            }
        }
        apply_return(vars, oop, result_var, Some(is_sub.to_string()));
        return true;
    }

    // field_names <instance> <listname>  — populate a list with the field names
    // of the instance (useful for serializers, debug dumps, etc).
    if let Some(rest) = line.strip_prefix("field_names ") {
        let toks: Vec<&str> = rest.split_whitespace().collect();
        if toks.len() == 2 {
            let inst_name = toks[0];
            let list_name = toks[1].to_string();
            let mut names: Vec<String> = if let Some(inst) = oop.instances.get(inst_name) {
                inst.fields.keys().cloned().collect()
            } else {
                Vec::new()
            };
            names.sort();
            oop.lists.insert(list_name, names);
        }
        return true;
    }

    // method_names <classname> <listname>  — list method names of a class
    // (excludes inherited methods; use is_subclass to walk the chain).
    if let Some(rest) = line.strip_prefix("method_names ") {
        let toks: Vec<&str> = rest.split_whitespace().collect();
        if toks.len() == 2 {
            let class_name = toks[0];
            let list_name = toks[1].to_string();
            let mut names: Vec<String> = if let Some(cls) = oop.classes.get(class_name) {
                cls.methods.keys().cloned().collect()
            } else {
                Vec::new()
            };
            names.sort();
            oop.lists.insert(list_name, names);
        }
        return true;
    }

    // call_method <instance> "<methodname>" <args...>  — dynamic dispatch.
    // Calls a method by name string, e.g. for reflection-style code.
    if let Some(rest) = line.strip_prefix("call_method ") {
        let toks: Vec<&str> = rest.splitn(3, char::is_whitespace).collect();
        if toks.len() >= 2 {
            let inst_name = toks[0].trim();
            let method = resolve_arg(toks[1].trim(), vars, oop);
            let extra = toks.get(2).copied().unwrap_or("").trim();
            // Build "call instance.method args" and dispatch through normal path.
            let cmd = if extra.is_empty() {
                format!("call {}.{}", inst_name, method)
            } else {
                format!("call {}.{} {}", inst_name, method, extra)
            };
            return execute(&cmd, vars, server_cfg, oop);
        }
        return true;
    }

    // has_method <classname> "<methodname>" -> var  — returns 1 if the class
    // (or any ancestor) defines the method.
    if let Some(rest) = line.strip_prefix("has_method ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let toks: Vec<&str> = parts[0].split_whitespace().collect();
        let mut has = 0;
        if toks.len() >= 2 {
            let cn = toks[0];
            let mname = resolve_arg(toks[1], vars, oop);
            let mut cur = Some(cn.to_string());
            while let Some(c) = cur {
                if let Some(cls) = oop.classes.get(&c) {
                    if cls.methods.contains_key(&mname) { has = 1; break; }
                    cur = cls.parent.clone();
                } else { break; }
            }
        }
        apply_return(vars, oop, result_var, Some(has.to_string()));
        return true;
    }

    // parent_of <classname> -> var  — returns the parent class name or "" if none.
    if let Some(rest) = line.strip_prefix("parent_of ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let cn = parts[0].trim();
        let p = oop.classes.get(cn).and_then(|c| c.parent.clone()).unwrap_or_default();
        apply_return(vars, oop, result_var, Some(p));
        return true;
    }

    if let Some(rest) = line.strip_prefix("typeof ") {
        let tokens: Vec<&str> = rest.split_whitespace().collect();
        if let Some(name) = tokens.first() {
            let result_var = tokens.iter().position(|t| *t == "->").and_then(|i| tokens.get(i + 1));
            let t = if let Some(inst) = oop.instances.get(*name) {
                inst.class_name.clone()
            } else if oop.classes.contains_key(*name) {
                "Class".to_string()
            } else if oop.string_vars.contains_key(*name) {
                "string".to_string()
            } else if vars.contains_key(*name) {
                "int".to_string()
            } else if oop.functions.contains_key(*name) {
                "function".to_string()
            } else {
                "undefined".to_string()
            };
            if let Some(v) = result_var {
                apply_return(vars, oop, Some(v.to_string()), Some(t));
            } else {
                println!("{}", t);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("repeat ") {
        let parts: Vec<&str> = rest.split_whitespace().collect();
        // First arg may be a literal int or a variable name — resolve either way.
        let count: i64 = parts
            .first()
            .map(|s| parse_i64_loose(&resolve_arg(s, vars, oop)))
            .unwrap_or(0);
        let counter_var = parts.get(1).map(|s| s.to_string());
        oop.repeat_stack.push(RepeatDef {
            count,
            counter_var,
            body: Vec::new(),
            depth: 0,
        });
        return true;
    }

    if let Some(cond_expr) = line.strip_prefix("if ") {
        let condition = eval_condition(cond_expr, vars, oop);
        oop.if_stack.push(IfDef {
            condition,
            then_body: Vec::new(),
            else_body: Vec::new(),
            in_else: false,
            depth: 0,
        });
        return true;
    }

    if let Some(name) = line.strip_prefix("class ") {
        let tokens: Vec<&str> = name.split_whitespace().collect();
        let raw_name = tokens[0].to_string();
        let class_name = match &oop.current_module {
            Some(m) => format!("{}.{}", m, raw_name),
            None => raw_name,
        };
        let parent = if tokens.len() >= 3 && tokens[1] == "extends" {
            Some(tokens[2].to_string())
        } else {
            None
        };
        let mut def = ClassDef::default();
        def.parent = parent;
        oop.classes.insert(class_name.clone(), def);
        oop.current_class = Some(class_name);
        return true;
    }

    if let Some(name) = line.strip_prefix("module ") {
        let mname = name.trim().to_string();
        oop.modules.insert(mname.clone(), String::new());
        oop.current_module = Some(mname);
        return true;
    }

    if line == "endmodule" {
        oop.current_module = None;
        return true;
    }

    if !oop.current_interface.is_none() {
        let iname = oop.current_interface.clone().unwrap();
        if line == "endinterface" {
            oop.current_interface = None;
            return true;
        }
        if let Some(m) = line.strip_prefix("method ") {
            let mname = m.split_whitespace().next().unwrap_or("").to_string();
            if let Some(list) = oop.interfaces.get_mut(&iname) {
                list.push(mname);
            }
            return true;
        }
        return true;
    }

    if let Some(name) = line.strip_prefix("interface ") {
        let iname = name.trim().to_string();
        oop.interfaces.insert(iname.clone(), Vec::new());
        oop.current_interface = Some(iname);
        return true;
    }

    if let Some(rest) = line.strip_prefix("enum ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let ename = parts[0].trim().to_string();
            let mut def = ClassDef::default();
            for v in parts[1].split(',') {
                let key = v.trim().to_string();
                def.static_fields.insert(key.clone(), key);
            }
            oop.classes.insert(ename, def);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("const ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let name = parts[0].trim().to_string();
            let value = resolve_arg(parts[1].trim(), vars, oop);
            if let Ok(n) = value.parse::<i64>() {
                vars.insert(name, n);
            } else {
                oop.string_vars.insert(name, value);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("implements ") {
        let toks: Vec<&str> = rest.split_whitespace().collect();
        if toks.len() >= 2 {
            let class_name = toks[0];
            let iface_name = toks[1];
            let required: Vec<String> = oop
                .interfaces
                .get(iface_name)
                .cloned()
                .unwrap_or_default();
            if let Some(class) = oop.classes.get(class_name) {
                let mut missing: Vec<String> = Vec::new();
                for m in &required {
                    if !class.methods.contains_key(m) {
                        missing.push(m.clone());
                    }
                }
                if missing.is_empty() {
                    println!("OK: {} implements {}", class_name, iface_name);
                } else {
                    println!(
                        "FAIL: {} missing methods for {}: {}",
                        class_name,
                        iface_name,
                        missing.join(", ")
                    );
                }
            } else {
                println!("implements: class '{}' not found", class_name);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("new ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let inst_name = parts[0].trim().to_string();
            let class_spec = parts[1].trim();

            let (class_name, args_str): (String, String) = if let Some(open) = class_spec.find('(') {
                if let Some(close) = class_spec.rfind(')') {
                    (
                        class_spec[..open].trim().to_string(),
                        class_spec[open + 1..close].to_string(),
                    )
                } else {
                    (class_spec.to_string(), String::new())
                }
            } else {
                (class_spec.to_string(), String::new())
            };

            let raw_args: Vec<String> = if args_str.trim().is_empty() {
                Vec::new()
            } else {
                args_str.split(',').map(|s| s.trim().to_string()).collect()
            };

            if !oop.classes.contains_key(&class_name) {
                println!("Class '{}' not found", class_name);
                return true;
            }

            let inherited = collect_inherited_fields(&oop.classes, &class_name);
            let mut fields = HashMap::new();
            for (fname, fdefault) in &inherited {
                fields.insert(fname.clone(), interpolate(fdefault, vars, oop));
            }
            oop.instances.insert(
                inst_name.clone(),
                Instance {
                    class_name: class_name.clone(),
                    fields,
                },
            );

            if let Some((owner, method)) =
                find_method_in_chain(&oop.classes, &class_name, "init", None)
            {
                let mut saved: Vec<(String, Option<String>)> = Vec::new();
                for (i, param) in method.params.iter().enumerate() {
                    saved.push((param.clone(), oop.string_vars.get(param).cloned()));
                    let arg_raw = raw_args.get(i).cloned().unwrap_or_default();
                    let resolved = resolve_arg(&arg_raw, vars, oop);
                    oop.string_vars.insert(param.clone(), resolved);
                }

                oop.self_stack.push(inst_name.clone());
                oop.method_owner_stack.push(owner);
                let save_ret = oop.return_flag;
                oop.return_flag = false;
                for l in &method.body {
                    if !execute(l, vars, server_cfg, oop) {
                        oop.method_owner_stack.pop();
                        oop.self_stack.pop();
                        oop.return_flag = save_ret;
                        return false;
                    }
                    if oop.return_flag {
                        oop.return_flag = false;
                        break;
                    }
                }
                oop.return_flag = save_ret;
                oop.method_owner_stack.pop();
                oop.self_stack.pop();

                for (name, prev) in saved {
                    match prev {
                        Some(v) => {
                            oop.string_vars.insert(name, v);
                        }
                        None => {
                            oop.string_vars.remove(&name);
                        }
                    }
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("setf ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let lhs = parts[0].trim();
            let value = resolve_arg(parts[1].trim(), vars, oop);
            let mut dot = lhs.splitn(2, '.');
            if let (Some(inst), Some(field)) = (dot.next(), dot.next()) {
                if let Some(instance) = oop.instances.get_mut(inst.trim()) {
                    instance.fields.insert(field.trim().to_string(), value);
                } else {
                    println!("Instance '{}' not found", inst.trim());
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("getf ") {
        let mut dot = rest.trim().splitn(2, '.');
        if let (Some(inst), Some(field)) = (dot.next(), dot.next()) {
            if let Some(instance) = oop.instances.get(inst.trim()) {
                match instance.fields.get(field.trim()) {
                    Some(v) => println!("{}", v),
                    None => println!("Field '{}' not found", field.trim()),
                }
            } else {
                println!("Instance '{}' not found", inst.trim());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("call ") {
        let rest_trim = rest.trim();

        let (call_part, result_var) = match rest_trim.rfind("->") {
            Some(idx) => (
                rest_trim[..idx].trim().to_string(),
                Some(rest_trim[idx + 2..].trim().to_string()),
            ),
            None => (rest_trim.to_string(), None),
        };

        let first_token_end = call_part
            .find(char::is_whitespace)
            .unwrap_or(call_part.len());
        let target = &call_part[..first_token_end];
        let args_part = &call_part[first_token_end..];
        let raw_args: Vec<String> = split_args(args_part);

        if target.contains('.') {
            let mut dot = target.splitn(2, '.');
            let lhs = dot.next().unwrap_or("").trim().to_string();
            let method_name = dot.next().unwrap_or("").trim().to_string();

            if lhs == "self" {
                let self_name = oop.self_stack.last().cloned();
                if let Some(self_name) = self_name {
                    let class_of_self = oop
                        .instances
                        .get(&self_name)
                        .map(|i| i.class_name.clone());
                    if let Some(cur_class) = class_of_self {
                        if let Some((owner, method)) = find_method_in_chain(
                            &oop.classes,
                            &cur_class,
                            &method_name,
                            None,
                        ) {
                            let captured = capture_call_return(
                                vars,
                                server_cfg,
                                oop,
                                Some(self_name.clone()),
                                &method,
                                &raw_args,
                                Some(owner),
                            );
                            if !captured.0 {
                                return false;
                            }
                            apply_return(vars, oop, result_var, captured.1);
                            return true;
                        } else {
                            println!("self.{}: method not found", method_name);
                            return true;
                        }
                    }
                }
                println!("self.{}: no enclosing self", method_name);
                return true;
            }

            if lhs == "super" {
                let self_name = oop.self_stack.last().cloned();
                let current_owner = oop.method_owner_stack.last().cloned();
                if let (Some(self_name), Some(cur_owner)) = (self_name, current_owner) {
                    if let Some((owner, method)) = find_method_in_chain(
                        &oop.classes,
                        &cur_owner,
                        &method_name,
                        Some(&cur_owner),
                    ) {
                        let captured = capture_call_return(
                            vars,
                            server_cfg,
                            oop,
                            Some(self_name.clone()),
                            &method,
                            &raw_args,
                            Some(owner),
                        );
                        if !captured.0 {
                            return false;
                        }
                        apply_return(vars, oop, result_var, captured.1);
                        return true;
                    } else {
                        println!("super.{}: parent method not found", method_name);
                        return true;
                    }
                }
                println!("super.{}: no enclosing self/method", method_name);
                return true;
            }

            if let Some(inst) = oop.instances.get(&lhs).cloned() {
                if let Some((owner, method)) =
                    find_method_in_chain(&oop.classes, &inst.class_name, &method_name, None)
                {
                    let captured = capture_call_return(
                        vars,
                        server_cfg,
                        oop,
                        Some(lhs.clone()),
                        &method,
                        &raw_args,
                        Some(owner),
                    );
                    if !captured.0 {
                        return false;
                    }
                    apply_return(vars, oop, result_var, captured.1);
                    return true;
                } else {
                    println!("Method '{}' not found on instance '{}'", method_name, lhs);
                    return true;
                }
            }

            if let Some(class_def) = oop.classes.get(&lhs).cloned() {
                if let Some(method) = class_def.static_methods.get(&method_name).cloned() {
                    let captured =
                        capture_call_return(vars, server_cfg, oop, None, &method, &raw_args, Some(lhs.clone()));
                    if !captured.0 {
                        return false;
                    }
                    apply_return(vars, oop, result_var, captured.1);
                    return true;
                } else if let Some(v) = class_def.static_fields.get(&method_name) {
                    apply_return(vars, oop, result_var, Some(v.clone()));
                    return true;
                } else {
                    println!("Static '{}.{}' not found", lhs, method_name);
                    return true;
                }
            }

            let namespaced = format!("{}.{}", lhs, method_name);
            if let Some(func) = oop.functions.get(&namespaced).cloned() {
                let mut saved: Vec<(String, Option<String>)> = Vec::new();
                for (i, param) in func.params.iter().enumerate() {
                    saved.push((param.clone(), oop.string_vars.get(param).cloned()));
                    let arg_raw = raw_args.get(i).cloned().unwrap_or_default();
                    let resolved = resolve_arg(&arg_raw, vars, oop);
                    oop.string_vars.insert(param.clone(), resolved);
                }
                let save_return = oop.return_flag;
                let save_retval = oop.return_value.take();
                oop.return_flag = false;
                for body_line in &func.body {
                    if !execute(body_line, vars, server_cfg, oop) {
                        break;
                    }
                    if oop.return_flag {
                        break;
                    }
                }
                let captured = oop.return_value.take();
                oop.return_flag = save_return;
                oop.return_value = save_retval;
                for (name, prev) in saved {
                    match prev {
                        Some(v) => {
                            oop.string_vars.insert(name, v);
                        }
                        None => {
                            oop.string_vars.remove(&name);
                        }
                    }
                }
                apply_return(vars, oop, result_var, captured);
                return true;
            }

            println!("'{}' is not an instance, class, or module", lhs);
            return true;
        }

        let mut fn_name = target.to_string();
        if !oop.functions.contains_key(&fn_name) {
            if let Some(v) = oop.string_vars.get(&fn_name) {
                if oop.functions.contains_key(v) {
                    fn_name = v.clone();
                }
            }
        }
        let func = match oop.functions.get(&fn_name).cloned() {
            Some(f) => f,
            None => {
                println!("Function '{}' not found", fn_name);
                return true;
            }
        };

        let mut saved: Vec<(String, Option<String>)> = Vec::new();
        for (i, param) in func.params.iter().enumerate() {
            saved.push((param.clone(), oop.string_vars.get(param).cloned()));
            let arg_raw = raw_args.get(i).cloned().unwrap_or_default();
            let resolved = resolve_arg(&arg_raw, vars, oop);
            oop.string_vars.insert(param.clone(), resolved);
        }

        let save_break = oop.break_flag;
        let save_continue = oop.continue_flag;
        let save_return = oop.return_flag;
        let save_retval = oop.return_value.take();
        oop.break_flag = false;
        oop.continue_flag = false;
        oop.return_flag = false;

        let mut keep_going = true;
        for body_line in &func.body {
            if !execute(body_line, vars, server_cfg, oop) {
                keep_going = false;
                break;
            }
            if oop.return_flag {
                break;
            }
        }

        let captured_return = oop.return_value.take();
        oop.return_flag = save_return;
        oop.return_value = save_retval;
        oop.break_flag = save_break;
        oop.continue_flag = save_continue;

        for (name, prev) in saved {
            match prev {
                Some(v) => {
                    oop.string_vars.insert(name, v);
                }
                None => {
                    oop.string_vars.remove(&name);
                }
            }
        }

        if !keep_going {
            return false;
        }

        apply_return(vars, oop, result_var, captured_return);
        return true;
    }

    if let Some(self_name) = oop.self_stack.last().cloned() {
        if let Some(rest) = line.strip_prefix("selfget ") {
            let field = rest.trim();
            if let Some(instance) = oop.instances.get(&self_name) {
                match instance.fields.get(field) {
                    Some(v) => println!("{}", v),
                    None => println!("Field '{}' not found", field),
                }
            }
            return true;
        }

        if let Some(rest) = line.strip_prefix("selfset ") {
            let parts: Vec<&str> = rest.splitn(2, '=').collect();
            if parts.len() == 2 {
                let field = parts[0].trim().to_string();
                let value = resolve_arg(parts[1].trim(), vars, oop);
                if let Some(instance) = oop.instances.get_mut(&self_name) {
                    instance.fields.insert(field, value);
                }
            }
            return true;
        }
    }

    if line == "exit" {
        return false;
    }

    if let Some(t) = line.strip_prefix("psyska -/ ") {
        println!("{}", interpolate(strip_outer_quotes(t), vars, oop));
        return true;
    }

    if line.starts_with("set ") {
        let parts: Vec<&str> = line[4..].splitn(2, '=').collect();
        if parts.len() == 2 {
            let name = parts[0].trim().to_string();
            let raw_rhs = parts[1].trim();

            let is_quoted = raw_rhs.starts_with('"')
                && raw_rhs.ends_with('"')
                && raw_rhs.len() >= 2;

            let resolved: String = if is_quoted {
                interpolate(&raw_rhs[1..raw_rhs.len() - 1], vars, oop)
            } else if raw_rhs.contains('{') {
                interpolate(raw_rhs, vars, oop)
            } else if let Ok(n) = raw_rhs.parse::<i64>() {
                n.to_string()
            } else if let Ok(f) = raw_rhs.parse::<f64>() {
                f.to_string()
            } else if let Some(v) = lookup_simple(raw_rhs, vars, oop) {
                v
            } else if let Some(v) = eval_expression(raw_rhs, vars, oop) {
                v
            } else {
                raw_rhs.to_string()
            };

            let trimmed = resolved.trim();

            // If the LHS is dotted (e.g. "d.name" or "self.name"), route to
            // the instance / static-field setter instead of storing a flat
            // variable named "d.name". Falls through to flat-var storage if
            // no matching instance/class is found (preserves legacy behavior
            // for users who happened to use dotted names as plain keys).
            if let Some(dot) = name.find('.') {
                let inst_name_raw = name[..dot].trim();
                let field_name = name[dot + 1..].trim().to_string();
                let inst_key: Option<String> = if inst_name_raw == "self" {
                    oop.self_stack.last().cloned()
                } else {
                    Some(inst_name_raw.to_string())
                };
                if let Some(inst_key) = inst_key {
                    if let Some(instance) = oop.instances.get_mut(&inst_key) {
                        instance.fields.insert(field_name, resolved.clone());
                        return true;
                    }
                    if let Some(class_def) = oop.classes.get_mut(&inst_key) {
                        class_def.static_fields.insert(field_name, resolved.clone());
                        return true;
                    }
                }
                // No instance/class found — fall through to flat-var assignment.
            }

            if let Ok(n) = trimmed.parse::<i64>() {
                vars.insert(name.clone(), n);
                oop.string_vars.remove(&name);
            } else if trimmed.parse::<f64>().is_ok() {
                // preserve float precision by storing as string
                oop.string_vars.insert(name.clone(), trimmed.to_string());
                vars.remove(&name);
            } else {
                oop.string_vars.insert(name.clone(), resolved);
                vars.remove(&name);
            }
        }
        return true;
    }

    if line.starts_with("add ") {
        let parts: Vec<&str> = line[4..].splitn(2, ',').collect();
        if parts.len() == 2 {
            let name = parts[0].trim().to_string();
            let rhs = parts[1].trim();
            let amount: i64 = match rhs.parse::<i64>() {
                Ok(n) => n,
                Err(_) => {
                    let resolved = interpolate(&format!("{{{}}}", rhs), vars, oop);
                    resolved.trim().parse::<i64>().unwrap_or_else(|_| {
                        resolved
                            .trim()
                            .parse::<f64>()
                            .map(|f| f as i64)
                            .unwrap_or(0)
                    })
                }
            };
            let v = vars.entry(name).or_insert(0);
            *v += amount;
        }
        return true;
    }

    if line.starts_with("asknum ") {
        let rest = line[7..].trim();
        let parts: Vec<&str> = rest.split_whitespace().collect();
        let var_name = parts.first().copied().unwrap_or("");
        let write_flag = parts.get(1) == Some(&"write");

        if var_name.is_empty() {
            println!("asknum: missing variable name");
            return true;
        }

        print!("Value of {}: ", var_name);
        io::stdout().flush().unwrap();

        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();
        let value: i64 = input.trim().parse().unwrap_or(0);
        vars.insert(var_name.to_string(), value);

        if write_flag {
            if let Some(path) = oop.top_script_path.clone() {
                if let Ok(content) = fs::read_to_string(&path) {
                    let mut new_lines: Vec<String> = Vec::new();
                    let mut replaced = false;
                    for orig in content.lines() {
                        if !replaced && orig.trim() == line {
                            new_lines.push(format!("set {} = {}", var_name, value));
                            replaced = true;
                        } else {
                            new_lines.push(orig.to_string());
                        }
                    }
                    let mut new_content = new_lines.join("\n");
                    if content.ends_with('\n') {
                        new_content.push('\n');
                    }
                    let _ = fs::write(&path, new_content);
                }
            }
        }

        return true;
    }

    if line == "pause" {
        let mut s = String::new();
        io::stdin().read_line(&mut s).unwrap();
        return true;
    }

    if line == "waitkey" || line.starts_with("waitkey ") {
        let var_name = line.strip_prefix("waitkey").unwrap_or("").trim();
        let term = console::Term::stdout();
        match term.read_key() {
            Ok(key) => {
                if !var_name.is_empty() {
                    let label = match key {
                        console::Key::Char(c) => c.to_string(),
                        console::Key::ArrowUp => "up".into(),
                        console::Key::ArrowDown => "down".into(),
                        console::Key::ArrowLeft => "left".into(),
                        console::Key::ArrowRight => "right".into(),
                        console::Key::Enter => "enter".into(),
                        console::Key::Escape => "esc".into(),
                        console::Key::Backspace => "backspace".into(),
                        console::Key::Tab => "tab".into(),
                        console::Key::Home => "home".into(),
                        console::Key::End => "end".into(),
                        console::Key::PageUp => "pageup".into(),
                        console::Key::PageDown => "pagedown".into(),
                        console::Key::Del => "delete".into(),
                        console::Key::Insert => "insert".into(),
                        _ => "unknown".into(),
                    };
                    oop.string_vars.insert(var_name.to_string(), label);
                }
            }
            Err(e) => println!("waitkey failed: {}", e),
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("strlen ") {
        let tokens: Vec<&str> = rest.split_whitespace().collect();
        if tokens.len() >= 3 && tokens[1] == "=" {
            let var = tokens[0].to_string();
            let raw = rest.splitn(2, '=').nth(1).unwrap().trim();
            let s = resolve_arg(raw, vars, oop);
            vars.insert(var, s.chars().count() as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lower ") {
        let tokens: Vec<&str> = rest.splitn(2, '=').collect();
        if tokens.len() == 2 {
            let var = tokens[0].trim().to_string();
            let s = resolve_arg(tokens[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.to_lowercase());
        } else {
            let s = resolve_arg(rest.trim(), vars, oop);
            println!("{}", s.to_lowercase());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("upper ") {
        let tokens: Vec<&str> = rest.splitn(2, '=').collect();
        if tokens.len() == 2 {
            let var = tokens[0].trim().to_string();
            let s = resolve_arg(tokens[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.to_uppercase());
        } else {
            let s = resolve_arg(rest.trim(), vars, oop);
            println!("{}", s.to_uppercase());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("trim ") {
        let tokens: Vec<&str> = rest.splitn(2, '=').collect();
        if tokens.len() == 2 {
            let var = tokens[0].trim().to_string();
            let s = resolve_arg(tokens[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.trim().to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("contains ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let haystack = resolve_arg(&args[0], vars, oop);
                let needle = resolve_arg(&args[1], vars, oop);
                vars.insert(var, if haystack.contains(&needle) { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("substr ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 3 {
                let s = resolve_arg(&args[0], vars, oop);
                let start: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let len: usize = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0);
                let result: String = s.chars().skip(start).take(len).collect();
                oop.string_vars.insert(var, result);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("replace ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 3 {
                let s = resolve_arg(&args[0], vars, oop);
                let from = resolve_arg(&args[1], vars, oop);
                let to = resolve_arg(&args[2], vars, oop);
                oop.string_vars.insert(var, s.replace(&from, &to));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("pad ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let width: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let fill = if args.len() >= 3 {
                    resolve_arg(&args[2], vars, oop)
                        .chars()
                        .next()
                        .unwrap_or(' ')
                } else {
                    ' '
                };
                let pad = width.saturating_sub(s.chars().count());
                oop.string_vars
                    .insert(var, format!("{}{}", s, fill.to_string().repeat(pad)));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("center ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let width: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let len = s.chars().count();
                let pad = width.saturating_sub(len);
                let lp = pad / 2;
                let rp = pad - lp;
                oop.string_vars
                    .insert(var, format!("{}{}{}", " ".repeat(lp), s, " ".repeat(rp)));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("repeat_str ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                oop.string_vars.insert(var, s.repeat(n));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("startswith ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let p = resolve_arg(&args[1], vars, oop);
                vars.insert(var, if s.starts_with(&p) { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("endswith ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let p = resolve_arg(&args[1], vars, oop);
                vars.insert(var, if s.ends_with(&p) { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("range ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let (start, end, step) = match args.len() {
                1 => (
                    0,
                    resolve_arg(&args[0], vars, oop).parse().unwrap_or(0),
                    1,
                ),
                2 => (
                    resolve_arg(&args[0], vars, oop).parse().unwrap_or(0),
                    resolve_arg(&args[1], vars, oop).parse().unwrap_or(0),
                    1,
                ),
                _ => (
                    resolve_arg(&args[0], vars, oop).parse().unwrap_or(0),
                    resolve_arg(&args[1], vars, oop).parse().unwrap_or(0),
                    resolve_arg(&args[2], vars, oop).parse().unwrap_or(1),
                ),
            };
            let mut out: Vec<String> = Vec::new();
            let mut i: i64 = start;
            if step > 0 {
                while i < end {
                    out.push(i.to_string());
                    i += step;
                }
            } else if step < 0 {
                while i > end {
                    out.push(i.to_string());
                    i += step;
                }
            }
            oop.lists.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lsort ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get_mut(name) {
            l.sort_by(|a, b| {
                if let (Ok(an), Ok(bn)) = (a.parse::<f64>(), b.parse::<f64>()) {
                    an.partial_cmp(&bn).unwrap_or(std::cmp::Ordering::Equal)
                } else {
                    a.cmp(b)
                }
            });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lreverse ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get_mut(name) {
            l.reverse();
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lunique ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get_mut(name) {
            let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new();
            l.retain(|x| seen.insert(x.clone()));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lmax ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let val = oop
            .lists
            .get(name)
            .and_then(|l| {
                l.iter()
                    .filter_map(|x| x.parse::<f64>().ok())
                    .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
            })
            .map(|n| {
                if n.fract() == 0.0 {
                    (n as i64).to_string()
                } else {
                    n.to_string()
                }
            });
        apply_return(vars, oop, result_var, val);
        return true;
    }

    if let Some(rest) = line.strip_prefix("lmin ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let val = oop
            .lists
            .get(name)
            .and_then(|l| {
                l.iter()
                    .filter_map(|x| x.parse::<f64>().ok())
                    .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
            })
            .map(|n| {
                if n.fract() == 0.0 {
                    (n as i64).to_string()
                } else {
                    n.to_string()
                }
            });
        apply_return(vars, oop, result_var, val);
        return true;
    }

    if let Some(rest) = line.strip_prefix("lsum ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let sum: f64 = oop
            .lists
            .get(name)
            .map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).sum())
            .unwrap_or(0.0);
        let str_val = if sum.fract() == 0.0 {
            (sum as i64).to_string()
        } else {
            sum.to_string()
        };
        apply_return(vars, oop, result_var, Some(str_val));
        return true;
    }

    if let Some(rest) = line.strip_prefix("lavg ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let avg: f64 = oop
            .lists
            .get(name)
            .map(|l| {
                let nums: Vec<f64> = l.iter().filter_map(|x| x.parse::<f64>().ok()).collect();
                if nums.is_empty() {
                    0.0
                } else {
                    nums.iter().sum::<f64>() / nums.len() as f64
                }
            })
            .unwrap_or(0.0);
        apply_return(vars, oop, result_var, Some(avg.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("lshuffle ") {
        use rand::seq::SliceRandom;
        let name = rest.trim();
        if let Some(l) = oop.lists.get_mut(name) {
            let mut rng = rand::thread_rng();
            l.shuffle(&mut rng);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lchoice ") {
        use rand::seq::SliceRandom;
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let mut rng = rand::thread_rng();
        let val = oop
            .lists
            .get(name)
            .and_then(|l| l.choose(&mut rng).cloned());
        apply_return(vars, oop, result_var, val);
        return true;
    }

    if let Some(rest) = line.strip_prefix("getenv ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let key = resolve_arg(parts[1].trim(), vars, oop);
            let v = env::var(&key).unwrap_or_default();
            oop.string_vars.insert(var, v);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("setenv ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let key = resolve_arg(&args[0], vars, oop);
            let value = resolve_arg(&args[1], vars, oop);
            env::set_var(key, value);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("loadenv ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        match fs::read_to_string(&path) {
            Ok(content) => {
                for line in content.lines() {
                    let l = line.trim();
                    if l.is_empty() || l.starts_with('#') {
                        continue;
                    }
                    if let Some(idx) = l.find('=') {
                        let k = l[..idx].trim().to_string();
                        let mut v = l[idx + 1..].trim().to_string();
                        if v.starts_with('"') && v.ends_with('"') && v.len() >= 2 {
                            v = v[1..v.len() - 1].to_string();
                        }
                        env::set_var(&k, &v);
                        oop.string_vars.insert(k, v);
                    }
                }
            }
            Err(e) => {
                oop.error_message = Some(format!("loadenv: {}", e));
                println!("loadenv failed: {}", e);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("log ") {
        let parts: Vec<&str> = rest.splitn(2, char::is_whitespace).collect();
        let level = parts[0];
        let msg = if parts.len() > 1 {
            resolve_arg(parts[1].trim(), vars, oop)
        } else {
            String::new()
        };
        let ts = chrono::Local::now().format("%H:%M:%S");
        let (color, label) = match level {
            "info" => ("\x1b[36m", "INFO"),
            "warn" => ("\x1b[33m", "WARN"),
            "error" => ("\x1b[31m", "ERROR"),
            "debug" => ("\x1b[2m", "DEBUG"),
            _ => ("\x1b[37m", level),
        };
        let formatted = format!("{}[{} {}]\x1b[0m {}", color, ts, label, msg);
        println!("{}", formatted);
        if let Some(path) = oop.log_file.clone() {
            let plain = format!("[{} {}] {}\n", ts, label, msg);
            let _ = fs::OpenOptions::new()
                .create(true)
                .append(true)
                .open(&path)
                .and_then(|mut f| {
                    use std::io::Write;
                    f.write_all(plain.as_bytes())
                });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("logfile ") {
        oop.log_file = Some(expand_path(&resolve_arg(rest.trim(), vars, oop))
            .to_string_lossy()
            .to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("inspect ") {
        let name = rest.trim();
        println!("\x1b[1;36m── inspect: {} ──\x1b[0m", name);
        if let Some(v) = vars.get(name) {
            println!("  type: int     value: {}", v);
        } else if let Some(v) = oop.string_vars.get(name) {
            println!("  type: string  value: {:?}", v);
        } else if let Some(l) = oop.lists.get(name) {
            println!("  type: list    size: {}", l.len());
            for (i, item) in l.iter().enumerate().take(20) {
                println!("    [{}] {}", i, item);
            }
            if l.len() > 20 {
                println!("    ... and {} more", l.len() - 20);
            }
        } else if let Some(d) = oop.dicts.get(name) {
            println!("  type: dict    size: {}", d.len());
            let mut keys: Vec<_> = d.keys().collect();
            keys.sort();
            for k in keys.iter().take(20) {
                println!("    {} = {}", k, d[*k]);
            }
            if keys.len() > 20 {
                println!("    ... and {} more", keys.len() - 20);
            }
        } else if let Some(inst) = oop.instances.get(name) {
            println!("  type: {} instance", inst.class_name);
            let mut keys: Vec<_> = inst.fields.keys().collect();
            keys.sort();
            for k in keys {
                println!("    .{} = {}", k, inst.fields[k]);
            }
        } else if oop.classes.contains_key(name) {
            println!("  type: Class");
        } else if oop.functions.contains_key(name) {
            println!("  type: function");
        } else {
            println!("  \x1b[31m(not found)\x1b[0m");
        }
        return true;
    }

    // Signal an explicit test failure with an optional message.
    if let Some(rest) = line.strip_prefix("fail ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        println!("\x1b[31m✗ FAIL\x1b[0m {}", msg);
        if oop.current_line_no > 0 {
            println!("  at line {}", oop.current_line_no);
        }
        println!("[TEST FAIL]");
        return true;
    }
    if line == "fail" {
        println!("\x1b[31m✗ FAIL\x1b[0m");
        println!("[TEST FAIL]");
        return true;
    }

    if let Some(rest) = line.strip_prefix("assert ") {
        let args = split_args(rest);
        if args.len() >= 2 {
            let actual = resolve_arg(&args[0], vars, oop);
            let expected = resolve_arg(&args[1], vars, oop);
            if actual == expected {
                println!(
                    "\x1b[32m✓ ASSERT\x1b[0m {} == {}",
                    args[0].trim(),
                    expected
                );
            } else {
                println!(
                    "\x1b[31m✗ ASSERT FAILED\x1b[0m {} == {} (got: {})",
                    args[0].trim(),
                    expected,
                    actual
                );
                if oop.current_line_no > 0 {
                    println!("  at line {}", oop.current_line_no);
                }
                println!("[TEST FAIL]");
            }
        } else if args.len() == 1 {
            let v = resolve_arg(&args[0], vars, oop);
            let truthy = v != "0" && !v.is_empty();
            if truthy {
                println!("\x1b[32m✓ ASSERT\x1b[0m {} is truthy", args[0].trim());
            } else {
                println!("\x1b[31m✗ ASSERT FAILED\x1b[0m {} is falsy ({})", args[0].trim(), v);
            }
        }
        return true;
    }

    if line == "debug" {
        println!("\x1b[1;36m── debug: full state ──\x1b[0m");
        println!("  vars: {} numeric, {} string", vars.len(), oop.string_vars.len());
        println!("  classes: {}, instances: {}", oop.classes.len(), oop.instances.len());
        println!("  functions: {}", oop.functions.len());
        println!("  lists: {}, dicts: {}", oop.lists.len(), oop.dicts.len());
        if !vars.is_empty() {
            println!("  numeric vars:");
            let mut keys: Vec<_> = vars.keys().collect();
            keys.sort();
            for k in keys {
                println!("    {} = {}", k, vars[k]);
            }
        }
        if !oop.string_vars.is_empty() {
            println!("  string vars:");
            let mut keys: Vec<_> = oop.string_vars.keys().collect();
            keys.sort();
            for k in keys {
                println!("    {} = {:?}", k, oop.string_vars[k]);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_open ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let alias = resolve_arg(&args[0], vars, oop);
            let path = expand_path(&resolve_arg(&args[1], vars, oop));
            match rusqlite::Connection::open(&path) {
                Ok(conn) => {
                    oop.db_connections.insert(alias, conn);
                }
                Err(e) => {
                    oop.error_message = Some(format!("db_open: {}", e));
                    println!("db_open failed: {}", e);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_close ") {
        let alias = resolve_arg(rest.trim(), vars, oop);
        oop.db_connections.remove(&alias);
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_exec ") {
        let args = split_args(rest);
        if args.len() >= 2 {
            let alias = resolve_arg(&args[0], vars, oop);
            let sql = resolve_arg(&args[1], vars, oop);
            if let Some(conn) = oop.db_connections.get(&alias) {
                match conn.execute(&sql, []) {
                    Ok(_) => {}
                    Err(e) => {
                        oop.error_message = Some(format!("db_exec: {}", e));
                        println!("db_exec failed: {}", e);
                    }
                }
            } else {
                println!("db_exec: connection '{}' not open", alias);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_query ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() >= 2 {
            let alias = resolve_arg(&args[0], vars, oop);
            let sql = resolve_arg(&args[1], vars, oop);
            if let Some(conn) = oop.db_connections.get(&alias) {
                let mut rows_out: Vec<String> = Vec::new();
                match conn.prepare(&sql) {
                    Ok(mut stmt) => {
                        let col_count = stmt.column_count();
                        let col_names: Vec<String> =
                            (0..col_count).map(|i| stmt.column_name(i).unwrap_or("?").to_string()).collect();
                        match stmt.query([]) {
                            Ok(mut rows) => {
                                while let Ok(Some(row)) = rows.next() {
                                    let mut parts_str = Vec::new();
                                    for (i, name) in col_names.iter().enumerate() {
                                        let val: rusqlite::types::Value =
                                            row.get_unwrap::<usize, rusqlite::types::Value>(i);
                                        let s = match val {
                                            rusqlite::types::Value::Null => "null".to_string(),
                                            rusqlite::types::Value::Integer(n) => n.to_string(),
                                            rusqlite::types::Value::Real(f) => f.to_string(),
                                            rusqlite::types::Value::Text(s) => s,
                                            rusqlite::types::Value::Blob(_) => "<blob>".into(),
                                        };
                                        parts_str.push(format!("{}={}", name, s));
                                    }
                                    rows_out.push(parts_str.join("|"));
                                }
                            }
                            Err(e) => println!("db_query rows: {}", e),
                        }
                    }
                    Err(e) => println!("db_query prepare: {}", e),
                }
                if let Some(target) = result_var {
                    oop.lists.insert(target, rows_out);
                }
            } else {
                println!("db_query: connection '{}' not open", alias);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("abs ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            let v = n.abs();
            if v.fract() == 0.0 {
                vars.insert(var, v as i64);
            } else {
                oop.string_vars.insert(var, v.to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sign ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            vars.insert(var, if n > 0.0 { 1 } else if n < 0.0 { -1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("floor ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            vars.insert(var, n.floor() as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ceil ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            vars.insert(var, n.ceil() as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("round ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            vars.insert(var, n.round() as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("trunc ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            vars.insert(var, n.trunc() as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("pow ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let b: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let e: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                let v = b.powf(e);
                if v.fract() == 0.0 && v.abs() < 1e18 {
                    vars.insert(var, v as i64);
                } else {
                    oop.string_vars.insert(var, v.to_string());
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sqrt ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            let v = n.sqrt();
            if v.fract() == 0.0 {
                vars.insert(var, v as i64);
            } else {
                oop.string_vars.insert(var, v.to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("fmax ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let b: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                vars.insert(var, a.max(b) as i64);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("fmin ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let b: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                vars.insert(var, a.min(b) as i64);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("clamp ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 3 {
                let n: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let lo: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                let hi: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
                vars.insert(var, n.max(lo).min(hi) as i64);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gcd ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let mut a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let mut b: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                while b != 0 { let t = b; b = a % b; a = t; }
                vars.insert(var, a.abs());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcm ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let b: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let mut x = a.abs(); let mut y = b.abs();
                while y != 0 { let t = y; y = x % y; x = t; }
                vars.insert(var, if x == 0 { 0 } else { (a * b).abs() / x });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("factorial ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let mut acc: i64 = 1;
            for i in 1..=n { acc = acc.saturating_mul(i); }
            vars.insert(var, acc);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_even ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            vars.insert(var, if n % 2 == 0 { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_odd ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            vars.insert(var, if n % 2 != 0 { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_prime ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let prime = if n < 2 { false } else if n < 4 { true } else if n % 2 == 0 { false } else {
                let mut i: i64 = 3; let mut p = true;
                while i * i <= n { if n % i == 0 { p = false; break; } i += 2; } p
            };
            vars.insert(var, if prime { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("band ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let b: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                vars.insert(var, a & b);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("bor ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let b: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                vars.insert(var, a | b);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("bxor ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let b: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                vars.insert(var, a ^ b);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("bnot ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            vars.insert(var, !n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("shl ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let b: u32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                vars.insert(var, a << b);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("shr ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let b: u32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                vars.insert(var, a >> b);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_int ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let n: i64 = s.trim().parse().unwrap_or_else(|_| s.trim().parse::<f64>().map(|f| f as i64).unwrap_or(0));
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_str ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(var, s);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_hex ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.string_vars.insert(var, format!("{:x}", n));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_bin ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.string_vars.insert(var, format!("{:b}", n));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_oct ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.string_vars.insert(var, format!("{:o}", n));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("from_hex ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, i64::from_str_radix(s.trim_start_matches("0x"), 16).unwrap_or(0));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("from_bin ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, i64::from_str_radix(s.trim_start_matches("0b"), 2).unwrap_or(0));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ord ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, s.chars().next().map(|c| c as i64).unwrap_or(0));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("chr ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: u32 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.string_vars.insert(var, char::from_u32(n).map(|c| c.to_string()).unwrap_or_default());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("title ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let titled: String = s.split_whitespace()
                .map(|w| {
                    let mut c = w.chars();
                    match c.next() {
                        Some(f) => f.to_uppercase().collect::<String>() + &c.as_str().to_lowercase(),
                        None => String::new(),
                    }
                })
                .collect::<Vec<_>>().join(" ");
            oop.string_vars.insert(var, titled);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("capitalize ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let mut c = s.chars();
            let r = match c.next() {
                Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
                None => String::new(),
            };
            oop.string_vars.insert(var, r);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("count_substr ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let needle = resolve_arg(&args[1], vars, oop);
                if needle.is_empty() {
                    vars.insert(var, 0);
                } else {
                    vars.insert(var, s.matches(&needle).count() as i64);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("find_index ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let needle = resolve_arg(&args[1], vars, oop);
                vars.insert(var, s.find(&needle).map(|i| i as i64).unwrap_or(-1));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("count_words ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, s.split_whitespace().count() as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("strip_left ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.trim_start().to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("strip_right ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.trim_end().to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("first ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let v = oop.lists.get(name).and_then(|l| l.first().cloned());
        apply_return(vars, oop, result_var, v);
        return true;
    }

    if let Some(rest) = line.strip_prefix("last ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let v = oop.lists.get(name).and_then(|l| l.last().cloned());
        apply_return(vars, oop, result_var, v);
        return true;
    }

    if let Some(rest) = line.strip_prefix("lindex ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let name = args[0].trim();
                let needle = resolve_arg(&args[1], vars, oop);
                let idx = oop.lists.get(name).map(|l| l.iter().position(|v| v == &needle).map(|i| i as i64).unwrap_or(-1)).unwrap_or(-1);
                vars.insert(var, idx);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcopy ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            if let Some(l) = oop.lists.get(src).cloned() {
                oop.lists.insert(dest, l);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dvalues ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        if let Some(target) = result_var {
            let mut values: Vec<String> = oop.dicts.get(name).map(|d| d.values().cloned().collect()).unwrap_or_default();
            values.sort();
            oop.lists.insert(target, values);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dmerge ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let dest = args[0].trim().to_string();
            let src = args[1].trim();
            let src_d = oop.dicts.get(src).cloned().unwrap_or_default();
            let dest_d = oop.dicts.entry(dest).or_insert_with(HashMap::new);
            for (k, v) in src_d { dest_d.insert(k, v); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("read_lines ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let path = expand_path(&resolve_arg(parts[0].trim(), vars, oop));
        match fs::read_to_string(&path) {
            Ok(data) => {
                let lines: Vec<String> = data.lines().map(String::from).collect();
                if let Some(target) = result_var {
                    oop.lists.insert(target, lines);
                }
            }
            Err(e) => {
                oop.error_message = Some(format!("read_lines: {}", e));
                println!("read_lines failed: {}", e);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("append_file ") {
        let args = split_args(rest);
        if args.len() == 2 {
            use std::io::Write;
            let path = expand_path(&resolve_arg(&args[0], vars, oop));
            let text = resolve_arg(&args[1], vars, oop);
            match fs::OpenOptions::new().create(true).append(true).open(&path) {
                Ok(mut f) => { let _ = f.write_all(text.as_bytes()); }
                Err(e) => { oop.error_message = Some(format!("append_file: {}", e)); println!("append_file failed: {}", e); }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_size ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let path = expand_path(&resolve_arg(parts[0].trim(), vars, oop));
        let sz: i64 = fs::metadata(&path).map(|m| m.len() as i64).unwrap_or(-1);
        if let Some(v) = result_var { vars.insert(v, sz); } else { println!("{}", sz); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_dir ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let path = expand_path(&resolve_arg(parts[0].trim(), vars, oop));
        let is = path.is_dir();
        if let Some(v) = result_var { vars.insert(v, if is { 1 } else { 0 }); } else { println!("{}", if is { 1 } else { 0 }); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_file ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let path = expand_path(&resolve_arg(parts[0].trim(), vars, oop));
        let is = path.is_file();
        if let Some(v) = result_var { vars.insert(v, if is { 1 } else { 0 }); } else { println!("{}", if is { 1 } else { 0 }); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("basename ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = resolve_arg(parts[1].trim(), vars, oop);
            let b = PathBuf::from(&path).file_name().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
            oop.string_vars.insert(var, b);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dirname ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = resolve_arg(parts[1].trim(), vars, oop);
            let b = PathBuf::from(&path).parent().map(|p| p.to_string_lossy().to_string()).unwrap_or_default();
            oop.string_vars.insert(var, b);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("extname ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = resolve_arg(parts[1].trim(), vars, oop);
            let b = PathBuf::from(&path).extension().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
            oop.string_vars.insert(var, b);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("joinpath ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let mut p = PathBuf::new();
            for a in &args { p.push(resolve_arg(a, vars, oop)); }
            oop.string_vars.insert(var, p.to_string_lossy().to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("rand_float ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let (lo, hi): (f64, f64) = match args.len() {
                0 => (0.0, 1.0),
                1 => (0.0, resolve_arg(&args[0], vars, oop).parse().unwrap_or(1.0)),
                _ => (
                    resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0),
                    resolve_arg(&args[1], vars, oop).parse().unwrap_or(1.0),
                ),
            };
            let f: f64 = rand::Rng::gen_range(&mut rand::thread_rng(), lo..hi);
            oop.string_vars.insert(var, f.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("rand_bool ") {
        let var = rest.trim().to_string();
        let b: bool = rand::Rng::gen_bool(&mut rand::thread_rng(), 0.5);
        vars.insert(var, if b { 1 } else { 0 });
        return true;
    }

    if let Some(rest) = line.strip_prefix("coin ") {
        let var = rest.trim().to_string();
        let b: bool = rand::Rng::gen_bool(&mut rand::thread_rng(), 0.5);
        oop.string_vars.insert(var, if b { "heads".into() } else { "tails".into() });
        return true;
    }

    if let Some(rest) = line.strip_prefix("d6 ") {
        let var = rest.trim().to_string();
        let n: i64 = rand::Rng::gen_range(&mut rand::thread_rng(), 1..=6);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("d20 ") {
        let var = rest.trim().to_string();
        let n: i64 = rand::Rng::gen_range(&mut rand::thread_rng(), 1..=20);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("weekday ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let parsed = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").ok();
            let day = parsed.map(|d| d.format("%A").to_string()).unwrap_or_else(|| "invalid".to_string());
            oop.string_vars.insert(var, day);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("timestamp_ms ") {
        let var = rest.trim().to_string();
        let n = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| d.as_millis() as i64)
            .unwrap_or(0);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("pid ") {
        let var = rest.trim().to_string();
        vars.insert(var, std::process::id() as i64);
        return true;
    }

    if let Some(rest) = line.strip_prefix("platform ") {
        let var = rest.trim().to_string();
        let p = if cfg!(target_os = "linux") { "linux" }
            else if cfg!(target_os = "macos") { "macos" }
            else if cfg!(target_os = "windows") { "windows" }
            else { "other" };
        oop.string_vars.insert(var, p.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("http_delete ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let url = resolve_arg(parts[0].trim(), vars, oop);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let client = reqwest::blocking::Client::new();
        match client.delete(&url).send().and_then(|r| r.text()) {
            Ok(body) => apply_return(vars, oop, result_var, Some(body)),
            Err(e) => { oop.error_message = Some(format!("http_delete: {}", e)); println!("http_delete failed: {}", e); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("http_put ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let args = split_args(parts[0]);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        if args.len() >= 2 {
            let url = resolve_arg(&args[0], vars, oop);
            let body = resolve_arg(&args[1], vars, oop);
            let client = reqwest::blocking::Client::new();
            match client.put(&url).body(body).send().and_then(|r| r.text()) {
                Ok(b) => apply_return(vars, oop, result_var, Some(b)),
                Err(e) => { oop.error_message = Some(format!("http_put: {}", e)); println!("http_put failed: {}", e); }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gotoxy ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let x: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
            let y: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            print!("\x1b[{};{}H", y, x);
            let _ = io::stdout().flush();
        }
        return true;
    }

    if line == "hide_cursor" { print!("\x1b[?25l"); let _ = io::stdout().flush(); return true; }
    if line == "show_cursor" { print!("\x1b[?25h"); let _ = io::stdout().flush(); return true; }
    if line == "save_cursor" { print!("\x1b[s"); let _ = io::stdout().flush(); return true; }
    if line == "restore_cursor" { print!("\x1b[u"); let _ = io::stdout().flush(); return true; }
    if line == "clear_line" { print!("\x1b[2K\r"); let _ = io::stdout().flush(); return true; }
    if line == "clear_below" { print!("\x1b[J"); let _ = io::stdout().flush(); return true; }

    if let Some(rest) = line.strip_prefix("term_size ") {
        let var = rest.trim().to_string();
        let (cols, rows) = console::Term::stdout().size();
        oop.string_vars.insert(format!("{}_rows", var), rows.to_string());
        oop.string_vars.insert(format!("{}_cols", var), cols.to_string());
        return true;
    }

    if line == "blessing" {
        println!("🙏 May your code compile on the first try.");
        return true;
    }
    if line == "despair" {
        println!("💀 Segfault. Again.");
        return true;
    }
    if line == "hope" {
        println!("🌅 It might work this time. It might.");
        return true;
    }
    if line == "victory" {
        println!("🏆 All tests pass! Ship it!");
        return true;
    }
    if line == "defeat" {
        println!("😞 Build failed at the worst time.");
        return true;
    }
    if line == "sloth" {
        println!("🦥 Why optimize? It's only O(n²)");
        return true;
    }
    if line == "party" {
        println!("🎉 Release day! 🎊");
        return true;
    }
    if line == "taco" {
        println!("🌮 Tacos are the answer.");
        return true;
    }

    if let Some(rest) = line.strip_prefix("min ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let nums: Vec<f64> = args.iter().map(|a| resolve_arg(a, vars, oop).parse().unwrap_or(0.0)).collect();
            let m = nums.iter().cloned().fold(f64::INFINITY, f64::min);
            if m.fract() == 0.0 && m.is_finite() { vars.insert(var, m as i64); } else { oop.string_vars.insert(var, m.to_string()); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("max ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let nums: Vec<f64> = args.iter().map(|a| resolve_arg(a, vars, oop).parse().unwrap_or(0.0)).collect();
            let m = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
            if m.fract() == 0.0 && m.is_finite() { vars.insert(var, m as i64); } else { oop.string_vars.insert(var, m.to_string()); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sum ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let s: f64 = args.iter().map(|a| resolve_arg(a, vars, oop).parse::<f64>().unwrap_or(0.0)).sum();
            if s.fract() == 0.0 { vars.insert(var, s as i64); } else { oop.string_vars.insert(var, s.to_string()); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("avg ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let nums: Vec<f64> = args.iter().map(|a| resolve_arg(a, vars, oop).parse().unwrap_or(0.0)).collect();
            let a = if nums.is_empty() { 0.0 } else { nums.iter().sum::<f64>() / nums.len() as f64 };
            oop.string_vars.insert(var, a.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("noop ") { let _ = rest; return true; }
    if line == "noop" { return true; }
    if line == "nop" { return true; }

    if let Some(rest) = line.strip_prefix("panic ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        eprintln!("\x1b[1;31mPANIC:\x1b[0m {}", msg);
        return false;
    }

    if let Some(rest) = line.strip_prefix("todo ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        println!("\x1b[33mTODO:\x1b[0m {}", msg);
        return true;
    }

    if let Some(rest) = line.strip_prefix("note ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        println!("\x1b[34mNOTE:\x1b[0m {}", msg);
        return true;
    }

    if let Some(rest) = line.strip_prefix("warn ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        println!("\x1b[33mWARN:\x1b[0m {}", msg);
        return true;
    }

    if let Some(rest) = line.strip_prefix("rot13 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let r: String = s.chars().map(|c| match c {
                'a'..='z' => (((c as u8 - b'a' + 13) % 26) + b'a') as char,
                'A'..='Z' => (((c as u8 - b'A' + 13) % 26) + b'A') as char,
                _ => c,
            }).collect();
            oop.string_vars.insert(var, r);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("hex_encode ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.bytes().map(|b| format!("{:02x}", b)).collect::<String>());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dpairs ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        if let Some(target) = result_var {
            let mut items: Vec<String> = oop.dicts.get(name).map(|d| d.iter().map(|(k, v)| format!("{}={}", k, v)).collect()).unwrap_or_default();
            items.sort();
            oop.lists.insert(target, items);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("env_list ") {
        let var = rest.trim().to_string();
        let mut keys: Vec<String> = env::vars().map(|(k, _)| k).collect();
        keys.sort();
        oop.lists.insert(var, keys);
        return true;
    }

    if let Some(rest) = line.strip_prefix("getuser ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, env::var("USER").unwrap_or_else(|_| "unknown".into()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("gethome ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, env::var("HOME").unwrap_or_default());
        return true;
    }

    if let Some(rest) = line.strip_prefix("ping ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let host = resolve_arg(parts[0].trim(), vars, oop);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let status = Command::new("ping").arg("-c").arg("1").arg("-W").arg("2").arg(&host).status();
        let ok = status.map(|s| s.success()).unwrap_or(false);
        if let Some(v) = result_var { vars.insert(v, if ok { 1 } else { 0 }); } else { println!("{}", if ok { "up" } else { "down" }); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("pwd ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, env::current_dir().map(|p| p.to_string_lossy().to_string()).unwrap_or_default());
        return true;
    }

    if let Some(rest) = line.strip_prefix("abspath ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let abs = path.canonicalize().unwrap_or(path);
            oop.string_vars.insert(var, abs.to_string_lossy().to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("pi ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, std::f64::consts::PI.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("e ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, std::f64::consts::E.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("deg_to_rad ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            oop.string_vars.insert(var, (n.to_radians()).to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("rad_to_deg ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            oop.string_vars.insert(var, (n.to_degrees()).to_string());
        }
        return true;
    }

    if line == "version" {
        println!("AyaanScript+ 1.34.4");
        return true;
    }

    if line == "cls" {
        print!("\x1b[2J\x1b[1;1H");
        let _ = io::stdout().flush();
        return true;
    }

    if line == "credits" {
        println!("AyaanScript+ — created by Ayaan");
        println!("Built with Rust and chicken-lord-approved love.");
        return true;
    }

    if line == "license" {
        println!("MIT License — see LICENSE for details");
        return true;
    }

    let emoji_table: &[(&str, &str)] = &[
        ("cat", "🐱 Meow"), ("dog", "🐶 Woof"), ("cow", "🐮 Moo"),
        ("pig", "🐷 Oink"), ("frog", "🐸 Ribbit"), ("monkey", "🐵 Ooh ooh"),
        ("chicken", "🐔 Cluck"), ("penguin", "🐧 Brr"), ("dragon", "🐉 ROAR"),
        ("unicorn", "🦄 Sparkle"), ("fox", "🦊 Yip"), ("bear", "🐻 Grr"),
        ("panda", "🐼 Munch"), ("koala", "🐨 Zzz"), ("tiger", "🐯 Roar"),
        ("lion", "🦁 ROAR"), ("rabbit", "🐰 Hop"), ("mouse", "🐭 Squeak"),
        ("horse", "🐴 Neigh"), ("snake", "🐍 Hiss"), ("turtle", "🐢 Slow..."),
        ("hedgehog", "🦔 Prickle"), ("elephant", "🐘 Trumpet"),
        ("octopus", "🐙 Wiggle"), ("crab", "🦀 Snap"), ("shark", "🦈 Chomp"),
        ("whale", "🐋 Sploosh"), ("dolphin", "🐬 Eee eee"), ("fish", "🐟 Blub"),
        ("bee", "🐝 Buzz"), ("butterfly", "🦋 Flutter"), ("snail", "🐌 ..."),
        ("ant", "🐜 March"), ("spider", "🕷️ Skitter"), ("owl", "🦉 Hoot"),
        ("duck", "🦆 Quack"), ("rooster", "🐓 Cock-a-doodle-doo"),
        ("eagle", "🦅 Screech"), ("parrot", "🦜 Hello hello"), ("flamingo", "🦩 Pose"),
        ("pizza", "🍕 Cheesy"), ("burger", "🍔 Juicy"), ("fries", "🍟 Crispy"),
        ("hotdog", "🌭 Glizzy"), ("sushi", "🍣 Sashimi time"), ("ramen", "🍜 Slurp"),
        ("cookie", "🍪 Crunch"), ("donut", "🍩 Sweet"), ("cake", "🍰 Yum"),
        ("cupcake", "🧁 Cute"), ("icecream", "🍦 Cold"), ("popcorn", "🍿 Pop pop"),
        ("apple", "🍎 Crisp"), ("banana", "🍌 Slip"), ("grapes", "🍇 Juicy"),
        ("watermelon", "🍉 Refreshing"), ("strawberry", "🍓 Sweet"),
        ("cherry", "🍒 Tart"), ("lemon", "🍋 Sour"), ("pear", "🍐 Mild"),
        ("peach", "🍑 Fuzzy"), ("mango", "🥭 Tropical"), ("pineapple", "🍍 Spiky"),
        ("coconut", "🥥 Tropical"), ("avocado", "🥑 Healthy"), ("carrot", "🥕 Crunch"),
        ("broccoli", "🥦 Greens"), ("corn", "🌽 Sweet"), ("mushroom", "🍄 Earthy"),
        ("car", "🚗 Vroom"), ("truck", "🚚 Honk"), ("bus", "🚌 Stop"),
        ("bike", "🚲 Pedal"), ("scooter", "🛴 Zoom"), ("train", "🚂 Choo choo"),
        ("plane", "✈️ Whoosh"), ("rocket", "🚀 BLAST OFF"), ("ship", "🚢 Toot"),
        ("helicopter", "🚁 Whirr"), ("ufo", "🛸 ...is that you?"),
        ("sun", "☀️ Bright"), ("moon", "🌙 Quiet"), ("star", "⭐ Shine"),
        ("rainbow", "🌈 Magic"), ("cloud", "☁️ Fluffy"), ("rain", "🌧️ Drip"),
        ("snow", "❄️ Brrr"), ("fire", "🔥 Hot"), ("water", "💧 Splash"),
        ("earth", "🌍 Home"), ("volcano", "🌋 BOOM"), ("mountain", "⛰️ Tall"),
        ("tree", "🌳 Tall"), ("flower", "🌸 Pretty"), ("rose", "🌹 Romantic"),
        ("sunflower", "🌻 Cheery"), ("cactus", "🌵 Prickly"),
        ("heart", "❤️ Love"), ("broken_heart", "💔 Sad"), ("sparkles", "✨ Magic"),
        ("crown", "👑 Royalty"), ("gem", "💎 Shiny"), ("gift", "🎁 Surprise"),
        ("trophy", "🏆 Winner"), ("medal", "🏅 Honored"), ("gold", "🥇 First"),
        ("silver", "🥈 Second"), ("bronze", "🥉 Third"),
        ("smile", "😊 Happy"), ("laugh", "😂 LOL"), ("wink", "😉 ;)"),
        ("love", "🥰 Adore"), ("cool", "😎 Chill"), ("nerd", "🤓 Smart"),
        ("think", "🤔 Hmm"), ("cry", "😭 Sob"), ("angry", "😠 Mad"),
        ("scream", "😱 AAAH"), ("sleep", "😴 Zzz"), ("dizzy", "😵 Whoa"),
        ("ghost", "👻 Boo"), ("alien", "👽 Greetings"), ("robot", "🤖 Beep boop"),
        ("clown", "🤡 Honk"), ("skull", "💀 Spooky"), ("zombie", "🧟 Brains"),
        ("vampire", "🧛 Bleh"), ("wizard", "🧙 Abracadabra"),
        ("fairy", "🧚 Magic"), ("mermaid", "🧜 Splash"), ("genie", "🧞 Three wishes"),
        ("ninja", "🥷 Stealth"), ("santa", "🎅 Ho ho ho"),
        ("guitar", "🎸 Strum"), ("drum", "🥁 Boom"), ("piano", "🎹 Tinkle"),
        ("trumpet", "🎺 Toot"), ("violin", "🎻 Sweet"), ("microphone", "🎤 Test test"),
        ("ball", "⚽ Kick"), ("basketball", "🏀 Dribble"), ("football", "🏈 Hike"),
        ("tennis", "🎾 Bounce"), ("baseball", "⚾ Crack"), ("bowling", "🎳 Strike"),
        ("chess", "♟️ Check"), ("dice", "🎲 Roll"), ("controller", "🎮 Play"),
        ("computer", "💻 Compile"), ("phone", "📱 Ring"), ("camera", "📷 Snap"),
        ("book", "📖 Read"), ("pencil", "✏️ Write"), ("calendar", "📅 Today"),
        ("clock", "🕐 Tick"), ("hourglass", "⏳ Wait"), ("key", "🔑 Unlock"),
        ("lock", "🔒 Secure"), ("magnet", "🧲 Pull"), ("battery", "🔋 Charged"),
        ("bulb", "💡 Idea"), ("rocket_ship", "🚀 To the moon"),
        ("salt", "🧂 Season"), ("pepper", "🌶️ Spicy"), ("garlic", "🧄 Aromatic"),
        ("onion", "🧅 Tear"), ("egg", "🥚 Fragile"), ("bread", "🍞 Toasty"),
        ("cheese", "🧀 Cheesy"), ("milk", "🥛 Moo"), ("honey", "🍯 Sweet"),
        ("coffee_cup", "☕ Wake up"), ("tea_cup", "🫖 Soothing"),
        ("beer", "🍺 Cheers"), ("wine", "🍷 Sip"), ("cocktail", "🍹 Fancy"),
        ("ramen_bowl", "🍜 Hot"), ("rice", "🍚 Filling"), ("noodle", "🍝 Twirl"),
    ];
    for (cmd, out) in emoji_table {
        if line == *cmd {
            println!("{}", out);
            return true;
        }
    }

    let saying_table: &[(&str, &str)] = &[
        ("yo", "Wassup"), ("hi", "Hello!"), ("hello", "Hi there!"),
        ("hey", "Yo!"), ("sup", "Not much."), ("howdy", "Partner."),
        ("bye", "See ya"), ("goodbye", "Farewell"), ("later", "Catch you later"),
        ("cya", "Bye!"), ("ciao", "Ciao!"), ("adios", "Adios!"),
        ("thanks", "You're welcome"), ("thx", "np"), ("ty", "yw"),
        ("sorry", "It's okay"), ("oops", "My bad"), ("yikes", "Yeah..."),
        ("nice", "👌 Niiice"), ("epic", "🔥 Epic"), ("lit", "🔥 Lit"),
        ("cool_beans", "Cool beans, friend"), ("rad", "Totally rad"),
        ("yeet", "YEET"), ("yolo", "You only live once"), ("oof", "oof."),
        ("mood", "Big mood"), ("based", "Based and red-pilled"),
        ("cringe", "ick"), ("slay", "💅 You slay"), ("queen", "💅 Yas queen"),
        ("king", "👑 King behavior"), ("vibe", "Immaculate vibes"),
        ("woof", "🐶 Bark!"), ("meow", "🐱 Purr"), ("quack", "🦆 Quack quack"),
        ("yes", "Affirmative"), ("no", "Negative"), ("maybe", "Perhaps..."),
        ("idk", "I don't know either"), ("idc", "fair"),
        ("lol", "lol"), ("rofl", "rofling"), ("lmao", "lmaoooo"),
        ("brb", "back in 5"), ("afk", "stepping away"), ("imo", "you're entitled"),
        ("tldr", "yeah I didn't read it either"),
        ("ggez", "good game everyone"), ("gg", "good game"),
        ("nope", "nope nope nope"), ("yup", "yup yup"),
        ("wow", "Mind blown 🤯"), ("omg", "OH MY"), ("wtf", "wat"),
        ("nani", "🇯🇵 NANI?!"), ("uwu", "uwu"), ("owo", "owo what's this"),
        ("kek", "kek"), ("rip", "F"), ("press_f", "F to pay respects"),
        ("happy", "😊 Happy days"), ("sad", "😢 Cheer up"),
        ("party_time", "🎉 PARTY TIME"), ("celebrate", "🎊 Celebrate!"),
        ("birthday", "🎂 Happy birthday!"), ("congrats", "🎉 Congratulations!"),
        ("oof_size", "Massive oof"), ("clutch", "Big clutch"),
        ("pog", "POGGERS"), ("based2", "extra based"),
        ("salty", "Pass the salt 🧂"), ("savage", "savage."),
        ("mic_drop", "🎤⬇️ mic dropped"), ("boom", "💥 BOOM"),
        ("kaboom", "💥💥 KABOOM"), ("explode", "💥 Boom goes the dynamite"),
        ("nope_no_no", "no no no no no"), ("yes_yes", "yes yes yes"),
        ("magic", "✨ poof! ✨"), ("zap", "⚡ ZAP"),
        ("snap", "*snap* "), ("clap", "👏 *applause*"),
        ("thumbs_up", "👍 nice"), ("thumbs_down", "👎 boo"),
        ("ok_hand", "👌 perfect"), ("peace", "✌️ peace out"),
        ("fist_bump", "👊 dap"), ("high_five", "🙏 high five"),
        ("salute", "🫡 o7"), ("o7", "o7"), ("salute_back", "o7 to you too"),
        ("praise", "🙌 praise!"), ("amen", "Amen 🙏"),
        ("hello_world", "Hello, World!"), ("foo", "bar"), ("bar", "baz"),
        ("baz", "qux"), ("ping_pong", "pong"), ("marco", "Polo!"),
        ("polo", "Marco?"), ("knock_knock", "Who's there?"),
        ("who", "You wouldn't know them"),
        ("doge", "much wow"), ("wow_doge", "such program. very code. much wow."),
        ("borf", "borf borf"), ("blep", ":P blep"),
        ("morning", "☀️ Good morning"), ("evening", "🌆 Good evening"),
        ("night", "🌙 Goodnight"), ("noon", "🌞 Noon"),
        ("monday", "Ugh, Monday"), ("friday", "🎉 Friday!"),
        ("weekend", "Weekend mode 😎"),
        ("sleepy", "😴 So sleepy"), ("tired", "😩 Exhausted"),
        ("hungry", "🍽️ Feed me"), ("thirsty", "💧 Hydrate"),
        ("bored", "😑 Meh"), ("excited", "🤩 So excited"),
        ("scared", "😨 Yikes"), ("brave", "🦁 Be brave"),
        ("smart", "🧠 Big brain"), ("dumb", "🥴 oof"),
        ("rich", "💰 Cha-ching"), ("broke", "💸 Pockets empty"),
        ("win", "🏆 Winner!"), ("lose", "😢 Try again"),
        ("level_up", "⬆️ LEVEL UP!"), ("achievement", "🏅 Achievement unlocked"),
        ("ezpz", "ez pz lemon squeezy"), ("git_gud", "git gud, scrub"),
        ("noob", "noob detected"), ("pro", "pro gamer move"),
        ("404", "404 Not Found"), ("500", "500 Internal Server Error"),
        ("hello_chicken", "🐔 The chicken lord acknowledges you"),
        ("praise_chicken", "🙏🐔 ALL HAIL"),
        ("sino", "Sino..."), ("rules", "Yes they do."),
    ];
    for (cmd, out) in saying_table {
        if line == *cmd {
            println!("{}", out);
            return true;
        }
    }

    if let Some(rest) = line.strip_prefix("is_alpha ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.chars().all(|c| c.is_alphabetic()) { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_digit ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()) { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_alnum ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.chars().all(|c| c.is_alphanumeric()) { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_upper ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.chars().filter(|c| c.is_alphabetic()).all(|c| c.is_uppercase()) { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_lower ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.chars().filter(|c| c.is_alphabetic()).all(|c| c.is_lowercase()) { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_whitespace ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.chars().all(|c| c.is_whitespace()) { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_ascii ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if s.is_ascii() { 1 } else { 0 });
        }
        return true;
    }

    macro_rules! math_unary {
        ($name:expr, $f:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($name, " ")) {
                let parts: Vec<&str> = rest.splitn(2, '=').collect();
                if parts.len() == 2 {
                    let var = parts[0].trim().to_string();
                    let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
                    let v: f64 = $f(n);
                    if v.fract() == 0.0 && v.is_finite() && v.abs() < 1e18 {
                        vars.insert(var, v as i64);
                    } else {
                        oop.string_vars.insert(var, v.to_string());
                    }
                }
                return true;
            }
        };
    }

    math_unary!("sin", |x: f64| x.sin());
    math_unary!("cos", |x: f64| x.cos());
    math_unary!("tan", |x: f64| x.tan());
    math_unary!("asin", |x: f64| x.asin());
    math_unary!("acos", |x: f64| x.acos());
    math_unary!("atan", |x: f64| x.atan());
    math_unary!("sinh", |x: f64| x.sinh());
    math_unary!("cosh", |x: f64| x.cosh());
    math_unary!("tanh", |x: f64| x.tanh());
    math_unary!("asinh", |x: f64| x.asinh());
    math_unary!("acosh", |x: f64| x.acosh());
    math_unary!("atanh", |x: f64| x.atanh());
    math_unary!("exp", |x: f64| x.exp());
    math_unary!("exp2", |x: f64| x.exp2());
    math_unary!("ln", |x: f64| x.ln());
    math_unary!("log2", |x: f64| x.log2());
    math_unary!("log10", |x: f64| x.log10());
    math_unary!("cbrt", |x: f64| x.cbrt());
    math_unary!("recip", |x: f64| 1.0 / x);

    if let Some(rest) = line.strip_prefix("atan2 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let y: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let x: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                oop.string_vars.insert(var, y.atan2(x).to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("log_base ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let n: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let base: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(10.0);
                oop.string_vars.insert(var, n.log(base).to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("hypot ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let b: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                oop.string_vars.insert(var, a.hypot(b).to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("phi ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, ((1.0 + 5f64.sqrt()) / 2.0).to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("tau ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, std::f64::consts::TAU.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("sqrt2 ") {
        let var = rest.trim().to_string();
        oop.string_vars.insert(var, std::f64::consts::SQRT_2.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("hr ") {
        let n: usize = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(40);
        println!("{}", "─".repeat(n));
        return true;
    }
    if line == "hr" {
        println!("{}", "─".repeat(40));
        return true;
    }

    if let Some(rest) = line.strip_prefix("divider ") {
        let s = resolve_arg(rest.trim(), vars, oop);
        let len = s.chars().count().max(40);
        println!("{}", "═".repeat(len));
        println!("{}", s);
        println!("{}", "═".repeat(len));
        return true;
    }

    if let Some(rest) = line.strip_prefix("askstring ") {
        let var = rest.trim().to_string();
        print!("{}: ", var);
        let _ = io::stdout().flush();
        let mut input = String::new();
        let _ = io::stdin().read_line(&mut input);
        oop.string_vars.insert(var, input.trim().to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("askyesno ") {
        let var = rest.trim().to_string();
        print!("{} (y/n): ", var);
        let _ = io::stdout().flush();
        let mut input = String::new();
        let _ = io::stdin().read_line(&mut input);
        let yes = input.trim().to_lowercase().starts_with('y');
        vars.insert(var, if yes { 1 } else { 0 });
        return true;
    }

    if line == "cmds" {
        let mut all: Vec<&&str> = KNOWN_COMMANDS.iter().collect();
        all.sort();
        for (i, c) in all.iter().enumerate() {
            if i % 6 == 5 { println!("{:14}", c); } else { print!("{:14} ", c); }
        }
        println!();
        println!("Total: {} commands", all.len());
        return true;
    }

    if line == "cmd_count" {
        println!("{}", KNOWN_COMMANDS.len());
        return true;
    }

    if let Some(rest) = line.strip_prefix("rgb ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let r: u8 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
            let g: u8 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let b: u8 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0);
            print!("\x1b[38;2;{};{};{}m", r, g, b);
            let _ = io::stdout().flush();
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("bgrgb ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let r: u8 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
            let g: u8 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let b: u8 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0);
            print!("\x1b[48;2;{};{};{}m", r, g, b);
            let _ = io::stdout().flush();
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("repeat_print ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let s = resolve_arg(&args[0], vars, oop);
            let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            for _ in 0..n {
                println!("{}", s);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("times ") {
        let args = split_args(rest);
        if args.len() >= 1 {
            let n: usize = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
            let msg = if args.len() >= 2 {
                resolve_arg(&args[1], vars, oop)
            } else {
                String::new()
            };
            for i in 0..n {
                println!("{} {}", i, msg);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("countdown ") {
        let n: i64 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(0);
        for i in (1..=n).rev() {
            println!("{}", i);
            thread::sleep(Duration::from_millis(500));
        }
        println!("Go!");
        return true;
    }

    if let Some(rest) = line.strip_prefix("countup ") {
        let n: i64 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(0);
        for i in 1..=n {
            println!("{}", i);
            thread::sleep(Duration::from_millis(300));
        }
        return true;
    }

    if line == "yes_no" {
        println!("Maybe.");
        return true;
    }

    if line == "magic_8_ball" {
        let answers = [
            "It is certain.", "Reply hazy, try again.", "Don't count on it.",
            "Yes definitely.", "Most likely.", "My sources say no.",
            "Outlook not so good.", "Signs point to yes.", "Cannot predict now.",
            "Ask again later.", "Without a doubt.", "Very doubtful.",
        ];
        let mut rng = rand::thread_rng();
        let pick = rand::Rng::gen_range(&mut rng, 0..answers.len());
        println!("🎱 {}", answers[pick]);
        return true;
    }

    if line == "flip_coin" {
        let b: bool = rand::Rng::gen_bool(&mut rand::thread_rng(), 0.5);
        println!("{}", if b { "🪙 Heads" } else { "🪙 Tails" });
        return true;
    }

    if line == "compliment" {
        let lines = [
            "You're crushing it.", "That code is beautiful.",
            "You write tests like a hero.", "Your dedication is inspiring.",
            "You make pair programming better.", "Nobody refactors like you.",
        ];
        let mut rng = rand::thread_rng();
        let pick = rand::Rng::gen_range(&mut rng, 0..lines.len());
        println!("💖 {}", lines[pick]);
        return true;
    }

    if line == "insult" {
        let lines = [
            "Your code smells like Friday-afternoon code.",
            "Even GPT-2 could refactor this better.",
            "This deserves a `// TODO: rewrite`.",
        ];
        let mut rng = rand::thread_rng();
        let pick = rand::Rng::gen_range(&mut rng, 0..lines.len());
        println!("🔥 {}", lines[pick]);
        return true;
    }

    if line == "joke" {
        let jokes = [
            "Why do programmers prefer dark mode? Because light attracts bugs.",
            "There are 10 kinds of people in this world: those who understand binary, and those who don't.",
            "A SQL query walks into a bar, sees two tables, and asks: 'May I join you?'",
            "How many programmers does it take to change a lightbulb? None, that's a hardware problem.",
            "Why did the developer go broke? They used up all their cache.",
        ];
        let mut rng = rand::thread_rng();
        let pick = rand::Rng::gen_range(&mut rng, 0..jokes.len());
        println!("😂 {}", jokes[pick]);
        return true;
    }

    let emoji_table2: &[(&str, &str)] = &[
        ("giraffe", "🦒 Tall"), ("zebra", "🦓 Stripes"), ("camel", "🐫 Sand"),
        ("sheep", "🐑 Baa"), ("goat", "🐐 Mehh"), ("llama", "🦙 Spit"),
        ("hippo", "🦛 Splash"), ("rhino", "🦏 Charge"), ("kangaroo", "🦘 Hop hop"),
        ("sloth", "🦥 ...zzz"), ("otter", "🦦 Float"), ("badger", "🦡 Don't care"),
        ("skunk", "🦨 Smelly"), ("raccoon", "🦝 Trash panda"),
        ("squirrel", "🐿️ Nuts"), ("chipmunk", "🐿️ Chitter"),
        ("bat", "🦇 Flap"), ("dragon_face", "🐲 Roar"),
        ("seal", "🦭 Awooo"), ("walrus", "🦣 Tusk"),
        ("worm", "🪱 Wriggle"), ("ladybug", "🐞 Lucky"),
        ("beetle", "🪲 Buzz"), ("mosquito", "🦟 Bzzzz"), ("fly", "🪰 Annoying"),
        ("cricket", "🦗 Chirp"), ("scorpion", "🦂 Sting"),
        ("shrimp", "🦐 Pop"), ("squid", "🦑 Ink"), ("oyster", "🦪 Pearl"),
        ("lobster", "🦞 Pinch"),
        ("eggplant", "🍆"), ("tomato", "🍅 Saucy"), ("potato", "🥔 Spud"),
        ("sweet_potato", "🍠 Sweet"), ("cucumber", "🥒 Cool"),
        ("kiwi", "🥝 Fuzzy"), ("blueberry", "🫐 Tiny"),
        ("olive", "🫒 Salty"), ("bell_pepper", "🫑 Crunch"),
        ("waffle", "🧇 Buttery"), ("pancake", "🥞 Stacked"), ("croissant", "🥐 Flaky"),
        ("bagel", "🥯 Hole-some"), ("pretzel", "🥨 Twisted"),
        ("taco_food", "🌮 Tasty"), ("burrito", "🌯 Wrapped"),
        ("sandwich", "🥪 Layered"), ("falafel", "🧆 Chickpea"),
        ("dumpling", "🥟 Pinched"), ("kebab", "🌯 Skewer"),
        ("steak", "🥩 Sizzle"), ("bacon", "🥓 Crispy"),
        ("chocolate", "🍫 Sweet"), ("candy", "🍬 Yum"), ("lollipop", "🍭 Twist"),
        ("baby_bottle", "🍼 Glug"),
        ("motorcycle", "🏍️ Vroom"), ("racecar", "🏎️ Zoom"), ("tractor", "🚜 Slow"),
        ("forklift", "🏗️ Lift"), ("ambulance", "🚑 Wee woo"), ("firetruck", "🚒 Honk"),
        ("policecar", "🚓 Stop"), ("taxi", "🚕 Hail"), ("subway", "🚇 Mind the gap"),
        ("tram", "🚊 Ding ding"), ("rollercoaster", "🎢 WHEEEE"),
        ("ferris_wheel", "🎡 Slow rotation"), ("carousel", "🎠 Round and round"),
        ("kite", "🪁 Windy"), ("balloon", "🎈 Floaty"), ("flag", "🚩 Marked"),
        ("checkered", "🏁 Finish"),
        ("snowflake", "❄️ Unique"), ("snowman", "⛄ Cold"), ("comet", "☄️ Whoosh"),
        ("hurricane", "🌀 Spinny"), ("tornado", "🌪️ Twister"),
        ("fog", "🌫️ Hazy"), ("lightning", "🌩️ Strike"),
        ("typhoon", "🌀 Storm"),
        ("dollar", "💵 Cha-ching"), ("euro", "💶 Euro"), ("yen", "💴 Yen"),
        ("pound", "💷 Quid"), ("money_bag", "💰 Riches"),
        ("credit_card", "💳 Beep"), ("receipt", "🧾 Saved"),
        ("guitar_classical", "🎸 Rock"), ("saxophone", "🎷 Smooth"),
        ("accordion", "🪗 Polka"), ("banjo", "🪕 Twang"),
        ("envelope", "✉️ Mail"), ("package", "📦 Boxed"),
        ("scissors", "✂️ Snip"), ("hammer", "🔨 Bang"), ("wrench", "🔧 Tight"),
        ("screwdriver", "🪛 Turn"), ("nail", "🪛 Hammer"), ("toolbox", "🧰 Equipped"),
        ("microscope", "🔬 Tiny"), ("telescope", "🔭 Far"),
        ("magnify", "🔍 Search"), ("test_tube", "🧪 Science"),
        ("dna", "🧬 Genes"), ("syringe", "💉 Ouch"),
        ("pill", "💊 Cure"), ("bandage", "🩹 Patched"),
        ("toothbrush", "🪥 Clean"), ("soap", "🧼 Bubbly"),
        ("toilet_paper", "🧻 Last roll"), ("sponge", "🧽 Squishy"),
        ("plunger", "🪠 Unclog"), ("bucket", "🪣 Bring water"),
        ("umbrella", "☂️ Dry"), ("umbrella2", "🌂 Folded"),
        ("compass", "🧭 North"), ("map", "🗺️ Wandering"),
        ("dice2", "🎲 Roll again"), ("game_die", "🎲 Six"),
        ("puzzle", "🧩 Click"), ("teddy", "🧸 Cuddly"),
        ("frame", "🖼️ Framed"), ("paint", "🎨 Artsy"),
        ("brush", "🖌️ Stroke"),
        ("usa", "🇺🇸 Liberty"), ("uk", "🇬🇧 Tea time"), ("canada", "🇨🇦 Sorry, eh"),
        ("japan", "🇯🇵 Konnichiwa"), ("france", "🇫🇷 Bonjour"),
        ("germany", "🇩🇪 Guten tag"), ("spain", "🇪🇸 Hola"),
        ("italy", "🇮🇹 Ciao"), ("brazil", "🇧🇷 Olá"),
        ("mexico", "🇲🇽 Hola"), ("india", "🇮🇳 Namaste"),
        ("china", "🇨🇳 Ni hao"), ("korea", "🇰🇷 Annyeong"),
        ("russia", "🇷🇺 Privet"),
        ("london", "🏙️ Big Ben"), ("paris", "🗼 Tour Eiffel"),
        ("tokyo", "🗾 Konnichiwa"), ("nyc", "🗽 Big Apple"),
        ("rome", "🏛️ Colosseum"), ("egypt", "🏜️ Pyramids"),
        ("hawaii", "🌺 Aloha"), ("california", "🌴 Cali"),
    ];
    for (cmd, out) in emoji_table2 {
        if line == *cmd {
            println!("{}", out);
            return true;
        }
    }

    let saying_table2: &[(&str, &str)] = &[
        ("be_kind", "Be kind. Always."),
        ("be_brave", "Be brave. Always."),
        ("be_yourself", "Be yourself. The world adjusts."),
        ("believe", "Believe in yourself."),
        ("dream_big", "Dream big. Start small."),
        ("never_quit", "Never quit. Adapt."),
        ("keep_going", "Keep going."),
        ("breathe", "Just breathe. Slowly."),
        ("smile_more", "Smile a little more today."),
        ("you_matter", "You matter."),
        ("good_luck", "Good luck out there."),
        ("good_morning", "Good morning, world."),
        ("good_night", "Goodnight, sleep well."),
        ("see_you", "See you next time."),
        ("safe_travels", "Safe travels."),
        ("welcome", "Welcome!"),
        ("welcome_back", "Welcome back!"),
        ("get_well", "Get well soon."),
        ("you_got_this", "You got this. Trust me."),
        ("breathe_in", "Inhale..."),
        ("breathe_out", "Exhale."),
        ("om", "Om..."),
        ("namaste", "🙏 Namaste"),
        ("zen", "Be water, my friend."),
        ("focus", "Focus. Just one thing."),
        ("relax", "Relax. The deadline can wait."),
        ("chill", "Chill. It's fine."),
        ("vibe_check", "Vibe check: ✅ vibing"),
        ("mood2", "It's a mood."),
        ("facts", "Facts only."),
        ("real_talk", "Real talk."),
        ("no_cap", "No cap, fr"),
        ("cap", "🧢 cap"),
        ("frfr", "for real for real"),
        ("on_god", "on god"),
        ("sus", "kinda sus"),
        ("bussin", "this is bussin"),
        ("slaps", "this slaps"),
        ("clean", "clean."),
        ("dirty", "Dirty."),
        ("messy", "Messy."),
        ("sleek", "Sleek."),
        ("yass", "💅 YAAAS"),
        ("periodt", "PERIODT."),
        ("tea", "Spill the tea ☕"),
        ("the_tea", "👀 ooh the tea"),
        ("anyway", "Anyway..."),
        ("moving_on", "Moving on."),
        ("but_anyway", "But anyway..."),
        ("absolutely", "Absolutely!"),
        ("definitely", "Definitely."),
        ("totally", "Totally."),
        ("for_sure", "For sure."),
        ("of_course", "Of course."),
        ("naturally", "Naturally."),
        ("obviously", "Obviously."),
        ("clearly", "Clearly."),
        ("undoubtedly", "Undoubtedly."),
        ("certainly", "Certainly."),
        ("indeed", "Indeed."),
        ("agreed", "Agreed."),
        ("seconded", "Seconded."),
        ("disagree", "I disagree."),
        ("disagreed", "Strongly disagree."),
        ("hmm", "Hmm..."),
        ("interesting", "Interesting."),
        ("intriguing", "Intriguing..."),
        ("curious", "Curious."),
        ("strange", "Strange..."),
        ("weird", "Weird."),
        ("odd", "Odd."),
        ("typical", "Typical."),
        ("classic", "Classic."),
        ("legendary", "Legendary."),
        ("iconic", "Iconic."),
        ("historic", "Historic."),
        ("monumental", "Monumental."),
        ("incredible", "Incredible."),
        ("unbelievable", "Unbelievable."),
        ("astonishing", "Astonishing."),
        ("amazing", "Amazing."),
        ("excellent", "Excellent."),
        ("superb", "Superb."),
        ("magnificent", "Magnificent."),
        ("splendid", "Splendid."),
        ("fantastic", "Fantastic."),
        ("wonderful", "Wonderful."),
        ("marvelous", "Marvelous."),
        ("brilliant", "Brilliant!"),
        ("genius", "Genius!"),
        ("smart_move", "Smart move."),
        ("oof_no", "Oof. No."),
        ("the_chosen_one", "You are the chosen one."),
        ("destiny", "It is your destiny."),
        ("fate", "Fate has spoken."),
        ("by_the_way", "By the way..."),
        ("speaking_of", "Speaking of which..."),
        ("interrupt", "Sorry to interrupt..."),
        ("just_saying", "Just sayin'."),
        ("not_to_brag", "Not to brag, but..."),
        ("to_be_fair", "To be fair..."),
        ("in_my_defense", "In my defense..."),
        ("technically", "Technically..."),
        ("apparently", "Apparently."),
        ("supposedly", "Supposedly."),
        ("rumor_has_it", "Rumor has it..."),
        ("the_plot_thickens", "The plot thickens."),
        ("twist", "Plot twist!"),
        ("redemption", "Redemption arc."),
        ("character_development", "Character development."),
        ("foreshadowing", "Foreshadowing intensifies."),
        ("hello_there", "General Kenobi."),
        ("may_the_force", "May the force be with you."),
        ("live_long", "Live long and prosper."),
        ("avengers", "Avengers, assemble!"),
        ("wakanda", "Wakanda forever."),
        ("its_a_trap", "It's a trap!"),
        ("im_batman", "I'm Batman."),
        ("with_great_power", "With great power comes great responsibility."),
        ("there_is_no_try", "Do or do not, there is no try."),
        ("hodor", "Hodor."),
        ("winter_is_coming", "Winter is coming."),
        ("dracarys", "Dracarys."),
        ("you_shall_not_pass", "YOU SHALL NOT PASS"),
        ("one_does_not_simply", "One does not simply..."),
        ("hello_neighbor", "Hi neighbor."),
        ("dunder_mifflin", "Welcome to Dunder Mifflin."),
        ("bears_beets", "Bears. Beets. Battlestar Galactica."),
        ("the_office", "That's what she said."),
        ("yas_queen", "💅 YAS QUEEN"),
        ("girlboss", "Gatekeep gaslight girlboss"),
        ("touch_grass", "Go touch grass."),
        ("rent_free", "Living in your head rent free."),
        ("we_live_in_a_society", "We live in a society."),
        ("number_go_up", "Number go up 📈"),
        ("number_go_down", "Number go down 📉"),
        ("number_go_brr", "Number printer go brrrrrr"),
        ("stonks", "📈 STONKS"),
        ("not_stonks", "📉 NOT STONKS"),
        ("buy_high", "Buy high, sell low. Classic."),
        ("hodl", "💎🙌 HODL"),
        ("to_the_moon", "🚀🌙 To the moon!"),
        ("diamond_hands", "💎🙌 Diamond hands"),
        ("paper_hands", "📜🙌 Paper hands"),
        ("ape", "Apes together strong 🦍"),
        ("git_blame", "Don't blame me, blame the git history."),
        ("rubber_duck", "🦆 Quack. Try explaining to me."),
        ("stack_overflow", "Have you tried Stack Overflow?"),
        ("on_my_machine", "Works on my machine."),
        ("ship_it", "Ship it 🚀"),
        ("merge_conflict", "Merge conflicts make me sad."),
        ("force_push", "Don't force push to main."),
        ("hot_reload", "Hot reload? Cold reload? Just reload."),
        ("legacy_code", "Ancient code. Don't touch it."),
        ("works_for_now", "Works for now."),
        ("good_enough", "Good enough."),
        ("ship_friday", "Don't ship on Friday."),
        ("ship_monday", "Don't ship Monday morning either."),
        ("test_in_prod", "Test in prod."),
        ("its_a_feature", "It's not a bug, it's a feature."),
        ("documented_behavior", "It's documented behavior."),
        ("breaking_change", "This is a breaking change."),
        ("backwards_compat", "Backwards compatibility, baby."),
        ("undefined_behavior", "Undefined behavior. Run."),
        ("race_condition", "Maybe it's a race condition?"),
        ("heisenbug", "Disappears when you debug it. Heisenbug."),
        ("dependency_hell", "Welcome to dependency hell."),
        ("yak_shaving", "Yak shaving in progress."),
        ("bikeshedding", "We're bikeshedding."),
        ("scope_creep", "Scope creep alert 🚨"),
        ("technical_debt", "Adding to technical debt..."),
        ("refactor", "Time to refactor."),
        ("rewrite", "Just rewrite it from scratch."),
        ("nope_out", "Nope.gif"),
        ("git_push", "git push --force? Risky."),
        ("git_pull", "Pull before you push."),
        ("merge_pr", "LGTM, merging."),
        ("approve", "✅ Approved"),
        ("request_changes", "Requesting changes."),
        ("nitpick", "Nitpick: ..."),
        ("blocker", "🚫 Blocker"),
        ("optional", "Optional nit"),
        ("ship_it_squirrel", "🐿️ Ship it squirrel!"),
        ("dance", "💃 Dancing"),
        ("breakdance", "🕺 Breakdancing"),
        ("moonwalk", "🕺 Hee hee!"),
        ("flex", "💪 Flexing"),
        ("strong", "💪 Strong"),
        ("weak", "Weak..."),
        ("speedrun", "🏁 Speedrun any%"),
        ("any_percent", "Any% strats activated"),
        ("save_state", "💾 Save state"),
        ("load_state", "Loading save..."),
        ("game_over", "GAME OVER"),
        ("respawn", "Respawning..."),
        ("checkpoint", "🚩 Checkpoint reached"),
        ("you_died", "YOU DIED"),
        ("level_complete", "LEVEL COMPLETE"),
        ("boss_battle", "⚔️ BOSS BATTLE"),
        ("xp_gained", "+25 XP"),
        ("gold_gained", "+50 gold"),
        ("loot", "💰 Loot acquired"),
        ("quest_complete", "✓ Quest complete"),
        ("crit", "💥 CRITICAL HIT"),
        ("miss", "Miss!"),
        ("dodge", "Dodged!"),
        ("parry", "Parried!"),
        ("block", "Blocked."),
        ("counter", "Counter!"),
    ];
    for (cmd, out) in saying_table2 {
        if line == *cmd {
            println!("{}", out);
            return true;
        }
    }

    let constants_table: &[(&str, &str)] = &[
        ("avogadro", "6.02214076e23 (Avogadro's number)"),
        ("planck", "6.62607015e-34 (Planck constant, J·s)"),
        ("gravity", "9.80665 (m/s² standard gravity)"),
        ("light_speed", "299792458 (m/s)"),
        ("boltzmann", "1.380649e-23 (Boltzmann constant, J/K)"),
        ("electron_charge", "1.602176634e-19 (elementary charge, C)"),
        ("electron_mass", "9.1093837015e-31 (electron mass, kg)"),
        ("proton_mass", "1.67262192369e-27 (proton mass, kg)"),
        ("absolute_zero", "-273.15 (°C)"),
        ("earth_radius", "6371000 (m, mean)"),
        ("moon_distance", "384400000 (m average)"),
        ("sun_distance", "149597870700 (m, 1 AU)"),
        ("gas_constant", "8.314462618 (J/(mol·K))"),
        ("stefan_boltzmann", "5.670374419e-8 (W·m⁻²·K⁻⁴)"),
        ("vacuum_permittivity", "8.8541878128e-12 (F/m)"),
        ("vacuum_permeability", "1.25663706212e-6 (N/A²)"),
        ("year_seconds", "31557600 (≈365.25 days in seconds)"),
        ("day_seconds", "86400"),
        ("hour_seconds", "3600"),
        ("minute_seconds", "60"),
        ("week_seconds", "604800"),
        ("month_seconds", "2629800 (≈30.44 days)"),
    ];
    for (cmd, out) in constants_table {
        if line == *cmd {
            println!("{}", out);
            return true;
        }
    }

    let history_table: &[(&str, &str)] = &[
        ("einstein", "E = mc² — Einstein"),
        ("newton", "If I have seen further, it is by standing on the shoulders of giants. — Newton"),
        ("hawking", "Intelligence is the ability to adapt to change. — Hawking"),
        ("turing", "A computer would deserve to be called intelligent if it could deceive a human into believing that it was human. — Turing"),
        ("lovelace", "That brain of mine is something more than merely mortal. — Ada Lovelace"),
        ("hopper", "The most damaging phrase in the language is 'we've always done it this way.' — Grace Hopper"),
        ("knuth", "Premature optimization is the root of all evil. — Knuth"),
        ("dijkstra", "Computer Science is no more about computers than astronomy is about telescopes. — Dijkstra"),
        ("torvalds", "Talk is cheap. Show me the code. — Linus Torvalds"),
        ("guido", "Code is read more often than it is written. — Guido van Rossum"),
        ("ritchie", "C is quirky, flawed, and an enormous success. — Dennis Ritchie"),
        ("aristotle", "We are what we repeatedly do. — Aristotle"),
        ("plato", "The beginning is the most important part of the work. — Plato"),
        ("socrates", "I know that I know nothing. — Socrates"),
        ("confucius", "It does not matter how slowly you go as long as you do not stop. — Confucius"),
        ("gandhi", "Be the change that you wish to see in the world. — Gandhi"),
        ("mlk", "The time is always right to do what is right. — MLK Jr."),
        ("mandela", "It always seems impossible until it's done. — Mandela"),
        ("lincoln", "The best way to predict your future is to create it. — Lincoln"),
        ("kennedy", "Ask not what your country can do for you. — JFK"),
        ("franklin", "Tell me and I forget. Teach me and I remember. Involve me and I learn. — Ben Franklin"),
        ("twain", "The two most important days in your life are the day you are born and the day you find out why. — Twain"),
        ("emerson", "What lies behind us and what lies before us are tiny matters compared to what lies within us. — Emerson"),
        ("thoreau", "Go confidently in the direction of your dreams. — Thoreau"),
        ("shakespeare", "To be, or not to be, that is the question. — Shakespeare"),
        ("dickens", "It was the best of times, it was the worst of times. — Dickens"),
        ("tolkien", "Not all those who wander are lost. — Tolkien"),
        ("rowling", "It is our choices that show what we truly are. — Rowling"),
        ("austen", "It is a truth universally acknowledged... — Austen"),
        ("orwell", "Big Brother is watching you. — Orwell"),
        ("vonnegut", "We are what we pretend to be. — Vonnegut"),
    ];
    for (cmd, out) in history_table {
        if line == *cmd {
            println!("📜 {}", out);
            return true;
        }
    }

    let extra_misc: &[(&str, &str)] = &[
        ("greet", "Hello there. 👋"),
        ("farewell", "Until next time. 👋"),
        ("welcome_aboard", "Welcome aboard! 🚀"),
        ("standing_ovation", "👏👏👏 *standing ovation*"),
        ("encore", "Encore! Encore!"),
        ("bravo", "Bravo! 👏"),
        ("hooray", "Hooray! 🎉"),
        ("hurrah", "Hurrah!"),
        ("huzzah", "Huzzah!"),
        ("eureka", "EUREKA!"),
        ("aha", "Aha!"),
        ("ahem", "Ahem."),
        ("yawn", "*yawn*"),
        ("groan", "*groan*"),
        ("sigh", "*sigh*"),
        ("gasp", "*gasp*"),
        ("snort", "*snort*"),
        ("giggle", "*giggle*"),
        ("chuckle", "*chuckle*"),
        ("guffaw", "GUFFAW"),
        ("smirk", "*smirk*"),
        ("grin", "*grin*"),
        ("squint", "*squint*"),
        ("ponder", "🤔 *ponder*"),
        ("contemplate", "*contemplating*"),
        ("daydream", "*daydreams*"),
        ("nightmare", "*nightmare intensifies*"),
        ("sweet_dreams", "Sweet dreams 💤"),
        ("nap_time", "💤 Nap time"),
        ("siesta", "Siesta time 😴"),
        ("snore", "*snore*"),
        ("scratch", "*scratches head*"),
        ("pace", "*paces*"),
        ("twiddle", "*twiddles thumbs*"),
        ("whistle", "*whistles*"),
        ("hum", "*hums*"),
        ("tap_tap", "*tap tap tap*"),
        ("knock", "*knock knock*"),
        ("ding", "🔔 *ding*"),
        ("buzz", "🔊 *buzz*"),
        ("ring", "📞 *ring ring*"),
        ("crash", "💥 *crash*"),
        ("bang", "💥 *bang*"),
        ("pop", "💥 *pop*"),
        ("whoosh", "💨 *whoosh*"),
        ("zoom", "💨 *zoom*"),
        ("zap_sound", "⚡ *zap*"),
        ("kapow", "💥 KAPOW"),
        ("kaboom_2", "💣 KABOOM"),
        ("ka_ching", "💰 *ka-ching*"),
        ("nom", "*nom nom nom*"),
        ("crunch", "*crunch*"),
        ("munch", "*munch*"),
        ("slurp", "*slurp*"),
        ("gulp", "*gulp*"),
        ("burp", "*burp*"),
        ("hiccup", "*hic*"),
        ("sneeze", "*ACHOO!*"),
        ("cough", "*cough cough*"),
        ("ahchoo", "*ah-choo!*"),
        ("bless_you", "Bless you 🙏"),
        ("blink", "*blink*"),
        ("nod", "*nods*"),
        ("shake_head", "*shakes head*"),
        ("shrug", "🤷 *shrug*"),
        ("facepalm", "🤦 *facepalm*"),
        ("headdesk", "*head meets desk*"),
        ("eye_roll", "🙄 *eye roll*"),
        ("side_eye", "👀 *side eye*"),
        ("staring", "👁️ *staring*"),
        ("glare", "*glare*"),
        ("scowl", "*scowl*"),
        ("frown", "*frown*"),
        ("pout", "*pout*"),
        ("scoff", "*scoff*"),
        ("snicker", "*snicker*"),
        ("titter", "*titter*"),
        ("squeal", "*squeal*"),
        ("yell", "*yells*"),
        ("shout", "*shouts*"),
        ("whisper", "*whispers*"),
        ("mumble", "*mumbles*"),
        ("mutter", "*mutters*"),
        ("grumble", "*grumbles*"),
        ("rant", "*ranting*"),
        ("rave", "*raving*"),
        ("pace_around", "*paces around*"),
        ("twirl", "*twirls*"),
        ("spin_around", "*spins around*"),
        ("jump", "*jumps*"),
        ("hop", "*hops*"),
        ("skip", "*skips*"),
        ("leap", "*leaps*"),
        ("lunge", "*lunges*"),
        ("dash", "*dashes*"),
        ("sprint", "*sprints*"),
        ("jog", "*jogs*"),
        ("stroll", "*strolls*"),
        ("wander", "*wanders*"),
        ("explore", "*explores*"),
        ("discover", "*discovers*"),
        ("found", "Found it!"),
        ("not_found", "Not found."),
        ("lost", "Lost..."),
        ("located", "Located. ✓"),
        ("hidden", "Hidden."),
        ("revealed", "Revealed."),
        ("secret", "🤫 Secret"),
        ("classified", "📁 CLASSIFIED"),
        ("top_secret", "🔒 TOP SECRET"),
        ("public", "📢 PUBLIC"),
        ("private2", "🔒 PRIVATE"),
        ("approved2", "✅ APPROVED"),
        ("rejected", "❌ REJECTED"),
        ("pending", "⏳ PENDING"),
        ("review", "👀 Under review"),
        ("done2", "✅ DONE"),
        ("todo2", "📝 TODO"),
        ("in_progress", "⏳ In progress"),
        ("blocked", "🚫 BLOCKED"),
        ("dunno", "Dunno 🤷"),
        ("aok", "All systems A-OK ✓"),
        ("standby", "Standing by..."),
        ("ready", "Ready."),
        ("not_ready", "Not ready yet."),
        ("almost", "Almost there."),
        ("nearly", "Nearly!"),
        ("just_about", "Just about."),
        ("about_done", "About done."),
        ("here_we_go", "Here we go!"),
        ("lets_go", "Let's go!"),
        ("away_we_go", "And away we go!"),
        ("liftoff", "Liftoff 🚀"),
        ("touchdown", "Touchdown!"),
        ("landed", "Landed safely."),
        ("departed", "Departed."),
        ("arrived", "Arrived."),
        ("on_time", "On time ⏰"),
        ("late", "Late ⏰"),
        ("early", "Early!"),
        ("punctual", "Punctual."),
    ];
    for (cmd, out) in extra_misc {
        if line == *cmd {
            println!("{}", out);
            return true;
        }
    }

    if let Some(rest) = line.strip_prefix("uuid ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let target = if parts.len() == 2 {
            parts[0].trim().to_string()
        } else {
            rest.trim().to_string()
        };
        let mut id = String::new();
        let hex = "0123456789abcdef";
        let hb = hex.as_bytes();
        let mut rng = rand::thread_rng();
        for (i, _) in (0..32).enumerate() {
            if i == 8 || i == 12 || i == 16 || i == 20 {
                id.push('-');
            }
            let n: usize = rand::Rng::gen_range(&mut rng, 0..16);
            id.push(hb[n] as char);
        }
        oop.string_vars.insert(target, id);
        return true;
    }

    if let Some(rest) = line.strip_prefix("hostname ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let target = if parts.len() == 2 {
            parts[0].trim().to_string()
        } else {
            rest.trim().to_string()
        };
        let h = std::process::Command::new("hostname")
            .output()
            .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
            .unwrap_or_else(|_| "unknown".to_string());
        oop.string_vars.insert(target, h);
        return true;
    }

    if let Some(rest) = line.strip_prefix("html_escape ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let escaped: String = s.chars().map(|c| match c {
                '&' => "&amp;".to_string(),
                '<' => "&lt;".to_string(),
                '>' => "&gt;".to_string(),
                '"' => "&quot;".to_string(),
                '\'' => "&#39;".to_string(),
                _ => c.to_string(),
            }).collect();
            oop.string_vars.insert(var, escaped);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("url_escape ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let escaped: String = s
                .bytes()
                .map(|b| {
                    if (b'A'..=b'Z').contains(&b)
                        || (b'a'..=b'z').contains(&b)
                        || (b'0'..=b'9').contains(&b)
                        || b == b'-'
                        || b == b'_'
                        || b == b'.'
                        || b == b'~'
                    {
                        (b as char).to_string()
                    } else {
                        format!("%{:02X}", b)
                    }
                })
                .collect();
            oop.string_vars.insert(var, escaped);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("time_start ") {
        let name = rest.trim().to_string();
        let n = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| d.as_millis() as i64)
            .unwrap_or(0);
        vars.insert(format!("__time_{}", name), n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("time_end ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let start = vars
            .get(&format!("__time_{}", name))
            .copied()
            .unwrap_or(0);
        let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| d.as_millis() as i64)
            .unwrap_or(0);
        let elapsed = now - start;
        if let Some(v) = result_var {
            vars.insert(v, elapsed);
        } else {
            println!("⏱  {} took {}ms", name, elapsed);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("spawn ") {
        let cmd = resolve_arg(rest.trim(), vars, oop);
        match std::process::Command::new("sh").arg("-c").arg(&cmd).spawn() {
            Ok(_) => {}
            Err(e) => println!("spawn failed: {}", e),
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("add_days ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let base = resolve_arg(&args[0], vars, oop);
                let days: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let fmt = if args.len() >= 3 {
                    resolve_arg(&args[2], vars, oop)
                } else {
                    "%Y-%m-%d".to_string()
                };
                let parsed = chrono::NaiveDate::parse_from_str(&base, "%Y-%m-%d")
                    .ok()
                    .map(|d| d + chrono::Duration::days(days));
                let result = parsed
                    .map(|d| d.format(&fmt).to_string())
                    .unwrap_or_else(|| "invalid".to_string());
                oop.string_vars.insert(var, result);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("diff_days ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let a = resolve_arg(&args[0], vars, oop);
                let b = resolve_arg(&args[1], vars, oop);
                let pa = chrono::NaiveDate::parse_from_str(&a, "%Y-%m-%d").ok();
                let pb = chrono::NaiveDate::parse_from_str(&b, "%Y-%m-%d").ok();
                let diff = match (pa, pb) {
                    (Some(a), Some(b)) => (b - a).num_days(),
                    _ => 0,
                };
                vars.insert(var, diff);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("table ") {
        let args = split_args(rest);
        if !args.is_empty() {
            let headers_list = resolve_arg(&args[0], vars, oop);
            let headers: Vec<String> =
                headers_list.split('|').map(|s| s.trim().to_string()).collect();
            let mut rows: Vec<Vec<String>> = Vec::new();
            for a in args.iter().skip(1) {
                let row_str = resolve_arg(a, vars, oop);
                let row: Vec<String> =
                    row_str.split('|').map(|s| s.trim().to_string()).collect();
                rows.push(row);
            }
            let mut widths: Vec<usize> = headers.iter().map(|h| h.chars().count()).collect();
            for row in &rows {
                for (i, cell) in row.iter().enumerate() {
                    if i < widths.len() {
                        widths[i] = widths[i].max(cell.chars().count());
                    }
                }
            }
            let sep = widths
                .iter()
                .map(|w| "─".repeat(w + 2))
                .collect::<Vec<_>>()
                .join("┼");
            println!("┌{}┐", sep.replace('┼', "┬"));
            let hrow = headers
                .iter()
                .enumerate()
                .map(|(i, h)| format!(" {:width$} ", h, width = widths[i]))
                .collect::<Vec<_>>()
                .join("│");
            println!("│{}│", hrow);
            println!("├{}┤", sep);
            for row in &rows {
                let line = row
                    .iter()
                    .enumerate()
                    .map(|(i, c)| {
                        format!(
                            " {:width$} ",
                            c,
                            width = widths.get(i).copied().unwrap_or(0)
                        )
                    })
                    .collect::<Vec<_>>()
                    .join("│");
                println!("│{}│", line);
            }
            println!("└{}┘", sep.replace('┼', "┴"));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sparkline ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get(name) {
            let nums: Vec<f64> = l.iter().filter_map(|x| x.parse::<f64>().ok()).collect();
            if !nums.is_empty() {
                let max = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
                let min = nums.iter().cloned().fold(f64::INFINITY, f64::min);
                let range = (max - min).max(1.0);
                let chars = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
                let spark: String = nums
                    .iter()
                    .map(|n| {
                        let idx = (((n - min) / range) * 7.0).round() as usize;
                        chars[idx.min(7)]
                    })
                    .collect();
                println!("{}", spark);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("barchart ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get(name) {
            let nums: Vec<f64> = l.iter().filter_map(|x| x.parse::<f64>().ok()).collect();
            if !nums.is_empty() {
                let max = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
                let bar_max: usize = 30;
                for (i, n) in nums.iter().enumerate() {
                    let filled = ((n / max) * bar_max as f64).round() as usize;
                    let bar: String = "█".repeat(filled.min(bar_max));
                    println!("  [{:>3}] {} {}", i, bar, n);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("watchfile ") {
        let parts: Vec<&str> = rest.splitn(2, char::is_whitespace).collect();
        if parts.len() < 2 {
            println!("watchfile syntax: watchfile <path> <func_name>");
            return true;
        }
        let path = expand_path(&resolve_arg(parts[0].trim(), vars, oop));
        let func_name = parts[1].trim().to_string();
        if !oop.functions.contains_key(&func_name) {
            println!("watchfile: function '{}' not found", func_name);
            return true;
        }
        println!("Watching {} (press Ctrl-C to stop)...", path.display());
        use notify::{Event, RecursiveMode, Watcher};
        let (tx, rx) = std::sync::mpsc::channel();
        let mut watcher = match notify::recommended_watcher(move |res| {
            let _ = tx.send(res);
        }) {
            Ok(w) => w,
            Err(e) => {
                println!("watchfile: {}", e);
                return true;
            }
        };
        if let Err(e) = watcher.watch(&path, RecursiveMode::NonRecursive) {
            println!("watchfile: {}", e);
            return true;
        }
        loop {
            match rx.recv_timeout(Duration::from_secs(1)) {
                Ok(Ok(Event { .. })) => {
                    let func = oop.functions.get(&func_name).cloned();
                    if let Some(f) = func {
                        for body_line in &f.body {
                            if !execute(body_line, vars, server_cfg, oop) {
                                return false;
                            }
                        }
                    }
                }
                Ok(Err(e)) => {
                    println!("watch error: {}", e);
                    break;
                }
                Err(std::sync::mpsc::RecvTimeoutError::Timeout) => continue,
                Err(_) => break,
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("spin ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        let frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
        for _ in 0..2 {
            for f in &frames {
                print!("\r{} {}    ", f, msg);
                let _ = io::stdout().flush();
                thread::sleep(Duration::from_millis(80));
            }
        }
        print!("\r✓ {}    \n", msg);
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(rest) = line.strip_prefix("format ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.is_empty() {
                return true;
            }
            let raw_tmpl = args[0].trim();
            let template: String = if raw_tmpl.starts_with('"')
                && raw_tmpl.ends_with('"')
                && raw_tmpl.len() >= 2
            {
                unescape_string(&raw_tmpl[1..raw_tmpl.len() - 1])
            } else {
                raw_tmpl.to_string()
            };
            let values: Vec<String> =
                args.iter().skip(1).map(|a| resolve_arg(a, vars, oop)).collect();
            let mut out = String::with_capacity(template.len());
            let bytes = template.as_bytes();
            let mut i = 0;
            while i < bytes.len() {
                if bytes[i] == b'{' {
                    if let Some(end) = template[i + 1..].find('}') {
                        let key = template[i + 1..i + 1 + end].trim();
                        if let Ok(idx) = key.parse::<usize>() {
                            if let Some(v) = values.get(idx) {
                                out.push_str(v);
                                i = i + 1 + end + 1;
                                continue;
                            }
                        }
                    }
                }
                let nb = next_char_boundary(&template, i);
                out.push_str(&template[i..nb]);
                i = nb;
            }
            oop.string_vars.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("concat ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let mut buf = String::new();
            for a in &args {
                buf.push_str(&resolve_arg(a, vars, oop));
            }
            oop.string_vars.insert(var, buf);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("split ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let sep = resolve_arg(&args[1], vars, oop);
                let items: Vec<String> = if sep.is_empty() {
                    s.chars().map(|c| c.to_string()).collect()
                } else {
                    s.split(&sep).map(|x| x.to_string()).collect()
                };
                oop.lists.insert(var, items);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("list ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let raw = parts[1].trim();
            let inner = if raw.starts_with('[') && raw.ends_with(']') && raw.len() >= 2 {
                &raw[1..raw.len() - 1]
            } else {
                raw
            };
            let items: Vec<String> = if inner.trim().is_empty() {
                Vec::new()
            } else {
                inner
                    .split(',')
                    .map(|x| resolve_arg(x.trim(), vars, oop))
                    .collect()
            };
            oop.lists.insert(var, items);
        }
        return true;
    }

    // ===== v2.0: FUNCTIONAL LIST OPS =====
    //
    //   map <list> <fn_name> -> <result_list>
    //     Calls fn_name(item) for each item; `result` from the call goes
    //     into <result_list> in order.
    //
    //   filter <list> <predicate_fn> -> <result_list>
    //     Calls predicate_fn(item); if `result` is 1 (or non-empty non-zero),
    //     keeps the item.
    //
    //   reduce <list> <fn_name> <initial> -> <result_var>
    //     acc = initial; for each item: acc = fn_name(acc, item). Store
    //     final acc.
    if let Some(rest) = line.strip_prefix("map ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let head_toks: Vec<&str> = parts[0].split_whitespace().collect();
        if head_toks.len() >= 2 && result_var.is_some() {
            let list_name = head_toks[0];
            let fn_name = head_toks[1];
            let items: Vec<String> = oop.lists.get(list_name).cloned().unwrap_or_default();
            let mut out: Vec<String> = Vec::with_capacity(items.len());
            for item in items {
                let val = call_named_func_1arg(fn_name, &item, vars, server_cfg, oop);
                out.push(val.unwrap_or_default());
            }
            oop.lists.insert(result_var.unwrap(), out);
        }
        return true;
    }
    if let Some(rest) = line.strip_prefix("filter ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let head_toks: Vec<&str> = parts[0].split_whitespace().collect();
        if head_toks.len() >= 2 && result_var.is_some() {
            let list_name = head_toks[0];
            let fn_name = head_toks[1];
            let items: Vec<String> = oop.lists.get(list_name).cloned().unwrap_or_default();
            let mut out: Vec<String> = Vec::new();
            for item in items {
                let val = call_named_func_1arg(fn_name, &item, vars, server_cfg, oop);
                let keep = match val.as_deref() {
                    Some("0") | Some("") | Some("false") | None => false,
                    _ => true,
                };
                if keep { out.push(item); }
            }
            oop.lists.insert(result_var.unwrap(), out);
        }
        return true;
    }
    if let Some(rest) = line.strip_prefix("reduce ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let head_toks: Vec<&str> = parts[0].split_whitespace().collect();
        if head_toks.len() >= 3 && result_var.is_some() {
            let list_name = head_toks[0];
            let fn_name = head_toks[1];
            let init = resolve_arg(head_toks[2], vars, oop);
            let items: Vec<String> = oop.lists.get(list_name).cloned().unwrap_or_default();
            let mut acc = init;
            for item in items {
                let val = call_named_func_2arg(fn_name, &acc, &item, vars, server_cfg, oop);
                if let Some(v) = val { acc = v; }
            }
            apply_return(vars, oop, result_var, Some(acc));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("push ") {
        let tokens: Vec<&str> = rest.splitn(2, char::is_whitespace).collect();
        if tokens.len() == 2 {
            let name = tokens[0].trim().to_string();
            let value = resolve_arg(tokens[1].trim(), vars, oop);
            if let Some(l) = oop.lists.get_mut(&name) {
                l.push(value);
            } else {
                println!("push: list '{}' not found", name);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("pop ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let popped = match oop.lists.get_mut(name) {
            Some(l) => l.pop(),
            None => {
                println!("pop: list '{}' not found", name);
                return true;
            }
        };
        if let Some(v) = popped {
            apply_return(vars, oop, result_var, Some(v));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lget ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let lhs = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let toks: Vec<&str> = lhs.split_whitespace().collect();
        if toks.len() >= 2 {
            let name = toks[0];
            let idx: usize = resolve_arg(toks[1], vars, oop).parse().unwrap_or(0);
            match oop.lists.get(name).and_then(|l| l.get(idx).cloned()) {
                Some(v) => apply_return(vars, oop, result_var, Some(v)),
                None => println!("lget: index {} out of range on '{}'", idx, name),
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lset ") {
        let toks: Vec<&str> = rest.splitn(3, char::is_whitespace).collect();
        if toks.len() == 3 {
            let name = toks[0].trim();
            let idx: usize = resolve_arg(toks[1].trim(), vars, oop).parse().unwrap_or(0);
            let value = resolve_arg(toks[2].trim(), vars, oop);
            if let Some(l) = oop.lists.get_mut(name) {
                if idx < l.len() {
                    l[idx] = value;
                } else {
                    println!("lset: index {} out of range on '{}'", idx, name);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lsize ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let n = oop.lists.get(name).map(|l| l.len() as i64).unwrap_or(0);
        apply_return(vars, oop, result_var, Some(n.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("lclear ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get_mut(name) {
            l.clear();
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcontains ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let toks: Vec<&str> = parts[0].splitn(2, char::is_whitespace).collect();
        if toks.len() == 2 {
            let name = toks[0].trim();
            let needle = resolve_arg(toks[1].trim(), vars, oop);
            let found = oop
                .lists
                .get(name)
                .map(|l| l.iter().any(|v| v == &needle))
                .unwrap_or(false);
            apply_return(
                vars,
                oop,
                result_var,
                Some(if found { "1" } else { "0" }.to_string()),
            );
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dict ") {
        let name = rest.trim().to_string();
        oop.dicts.insert(name, HashMap::new());
        return true;
    }

    if let Some(rest) = line.strip_prefix("dset ") {
        let toks: Vec<&str> = rest.splitn(3, char::is_whitespace).collect();
        if toks.len() == 3 {
            let name = toks[0].trim();
            let key = resolve_arg(toks[1].trim(), vars, oop);
            let value = resolve_arg(toks[2].trim(), vars, oop);
            if !oop.dicts.contains_key(name) {
                oop.dicts.insert(name.to_string(), HashMap::new());
            }
            oop.dicts.get_mut(name).unwrap().insert(key, value);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dget ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let toks: Vec<&str> = parts[0].splitn(2, char::is_whitespace).collect();
        if toks.len() == 2 {
            let name = toks[0].trim();
            let key = resolve_arg(toks[1].trim(), vars, oop);
            let v = oop.dicts.get(name).and_then(|d| d.get(&key)).cloned();
            apply_return(vars, oop, result_var, v);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dhas ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let toks: Vec<&str> = parts[0].splitn(2, char::is_whitespace).collect();
        if toks.len() == 2 {
            let name = toks[0].trim();
            let key = resolve_arg(toks[1].trim(), vars, oop);
            let found = oop
                .dicts
                .get(name)
                .map(|d| d.contains_key(&key))
                .unwrap_or(false);
            apply_return(
                vars,
                oop,
                result_var,
                Some(if found { "1" } else { "0" }.to_string()),
            );
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ddel ") {
        let toks: Vec<&str> = rest.splitn(2, char::is_whitespace).collect();
        if toks.len() == 2 {
            let name = toks[0].trim();
            let key = resolve_arg(toks[1].trim(), vars, oop);
            if let Some(d) = oop.dicts.get_mut(name) {
                d.remove(&key);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dsize ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let n = oop.dicts.get(name).map(|d| d.len() as i64).unwrap_or(0);
        apply_return(vars, oop, result_var, Some(n.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("dkeys ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        if let Some(target) = result_var {
            let mut keys: Vec<String> = oop
                .dicts
                .get(name)
                .map(|d| d.keys().cloned().collect())
                .unwrap_or_default();
            keys.sort();
            oop.lists.insert(target, keys);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("now ") {
        let var = rest.trim().to_string();
        let n = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| d.as_secs() as i64)
            .unwrap_or(0);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("datefmt ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let fmt = resolve_arg(parts[1].trim(), vars, oop);
            let now = chrono::Local::now();
            oop.string_vars
                .insert(var, now.format(&fmt).to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sleep_ms ") {
        let ms: u64 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(0);
        thread::sleep(Duration::from_millis(ms));
        return true;
    }

    if let Some(rest) = line.strip_prefix("mkdir ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        match fs::create_dir_all(&path) {
            Ok(_) => {}
            Err(e) => {
                oop.error_message = Some(format!("mkdir: {}", e));
                println!("mkdir failed: {}", e);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("rmdir ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        let _ = fs::remove_dir_all(&path);
        return true;
    }

    if let Some(rest) = line.strip_prefix("rm ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        let _ = fs::remove_file(&path);
        return true;
    }

    if let Some(rest) = line.strip_prefix("exists ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let path = expand_path(&resolve_arg(parts[0].trim(), vars, oop));
        let exists = path.exists();
        apply_return(
            vars,
            oop,
            result_var,
            Some(if exists { "1" } else { "0" }.into()),
        );
        return true;
    }

    if let Some(rest) = line.strip_prefix("listdir ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let path = expand_path(&resolve_arg(parts[0].trim(), vars, oop));
        let mut entries: Vec<String> = match fs::read_dir(&path) {
            Ok(rd) => rd
                .filter_map(|e| e.ok())
                .map(|e| e.file_name().to_string_lossy().to_string())
                .collect(),
            Err(e) => {
                oop.error_message = Some(format!("listdir: {}", e));
                Vec::new()
            }
        };
        entries.sort();
        if let Some(v) = result_var {
            oop.lists.insert(v, entries);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("copy ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let from = expand_path(&resolve_arg(&args[0], vars, oop));
            let to = expand_path(&resolve_arg(&args[1], vars, oop));
            if let Err(e) = fs::copy(&from, &to) {
                oop.error_message = Some(format!("copy: {}", e));
                println!("copy failed: {}", e);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("move ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let from = expand_path(&resolve_arg(&args[0], vars, oop));
            let to = expand_path(&resolve_arg(&args[1], vars, oop));
            if let Err(e) = fs::rename(&from, &to) {
                oop.error_message = Some(format!("move: {}", e));
                println!("move failed: {}", e);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("md5 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let digest = md5::compute(s.as_bytes());
            oop.string_vars.insert(var, format!("{:x}", digest));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sha256 ") {
        use sha2::{Digest, Sha256};
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let mut hasher = Sha256::new();
            hasher.update(s.as_bytes());
            let result = hasher.finalize();
            oop.string_vars.insert(var, format!("{:x}", result));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("base64_encode ") {
        use base64::Engine;
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(
                var,
                base64::engine::general_purpose::STANDARD.encode(s.as_bytes()),
            );
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("base64_decode ") {
        use base64::Engine;
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            match base64::engine::general_purpose::STANDARD.decode(s.as_bytes()) {
                Ok(bytes) => oop
                    .string_vars
                    .insert(var, String::from_utf8_lossy(&bytes).to_string()),
                Err(e) => {
                    oop.error_message = Some(format!("base64_decode: {}", e));
                    None
                }
            };
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("regex_match ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let pat = resolve_arg(&args[0], vars, oop);
                let text = resolve_arg(&args[1], vars, oop);
                match regex::Regex::new(&pat) {
                    Ok(re) => {
                        vars.insert(var, if re.is_match(&text) { 1 } else { 0 });
                    }
                    Err(e) => {
                        oop.error_message = Some(format!("regex: {}", e));
                        println!("regex_match: {}", e);
                    }
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("regex_replace ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 3 {
                let pat = resolve_arg(&args[0], vars, oop);
                let text = resolve_arg(&args[1], vars, oop);
                let repl = resolve_arg(&args[2], vars, oop);
                match regex::Regex::new(&pat) {
                    Ok(re) => {
                        oop.string_vars
                            .insert(var, re.replace_all(&text, repl.as_str()).to_string());
                    }
                    Err(e) => {
                        oop.error_message = Some(format!("regex: {}", e));
                    }
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("http_get ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let url = resolve_arg(parts[0].trim(), vars, oop);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        match reqwest::blocking::get(&url) {
            Ok(resp) => match resp.text() {
                Ok(body) => apply_return(vars, oop, result_var, Some(body)),
                Err(e) => {
                    oop.error_message = Some(format!("http_get: {}", e));
                    println!("http_get failed: {}", e);
                }
            },
            Err(e) => {
                oop.error_message = Some(format!("http_get: {}", e));
                println!("http_get failed: {}", e);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("http_post ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let args = split_args(parts[0]);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        if args.len() >= 2 {
            let url = resolve_arg(&args[0], vars, oop);
            let body = resolve_arg(&args[1], vars, oop);
            let client = reqwest::blocking::Client::new();
            match client.post(&url).body(body).send() {
                Ok(resp) => match resp.text() {
                    Ok(body) => apply_return(vars, oop, result_var, Some(body)),
                    Err(e) => {
                        oop.error_message = Some(format!("http_post: {}", e));
                    }
                },
                Err(e) => {
                    oop.error_message = Some(format!("http_post: {}", e));
                    println!("http_post failed: {}", e);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("json_parse ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let raw = resolve_arg(parts[0].trim(), vars, oop);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        if let Some(target) = result_var {
            match serde_json::from_str::<serde_json::Value>(&raw) {
                Ok(v) => {
                    if let serde_json::Value::Object(map) = v {
                        let mut d: HashMap<String, String> = HashMap::new();
                        for (k, val) in map {
                            d.insert(k, json_to_str(&val));
                        }
                        oop.dicts.insert(target, d);
                    } else if let serde_json::Value::Array(arr) = v {
                        let items: Vec<String> = arr.iter().map(json_to_str).collect();
                        oop.lists.insert(target, items);
                    } else {
                        oop.string_vars.insert(target, json_to_str(&v));
                    }
                }
                Err(e) => {
                    oop.error_message = Some(format!("json_parse: {}", e));
                    println!("json_parse failed: {}", e);
                }
            }
        }
        return true;
    }

    if line == "beep" {
        print!("\x07");
        let _ = io::stdout().flush();
        return true;
    }

    // theothecat — easter egg. Opens the base64-embedded JPEG directly in a
    // browser via a `data:` URL. xdg-open blocks data: URLs for security, so
    // we call known browsers (firefox/chrome/chromium) directly instead.
    if line == "theothecat" {
        let data_url = format!("data:image/jpeg;base64,{}", THEOTHECAT_B64.trim());
        use std::process::{Command, Stdio};

        // Browser binaries to try, in order. Firefox accepts data: URLs as
        // command-line args; Chrome/Chromium do too. xdg-open is last because
        // its gio backend filters out data: URLs.
        #[cfg(target_os = "linux")]
        let browsers: &[&str] = &[
            "firefox", "firefox-esr", "librewolf",
            "chromium", "chromium-browser",
            "google-chrome", "google-chrome-stable",
            "brave-browser", "vivaldi", "opera",
            "xdg-open",
        ];
        #[cfg(target_os = "macos")]
        let browsers: &[&str] = &["open"];
        #[cfg(target_os = "windows")]
        let browsers: &[&str] = &["cmd"];

        let mut opened: Option<&str> = None;
        for bin in browsers {
            #[cfg(target_os = "windows")]
            let args: Vec<&str> = vec!["/C", "start", "", &data_url];
            #[cfg(target_os = "macos")]
            let args: Vec<&str> = vec![&data_url];
            #[cfg(target_os = "linux")]
            let args: Vec<&str> = vec![&data_url];

            let spawn = Command::new(bin)
                .args(&args)
                .stdin(Stdio::null())
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .spawn();
            if spawn.is_ok() {
                opened = Some(bin);
                break;
            }
        }

        match opened {
            Some(b) => {
                println!("\x1b[36m🐈  Theo says hi!\x1b[0m  (opened in \x1b[2m{}\x1b[0m)", b);
            }
            None => {
                println!("\x1b[33mtheothecat: no browser found.\x1b[0m  Here's the URL:");
                println!();
                println!("{}", data_url);
            }
        }
        return true;
    }

    // tempdir -> var   Returns the OS temp directory (/tmp on Linux, %TEMP% on Windows)
    if let Some(rest) = line.strip_prefix("tempdir ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string())
            .unwrap_or_else(|| parts[0].trim().to_string());
        let p = std::env::temp_dir().to_string_lossy().to_string();
        apply_return(vars, oop, Some(var), Some(p));
        return true;
    }

    // tempfile "basename" -> var   Returns a path inside tempdir
    if let Some(rest) = line.strip_prefix("tempfile ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let base = resolve_arg(parts[0].trim(), vars, oop);
        let p = std::env::temp_dir().join(&base).to_string_lossy().to_string();
        apply_return(vars, oop, var, Some(p));
        return true;
    }

    if let Some(rest) = line.strip_prefix("play ") {
        let file = resolve_arg(rest.trim(), vars, oop);
        #[cfg(target_os = "macos")]
        {
            let _ = Command::new("afplay").arg(&file).spawn();
        }
        #[cfg(target_os = "windows")]
        {
            // PowerShell SoundPlayer plays .wav files synchronously; spawn
            // to avoid blocking the script.
            let ps = format!("(New-Object Media.SoundPlayer '{}').Play()", file.replace('\'', "''"));
            let _ = Command::new("powershell")
                .args(["-NoProfile", "-Command", &ps])
                .spawn();
        }
        #[cfg(all(unix, not(target_os = "macos")))]
        {
            let cmd = format!("aplay -q {} 2>/dev/null || paplay {} 2>/dev/null", file, file);
            let _ = Command::new("sh").arg("-c").arg(cmd).spawn();
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("banner ") {
        let text = resolve_arg(rest.trim(), vars, oop);
        print_banner(&text);
        return true;
    }

    if let Some(rest) = line.strip_prefix("box ") {
        let args = split_args(rest);
        if args.len() >= 1 {
            let title = resolve_arg(&args[0], vars, oop);
            let content = if args.len() >= 2 {
                resolve_arg(&args[1], vars, oop)
            } else {
                String::new()
            };
            print_box(&title, &content);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("progress ") {
        let args = split_args(rest);
        if args.len() >= 2 {
            let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
            let total: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1).max(1);
            let label = if args.len() >= 3 {
                resolve_arg(&args[2], vars, oop)
            } else {
                String::new()
            };
            print_progress(n, total, &label);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ljoin ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 1 {
                let name = args[0].trim();
                let sep = if args.len() >= 2 {
                    resolve_arg(&args[1], vars, oop)
                } else {
                    String::from(",")
                };
                let joined = oop
                    .lists
                    .get(name)
                    .map(|l| l.join(&sep))
                    .unwrap_or_default();
                oop.string_vars.insert(var, joined);
            }
        }
        return true;
    }

    if let Some(t) = line.strip_prefix("reverse ") {
        let s = interpolate(strip_outer_quotes(t), vars, oop);
        println!("{}", s.chars().rev().collect::<String>());
        return true;
    }

    if let Some(t) = line.strip_prefix("uppercase ") {
        let s = interpolate(strip_outer_quotes(t), vars, oop);
        println!("{}", s.to_uppercase());
        return true;
    }

    if let Some(expr) = line.strip_prefix("calc ") {
        match fasteval::ez_eval(expr, &mut math_ns()) {
            Ok(result) => println!("Result: {}", result),
            Err(_) => println!("Invalid expression"),
        }
        return true;
    }

    if line.starts_with("rand ") {
        let parts: Vec<&str> = line[5..].split_whitespace().collect();
        if parts.len() == 3 {
            let var_name = parts[0];
            // Resolve so variables, consts, and {expr} all work as min/max
            let min_val = parse_i64_loose(&resolve_arg(parts[1], vars, oop));
            let max_val = parse_i64_loose(&resolve_arg(parts[2], vars, oop));
            let (lo, hi) = if min_val <= max_val { (min_val, max_val) } else { (max_val, min_val) };
            let value = rand::thread_rng().gen_range(lo..=hi);
            vars.insert(var_name.into(), value);
        }
        return true;
    }

    if line.starts_with("sleep ") {
        let secs: u64 = line[6..].trim().parse().unwrap_or(1);
        thread::sleep(Duration::from_secs(secs));
        return true;
    }

    if line == "clear" {
        print!("\x1B[2J\x1B[1;1H");
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(rest) = line.strip_prefix("color ") {
        let code = match rest.trim() {
            "reset" | "off" => "\x1b[0m",
            "black" => "\x1b[30m",
            "red" => "\x1b[31m",
            "green" => "\x1b[32m",
            "yellow" => "\x1b[33m",
            "blue" => "\x1b[34m",
            "magenta" | "purple" => "\x1b[35m",
            "cyan" => "\x1b[36m",
            "white" => "\x1b[37m",
            "bold" => "\x1b[1m",
            "dim" => "\x1b[2m",
            "italic" => "\x1b[3m",
            "underline" => "\x1b[4m",
            "bg_red" => "\x1b[41m",
            "bg_green" => "\x1b[42m",
            "bg_yellow" => "\x1b[43m",
            "bg_blue" => "\x1b[44m",
            _ => "",
        };
        print!("{}", code);
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(cmd) = line.strip_prefix("exec ") {
        let resolved = interpolate(strip_outer_quotes(cmd), vars, oop);
        let _ = Command::new("sh").arg("-c").arg(resolved).status();
        return true;
    }

    if line == "sinorules" {
        println!("The chicken lord rules over us all");
        return true;
    }

    if line == "ayaanrules" {
        println!("Ayaan, the creator, watches over this code.");
        return true;
    }

    if line == "chickenwins" {
        println!("The chicken lord has been overthrown!");
        println!("...wait, who put me in charge now?");
        return true;
    }

    if line == "bringback" {
        println!("Recalling the chicken lord from the void...");
        println!("...it shall rule again. (sinorules has been restored)");
        return true;
    }

    if line == "xyzzy" {
        println!("Nothing happens.");
        return true;
    }

    if line == "theanswer" {
        println!("42");
        println!("(What was the question?)");
        return true;
    }

    if line == "coffee" {
        println!("    )  )  )");
        println!("   ( ( (");
        println!("  .________.");
        println!("  |        |]");
        println!("  \\        /");
        println!("   `------'");
        println!("  enjoy your coffee");
        return true;
    }

    if line == "konami" {
        println!("UP UP DOWN DOWN LEFT RIGHT LEFT RIGHT B A");
        println!("30 extra lives granted. (purely cosmetic)");
        return true;
    }

    if line == "selfdestruct" {
        println!("Self-destruct sequence initiated...");
        println!("3...");
        println!("2...");
        println!("1...");
        println!("...psych. You're fine.");
        return true;
    }

    if line == "tea" {
        println!("Have a nice cuppa.");
        return true;
    }

    if line == "matrix" {
        println!("Wake up, Neo...");
        println!("The Matrix has you...");
        println!("Follow the white rabbit.");
        return true;
    }

    if line == "eastereggs" {
        println!("There are no easter eggs here. Move along.");
        return true;
    }

    if line == "fortune" {
        let lines = [
            "The chicken lord smiles upon you today.",
            "A bug in hand is worth two in production.",
            "Today is a good day to write tests.",
            "You will refactor something you wrote 6 months ago.",
            "Beware: today, off-by-one errors lurk.",
            "Your next deploy will be smooth. Probably.",
            "When in doubt, println! it out.",
            "The Matrix says: there is no spoon, only nested loops.",
        ];
        let mut rng = rand::thread_rng();
        let pick = rand::Rng::gen_range(&mut rng, 0..lines.len());
        println!("🥠 {}", lines[pick]);
        return true;
    }

    if line == "rickroll" {
        println!("Never gonna give you up");
        println!("Never gonna let you down");
        println!("Never gonna run around and desert you");
        return true;
    }

    if line == "hack" {
        for i in 0..15 {
            let mut rng = rand::thread_rng();
            let chars: String = (0..40)
                .map(|_| {
                    let n: u32 = rand::Rng::gen_range(&mut rng, 33..127);
                    char::from_u32(n).unwrap()
                })
                .collect();
            println!("\x1b[32m[{:02}] {}\x1b[0m", i, chars);
            thread::sleep(Duration::from_millis(50));
        }
        println!("\x1b[32mACCESS GRANTED\x1b[0m");
        return true;
    }

    if line == "ayaaniscool" {
        println!("Yes, yes I am.");
        return true;
    }

    if line == "EmperorPenguin" {
        println!("Emperor Penguins are apart of the tallest penguin");
        return true;
    }

    macro_rules! unary_str_to_str {
        ($name:expr, $fn:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($name, " ")) {
                let parts: Vec<&str> = rest.splitn(2, '=').collect();
                if parts.len() == 2 {
                    let var = parts[0].trim().to_string();
                    let s = resolve_arg(parts[1].trim(), vars, oop);
                    oop.string_vars.insert(var, $fn(s));
                }
                return true;
            }
        };
    }

    macro_rules! unary_str_to_int {
        ($name:expr, $fn:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($name, " ")) {
                let parts: Vec<&str> = rest.splitn(2, '=').collect();
                if parts.len() == 2 {
                    let var = parts[0].trim().to_string();
                    let s = resolve_arg(parts[1].trim(), vars, oop);
                    vars.insert(var, $fn(s));
                }
                return true;
            }
        };
    }

    macro_rules! unary_n_to_n {
        ($name:expr, $fn:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($name, " ")) {
                let parts: Vec<&str> = rest.splitn(2, '=').collect();
                if parts.len() == 2 {
                    let var = parts[0].trim().to_string();
                    let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
                    let v: f64 = $fn(n);
                    if v.fract() == 0.0 && v.is_finite() && v.abs() < 1e18 {
                        vars.insert(var, v as i64);
                    } else {
                        oop.string_vars.insert(var, v.to_string());
                    }
                }
                return true;
            }
        };
    }

    unary_n_to_n!("c_to_f", |c: f64| c * 9.0 / 5.0 + 32.0);
    unary_n_to_n!("f_to_c", |f: f64| (f - 32.0) * 5.0 / 9.0);
    unary_n_to_n!("c_to_k", |c: f64| c + 273.15);
    unary_n_to_n!("k_to_c", |k: f64| k - 273.15);
    unary_n_to_n!("f_to_k", |f: f64| (f - 32.0) * 5.0 / 9.0 + 273.15);
    unary_n_to_n!("k_to_f", |k: f64| (k - 273.15) * 9.0 / 5.0 + 32.0);
    unary_n_to_n!("km_to_mi", |k: f64| k * 0.621371);
    unary_n_to_n!("mi_to_km", |m: f64| m * 1.609344);
    unary_n_to_n!("m_to_ft", |m: f64| m * 3.28084);
    unary_n_to_n!("ft_to_m", |f: f64| f / 3.28084);
    unary_n_to_n!("cm_to_in", |c: f64| c / 2.54);
    unary_n_to_n!("in_to_cm", |i: f64| i * 2.54);
    unary_n_to_n!("kg_to_lb", |k: f64| k * 2.20462);
    unary_n_to_n!("lb_to_kg", |l: f64| l / 2.20462);
    unary_n_to_n!("g_to_oz", |g: f64| g * 0.035274);
    unary_n_to_n!("oz_to_g", |o: f64| o / 0.035274);
    unary_n_to_n!("l_to_gal", |l: f64| l * 0.264172);
    unary_n_to_n!("gal_to_l", |g: f64| g / 0.264172);
    unary_n_to_n!("ml_to_floz", |m: f64| m * 0.033814);
    unary_n_to_n!("floz_to_ml", |f: f64| f / 0.033814);
    unary_n_to_n!("mph_to_kmh", |m: f64| m * 1.609344);
    unary_n_to_n!("kmh_to_mph", |k: f64| k / 1.609344);
    unary_n_to_n!("knots_to_kmh", |k: f64| k * 1.852);
    unary_n_to_n!("kmh_to_knots", |k: f64| k / 1.852);
    unary_n_to_n!("sec_to_min", |s: f64| s / 60.0);
    unary_n_to_n!("min_to_sec", |m: f64| m * 60.0);
    unary_n_to_n!("min_to_hr", |m: f64| m / 60.0);
    unary_n_to_n!("hr_to_min", |h: f64| h * 60.0);
    unary_n_to_n!("hr_to_sec", |h: f64| h * 3600.0);
    unary_n_to_n!("sec_to_hr", |s: f64| s / 3600.0);
    unary_n_to_n!("days_to_hr", |d: f64| d * 24.0);
    unary_n_to_n!("hr_to_days", |h: f64| h / 24.0);
    unary_n_to_n!("bytes_to_kb", |b: f64| b / 1024.0);
    unary_n_to_n!("kb_to_mb", |k: f64| k / 1024.0);
    unary_n_to_n!("mb_to_gb", |m: f64| m / 1024.0);
    unary_n_to_n!("gb_to_tb", |g: f64| g / 1024.0);
    unary_n_to_n!("bytes_to_mb", |b: f64| b / 1048576.0);
    unary_n_to_n!("bytes_to_gb", |b: f64| b / 1073741824.0);
    unary_n_to_n!("square", |n: f64| n * n);
    unary_n_to_n!("cube", |n: f64| n * n * n);
    unary_n_to_n!("negate", |n: f64| -n);
    unary_n_to_n!("double", |n: f64| n * 2.0);
    unary_n_to_n!("half", |n: f64| n / 2.0);
    unary_n_to_n!("triple", |n: f64| n * 3.0);
    unary_n_to_n!("third", |n: f64| n / 3.0);
    unary_n_to_n!("percent", |n: f64| n / 100.0);
    unary_n_to_n!("inverse_percent", |n: f64| n * 100.0);
    unary_n_to_n!("invert", |n: f64| 1.0 / n);

    unary_str_to_str!("swap_case", |s: String| s.chars().map(|c| if c.is_uppercase() { c.to_lowercase().next().unwrap_or(c) } else if c.is_lowercase() { c.to_uppercase().next().unwrap_or(c) } else { c }).collect());
    unary_str_to_str!("snake_to_camel", |s: String| {
        let mut out = String::new(); let mut upper = false;
        for c in s.chars() { if c == '_' { upper = true; } else if upper { out.push(c.to_uppercase().next().unwrap_or(c)); upper = false; } else { out.push(c); } }
        out
    });
    unary_str_to_str!("camel_to_snake", |s: String| {
        let mut out = String::new();
        for (i, c) in s.chars().enumerate() { if c.is_uppercase() && i > 0 { out.push('_'); } out.push(c.to_lowercase().next().unwrap_or(c)); }
        out
    });
    unary_str_to_str!("kebab_to_snake", |s: String| s.replace('-', "_"));
    unary_str_to_str!("snake_to_kebab", |s: String| s.replace('_', "-"));
    unary_str_to_str!("kebab_to_camel", |s: String| {
        let mut out = String::new(); let mut upper = false;
        for c in s.chars() { if c == '-' { upper = true; } else if upper { out.push(c.to_uppercase().next().unwrap_or(c)); upper = false; } else { out.push(c); } }
        out
    });
    unary_str_to_str!("slugify", |s: String| s.to_lowercase().chars().map(|c| if c.is_alphanumeric() { c } else { '-' }).collect::<String>().split('-').filter(|s| !s.is_empty()).collect::<Vec<&str>>().join("-"));
    unary_str_to_str!("reverse_words", |s: String| s.split_whitespace().rev().collect::<Vec<&str>>().join(" "));
    unary_str_to_str!("normalize_ws", |s: String| s.split_whitespace().collect::<Vec<&str>>().join(" "));
    unary_str_to_str!("only_letters", |s: String| s.chars().filter(|c| c.is_alphabetic()).collect());
    unary_str_to_str!("only_digits", |s: String| s.chars().filter(|c| c.is_ascii_digit()).collect());
    unary_str_to_str!("only_alnum", |s: String| s.chars().filter(|c| c.is_alphanumeric()).collect());
    unary_str_to_str!("remove_spaces", |s: String| s.chars().filter(|c| !c.is_whitespace()).collect());
    unary_str_to_str!("collapse_spaces", |s: String| {
        let mut out = String::new(); let mut last_ws = false;
        for c in s.chars() { if c.is_whitespace() { if !last_ws { out.push(' '); last_ws = true; } } else { out.push(c); last_ws = false; } }
        out
    });
    unary_str_to_str!("chomp", |s: String| s.trim_end_matches(&['\n', '\r'] as &[char]).to_string());
    unary_str_to_str!("chop", |s: String| { let mut c = s; c.pop(); c });
    unary_str_to_str!("escape_quotes", |s: String| s.replace('"', "\\\""));
    unary_str_to_str!("unescape_quotes", |s: String| s.replace("\\\"", "\""));
    unary_str_to_str!("repeat_chars", |s: String| s.chars().flat_map(|c| std::iter::repeat(c).take(2)).collect());
    unary_str_to_str!("first_letter", |s: String| s.chars().next().map(|c| c.to_string()).unwrap_or_default());
    unary_str_to_str!("last_letter", |s: String| s.chars().last().map(|c| c.to_string()).unwrap_or_default());
    unary_str_to_str!("acronym", |s: String| s.split_whitespace().filter_map(|w| w.chars().next()).map(|c| c.to_uppercase().next().unwrap_or(c)).collect());
    unary_str_to_str!("initials", |s: String| s.split_whitespace().filter_map(|w| w.chars().next()).map(|c| { let mut t = c.to_uppercase().to_string(); t.push('.'); t }).collect::<Vec<_>>().join(""));

    unary_str_to_int!("char_count", |s: String| s.chars().count() as i64);
    unary_str_to_int!("byte_count", |s: String| s.len() as i64);
    unary_str_to_int!("line_count", |s: String| s.lines().count() as i64);
    unary_str_to_int!("vowel_count", |s: String| s.chars().filter(|c| "aeiouAEIOU".contains(*c)).count() as i64);
    unary_str_to_int!("consonant_count", |s: String| s.chars().filter(|c| c.is_alphabetic() && !"aeiouAEIOU".contains(*c)).count() as i64);
    unary_str_to_int!("digit_count", |s: String| s.chars().filter(|c| c.is_ascii_digit()).count() as i64);
    unary_str_to_int!("space_count", |s: String| s.chars().filter(|c| c.is_whitespace()).count() as i64);
    unary_str_to_int!("uppercase_count", |s: String| s.chars().filter(|c| c.is_uppercase()).count() as i64);
    unary_str_to_int!("lowercase_count", |s: String| s.chars().filter(|c| c.is_lowercase()).count() as i64);

    if let Some(rest) = line.strip_prefix("pad_left ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let w: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let fill = if args.len() >= 3 { resolve_arg(&args[2], vars, oop).chars().next().unwrap_or(' ') } else { ' ' };
                let pad = w.saturating_sub(s.chars().count());
                oop.string_vars.insert(var, format!("{}{}", fill.to_string().repeat(pad), s));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("truncate ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let w: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let out: String = if s.chars().count() <= w { s } else { s.chars().take(w).collect::<String>() + "..." };
                oop.string_vars.insert(var, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("words ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let words: Vec<String> = s.split_whitespace().map(String::from).collect();
            oop.lists.insert(var, words);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("chars ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let cs: Vec<String> = s.chars().map(|c| c.to_string()).collect();
            oop.lists.insert(var, cs);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("nth_word ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let w = s.split_whitespace().nth(n).unwrap_or("").to_string();
                oop.string_vars.insert(var, w);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("first_word ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.split_whitespace().next().unwrap_or("").to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("last_word ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(var, s.split_whitespace().last().unwrap_or("").to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("left ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                oop.string_vars.insert(var, s.chars().take(n).collect());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("right ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let total = s.chars().count();
                oop.string_vars.insert(var, s.chars().skip(total.saturating_sub(n)).collect());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("repeat_print ") {
        let _ = rest;
    }

    if let Some(rest) = line.strip_prefix("ltake ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let src = args[0].trim();
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let l: Vec<String> = oop.lists.get(src).map(|l| l.iter().take(n).cloned().collect()).unwrap_or_default();
                oop.lists.insert(dest, l);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ldrop ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let src = args[0].trim();
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let l: Vec<String> = oop.lists.get(src).map(|l| l.iter().skip(n).cloned().collect()).unwrap_or_default();
                oop.lists.insert(dest, l);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lextend ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let dest = args[0].trim();
            let src = args[1].trim();
            let to_add: Vec<String> = oop.lists.get(src).cloned().unwrap_or_default();
            if let Some(l) = oop.lists.get_mut(dest) {
                l.extend(to_add);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("linsert ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let name = args[0].trim();
            let idx: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let value = resolve_arg(&args[2], vars, oop);
            if let Some(l) = oop.lists.get_mut(name) {
                if idx <= l.len() { l.insert(idx, value); }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lremove ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim();
            let value = resolve_arg(&args[1], vars, oop);
            if let Some(l) = oop.lists.get_mut(name) {
                l.retain(|v| v != &value);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lremove_at ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim();
            let idx: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            if let Some(l) = oop.lists.get_mut(name) {
                if idx < l.len() { l.remove(idx); }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lswap ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let name = args[0].trim();
            let i: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let j: usize = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0);
            if let Some(l) = oop.lists.get_mut(name) {
                if i < l.len() && j < l.len() { l.swap(i, j); }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcount_eq ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() >= 2 {
            let name = args[0].trim();
            let needle = resolve_arg(&args[1], vars, oop);
            let n = oop.lists.get(name).map(|l| l.iter().filter(|v| *v == &needle).count() as i64).unwrap_or(0);
            apply_return(vars, oop, result_var, Some(n.to_string()));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lproduct ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let p: f64 = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).product()).unwrap_or(1.0);
        let s = if p.fract() == 0.0 { (p as i64).to_string() } else { p.to_string() };
        apply_return(vars, oop, result_var, Some(s));
        return true;
    }

    if let Some(rest) = line.strip_prefix("lmedian ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let mut nums: Vec<f64> = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
        nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
        let m = if nums.is_empty() { 0.0 } else if nums.len() % 2 == 1 { nums[nums.len() / 2] } else { (nums[nums.len() / 2 - 1] + nums[nums.len() / 2]) / 2.0 };
        let s = if m.fract() == 0.0 { (m as i64).to_string() } else { m.to_string() };
        apply_return(vars, oop, result_var, Some(s));
        return true;
    }

    if let Some(rest) = line.strip_prefix("lvariance ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let nums: Vec<f64> = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
        let v = if nums.is_empty() { 0.0 } else {
            let mean = nums.iter().sum::<f64>() / nums.len() as f64;
            nums.iter().map(|n| (n - mean).powi(2)).sum::<f64>() / nums.len() as f64
        };
        apply_return(vars, oop, result_var, Some(v.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("lstddev ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let nums: Vec<f64> = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
        let s = if nums.is_empty() { 0.0 } else {
            let mean = nums.iter().sum::<f64>() / nums.len() as f64;
            (nums.iter().map(|n| (n - mean).powi(2)).sum::<f64>() / nums.len() as f64).sqrt()
        };
        apply_return(vars, oop, result_var, Some(s.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("write_lines ") {
        let args = split_args(rest);
        if args.len() == 2 {
            use std::io::Write;
            let path = expand_path(&resolve_arg(&args[0], vars, oop));
            let list_name = args[1].trim();
            if let Some(l) = oop.lists.get(list_name) {
                let content = l.join("\n");
                match fs::File::create(&path).and_then(|mut f| f.write_all(content.as_bytes())) {
                    Ok(_) => {}
                    Err(e) => println!("write_lines failed: {}", e),
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("touch ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        let _ = fs::OpenOptions::new().create(true).write(true).open(&path);
        return true;
    }

    if let Some(rest) = line.strip_prefix("ensure_dir ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        let _ = fs::create_dir_all(&path);
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_ext ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = resolve_arg(parts[1].trim(), vars, oop);
            let ext = PathBuf::from(&path).extension().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
            oop.string_vars.insert(var, ext);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_stem ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = resolve_arg(parts[1].trim(), vars, oop);
            let stem = PathBuf::from(&path).file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
            oop.string_vars.insert(var, stem);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_mtime ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let mtime = fs::metadata(&path).ok()
                .and_then(|m| m.modified().ok())
                .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
                .map(|d| d.as_secs() as i64).unwrap_or(0);
            vars.insert(var, mtime);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_age ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let mtime = fs::metadata(&path).ok()
                .and_then(|m| m.modified().ok())
                .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
                .map(|d| d.as_secs() as i64).unwrap_or(0);
            let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|d| d.as_secs() as i64).unwrap_or(0);
            vars.insert(var, now - mtime);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_empty ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let empty = fs::metadata(&path).map(|m| m.len() == 0).unwrap_or(true);
            vars.insert(var, if empty { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_hash ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            match fs::read(&path) {
                Ok(bytes) => {
                    use sha2::{Digest, Sha256};
                    let mut h = Sha256::new(); h.update(&bytes);
                    oop.string_vars.insert(var, format!("{:x}", h.finalize()));
                }
                Err(e) => { println!("file_hash failed: {}", e); }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("backup_file ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        let backup = path.with_extension(format!("{}.bak",
            path.extension().map(|e| e.to_string_lossy().to_string()).unwrap_or_default()));
        let _ = fs::copy(&path, &backup);
        return true;
    }

    if let Some(rest) = line.strip_prefix("which ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let cmd = resolve_arg(parts[1].trim(), vars, oop);
            let out = std::process::Command::new("which").arg(&cmd).output()
                .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
                .unwrap_or_default();
            oop.string_vars.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("nproc ") {
        let var = rest.trim().to_string();
        let n = std::thread::available_parallelism().map(|n| n.get() as i64).unwrap_or(1);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("uptime ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let out = std::process::Command::new("uptime").arg("-p").output()
            .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string())
            .unwrap_or_default();
        oop.string_vars.insert(var, out);
        return true;
    }

    if let Some(rest) = line.strip_prefix("public_ip ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let ip = reqwest::blocking::get("https://api.ipify.org")
            .and_then(|r| r.text()).map(|t| t.trim().to_string()).unwrap_or_default();
        oop.string_vars.insert(var, ip);
        return true;
    }

    if let Some(rest) = line.strip_prefix("local_ip ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let out = std::process::Command::new("hostname").arg("-I").output()
            .map(|o| String::from_utf8_lossy(&o.stdout).split_whitespace().next().unwrap_or("").to_string())
            .unwrap_or_default();
        oop.string_vars.insert(var, out);
        return true;
    }

    if let Some(rest) = line.strip_prefix("download ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let url = resolve_arg(&args[0], vars, oop);
            let path = expand_path(&resolve_arg(&args[1], vars, oop));
            match reqwest::blocking::get(&url).and_then(|r| r.bytes()) {
                Ok(bytes) => {
                    let _ = fs::write(&path, bytes);
                }
                Err(e) => println!("download failed: {}", e),
            }
        }
        return true;
    }

    // curl url path     — download URL to file (binary safe). Alias for download.
    // curl url -> var   — fetch URL contents as text into a variable.
    if let Some(rest) = line.strip_prefix("curl ") {
        // text-into-var form?
        if rest.contains("->") {
            let parts: Vec<&str> = rest.splitn(2, "->").collect();
            let var = parts.get(1).map(|s| s.trim().to_string());
            let url = resolve_arg(parts[0].trim(), vars, oop);
            match reqwest::blocking::get(&url).and_then(|r| r.text()) {
                Ok(text) => apply_return(vars, oop, var, Some(text)),
                Err(e) => println!("curl failed: {}", e),
            }
            return true;
        }
        // file form
        let args = split_args(rest);
        if args.len() == 2 {
            let url = resolve_arg(&args[0], vars, oop);
            let path = expand_path(&resolve_arg(&args[1], vars, oop));
            match reqwest::blocking::get(&url).and_then(|r| r.bytes()) {
                Ok(bytes) => {
                    if let Err(e) = fs::write(&path, &bytes) {
                        println!("curl write failed: {}", e);
                    } else {
                        println!("\x1b[36m[curl]\x1b[0m {} -> {} ({} bytes)",
                            url, path.display(), bytes.len());
                    }
                }
                Err(e) => println!("curl failed: {}", e),
            }
        }
        return true;
    }

    // gui_3d_load_texture_url "name" "https://..."  — fetch + decode in one shot
    if let Some(rest) = line.strip_prefix("gui_3d_load_texture_url ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = resolve_arg(&args[0], vars, oop);
            let url = resolve_arg(&args[1], vars, oop);
            match reqwest::blocking::get(&url).and_then(|r| r.bytes()) {
                Ok(bytes) => {
                    if let Some((buf, w, h)) = load_texture_bytes(&bytes) {
                        GUI_3D_TEXTURES.with(|t|
                            t.borrow_mut().insert(name.clone(), (buf, w, h)));
                        println!("\x1b[36m[3d]\x1b[0m loaded texture {} from URL ({}x{})", name, w, h);
                    } else {
                        println!("gui_3d_load_texture_url: format unrecognized");
                    }
                }
                Err(e) => println!("gui_3d_load_texture_url failed: {}", e),
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sha1 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            use sha2::Digest;
            let mut h = sha2::Sha256::new();
            h.update(s.as_bytes());
            oop.string_vars.insert(var, format!("{:x}", h.finalize()).chars().take(40).collect());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("sha512 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            use sha2::{Digest, Sha512};
            let mut h = Sha512::new();
            h.update(s.as_bytes());
            oop.string_vars.insert(var, format!("{:x}", h.finalize()));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("random_bytes ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: usize = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(16);
            let hex = "0123456789abcdef".as_bytes();
            let mut rng = rand::thread_rng();
            let s: String = (0..n*2).map(|_| {
                let i: usize = rand::Rng::gen_range(&mut rng, 0..16);
                hex[i] as char
            }).collect();
            oop.string_vars.insert(var, s);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("random_password ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: usize = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(16);
            let chars: Vec<char> = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*".chars().collect();
            let mut rng = rand::thread_rng();
            let s: String = (0..n).map(|_| {
                let i: usize = rand::Rng::gen_range(&mut rng, 0..chars.len());
                chars[i]
            }).collect();
            oop.string_vars.insert(var, s);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("hex_decode ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let bytes: Vec<u8> = (0..s.len()/2).filter_map(|i| u8::from_str_radix(&s[i*2..i*2+2], 16).ok()).collect();
            oop.string_vars.insert(var, String::from_utf8_lossy(&bytes).to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dpop ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim();
            let key = resolve_arg(&args[1], vars, oop);
            if let Some(d) = oop.dicts.get_mut(name) {
                d.remove(&key);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dincr ") {
        let args = split_args(rest);
        if args.len() >= 2 {
            let name = args[0].trim().to_string();
            let key = resolve_arg(&args[1], vars, oop);
            let by: i64 = if args.len() >= 3 { resolve_arg(&args[2], vars, oop).parse().unwrap_or(1) } else { 1 };
            let d = oop.dicts.entry(name).or_insert_with(HashMap::new);
            let cur: i64 = d.get(&key).and_then(|v| v.parse().ok()).unwrap_or(0);
            d.insert(key, (cur + by).to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dinvert ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let dest = args[0].trim().to_string();
            let src = args[1].trim();
            let inverted: HashMap<String, String> = oop.dicts.get(src).map(|d| d.iter().map(|(k, v)| (v.clone(), k.clone())).collect()).unwrap_or_default();
            oop.dicts.insert(dest, inverted);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dclear ") {
        let name = rest.trim();
        if let Some(d) = oop.dicts.get_mut(name) { d.clear(); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("year ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let n: i64 = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.format("%Y").to_string().parse().unwrap_or(0)).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("month ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let n: i64 = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.format("%m").to_string().parse().unwrap_or(0)).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("day ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let n: i64 = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.format("%d").to_string().parse().unwrap_or(0)).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dayofyear ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let n: i64 = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.format("%j").to_string().parse().unwrap_or(0)).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_leap_year ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let y: i32 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let leap = (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
            vars.insert(var, if leap { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("date_today ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, chrono::Local::now().format("%Y-%m-%d").to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("date_tomorrow ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, (chrono::Local::now() + chrono::Duration::days(1)).format("%Y-%m-%d").to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("date_yesterday ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, (chrono::Local::now() - chrono::Duration::days(1)).format("%Y-%m-%d").to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("now_iso ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, chrono::Local::now().to_rfc3339());
        return true;
    }

    if let Some(rest) = line.strip_prefix("hour_now ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let now: i64 = chrono::Local::now().format("%H").to_string().parse().unwrap_or(0);
        vars.insert(var, now);
        return true;
    }

    if let Some(rest) = line.strip_prefix("minute_now ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let n: i64 = chrono::Local::now().format("%M").to_string().parse().unwrap_or(0);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("second_now ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let n: i64 = chrono::Local::now().format("%S").to_string().parse().unwrap_or(0);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("monthname ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let m: u32 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(1);
            let names = ["", "January","February","March","April","May","June","July","August","September","October","November","December"];
            oop.string_vars.insert(var, names.get(m as usize).copied().unwrap_or("?").to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dayname ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let name = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.format("%A").to_string()).unwrap_or_default();
            oop.string_vars.insert(var, name);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_weekend ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let we = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| {
                let w = d.format("%w").to_string();
                w == "0" || w == "6"
            }).unwrap_or(false);
            vars.insert(var, if we { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("format_bytes ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: f64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0.0);
            let units = ["B", "KB", "MB", "GB", "TB", "PB"];
            let mut size = n; let mut unit = 0;
            while size >= 1024.0 && unit < units.len() - 1 { size /= 1024.0; unit += 1; }
            oop.string_vars.insert(var, format!("{:.2} {}", size, units[unit]));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("format_duration ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let mut s: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let h = s / 3600; s %= 3600;
            let m = s / 60; s %= 60;
            let out = if h > 0 { format!("{}h {}m {}s", h, m, s) }
                else if m > 0 { format!("{}m {}s", m, s) }
                else { format!("{}s", s) };
            oop.string_vars.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("format_number ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let s = n.to_string();
            let mut out = String::new();
            for (i, c) in s.chars().rev().enumerate() {
                if i > 0 && i % 3 == 0 && c != '-' { out.push(','); }
                out.push(c);
            }
            oop.string_vars.insert(var, out.chars().rev().collect());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("type_of ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let t = if vars.contains_key(name) { "int" }
                else if oop.string_vars.contains_key(name) { "string" }
                else if oop.lists.contains_key(name) { "list" }
                else if oop.dicts.contains_key(name) { "dict" }
                else if oop.instances.contains_key(name) { "instance" }
                else if oop.classes.contains_key(name) { "class" }
                else if oop.functions.contains_key(name) { "function" }
                else { "undefined" };
            oop.string_vars.insert(var, t.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("has_var ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let has = vars.contains_key(name) || oop.string_vars.contains_key(name);
            vars.insert(var, if has { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("unset_var ") {
        let name = rest.trim();
        vars.remove(name);
        oop.string_vars.remove(name);
        return true;
    }

    if let Some(rest) = line.strip_prefix("copy_var ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            if let Some(v) = vars.get(src).copied() { vars.insert(dest.clone(), v); }
            else if let Some(v) = oop.string_vars.get(src).cloned() { oop.string_vars.insert(dest, v); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("swap_vars ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let a = args[0].trim().to_string();
            let b = args[1].trim().to_string();
            let va = vars.get(&a).copied();
            let vb = vars.get(&b).copied();
            if let (Some(x), Some(y)) = (va, vb) {
                vars.insert(a, y); vars.insert(b, x);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("titlebar ") {
        let title = resolve_arg(rest.trim(), vars, oop);
        print!("\x1b]0;{}\x07", title);
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(rest) = line.strip_prefix("arrow_up ") {
        let n: usize = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(1);
        print!("\x1b[{}A", n);
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(rest) = line.strip_prefix("arrow_down ") {
        let n: usize = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(1);
        print!("\x1b[{}B", n);
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(rest) = line.strip_prefix("arrow_left ") {
        let n: usize = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(1);
        print!("\x1b[{}D", n);
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(rest) = line.strip_prefix("arrow_right ") {
        let n: usize = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(1);
        print!("\x1b[{}C", n);
        let _ = io::stdout().flush();
        return true;
    }

    if line == "bold_on" { print!("\x1b[1m"); let _ = io::stdout().flush(); return true; }
    if line == "bold_off" { print!("\x1b[22m"); let _ = io::stdout().flush(); return true; }
    if line == "italic_on" { print!("\x1b[3m"); let _ = io::stdout().flush(); return true; }
    if line == "italic_off" { print!("\x1b[23m"); let _ = io::stdout().flush(); return true; }
    if line == "underline_on" { print!("\x1b[4m"); let _ = io::stdout().flush(); return true; }
    if line == "underline_off" { print!("\x1b[24m"); let _ = io::stdout().flush(); return true; }
    if line == "strikethrough_on" { print!("\x1b[9m"); let _ = io::stdout().flush(); return true; }
    if line == "strikethrough_off" { print!("\x1b[29m"); let _ = io::stdout().flush(); return true; }
    if line == "blink_on" { print!("\x1b[5m"); let _ = io::stdout().flush(); return true; }
    if line == "blink_off" { print!("\x1b[25m"); let _ = io::stdout().flush(); return true; }
    if line == "invert_on" { print!("\x1b[7m"); let _ = io::stdout().flush(); return true; }
    if line == "invert_off" { print!("\x1b[27m"); let _ = io::stdout().flush(); return true; }

    if let Some(rest) = line.strip_prefix("echo ") {
        println!("{}", resolve_arg(rest.trim(), vars, oop));
        return true;
    }

    if let Some(rest) = line.strip_prefix("printf ") {
        print!("{}", resolve_arg(rest.trim(), vars, oop));
        let _ = io::stdout().flush();
        return true;
    }

    if let Some(rest) = line.strip_prefix("assert_eq ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let a = resolve_arg(&args[0], vars, oop);
            let b = resolve_arg(&args[1], vars, oop);
            if a == b { println!("\x1b[32m✓\x1b[0m {} == {}", args[0].trim(), b); }
            else { println!("\x1b[31m✗\x1b[0m {} != {} (got {})", args[0].trim(), b, a); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("assert_ne ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let a = resolve_arg(&args[0], vars, oop);
            let b = resolve_arg(&args[1], vars, oop);
            if a != b { println!("\x1b[32m✓\x1b[0m {} != {}", args[0].trim(), b); }
            else { println!("\x1b[31m✗\x1b[0m {} == {}", args[0].trim(), b); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("assert_lt ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let a: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let b: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            if a < b { println!("\x1b[32m✓\x1b[0m {} < {}", a, b); }
            else { println!("\x1b[31m✗\x1b[0m {} >= {}", a, b); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("assert_gt ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let a: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let b: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            if a > b { println!("\x1b[32m✓\x1b[0m {} > {}", a, b); }
            else { println!("\x1b[31m✗\x1b[0m {} <= {}", a, b); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("benchmark ") {
        let args = split_args(rest);
        if args.len() >= 2 {
            let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
            let code = resolve_arg(&args[1], vars, oop);
            let start = std::time::Instant::now();
            for _ in 0..n {
                execute(&code, vars, server_cfg, oop);
            }
            println!("benchmark: ran {} times in {:?} ({}μs avg)", n, start.elapsed(), start.elapsed().as_micros() / (n.max(1) as u128));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_count ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let alias = resolve_arg(&args[0], vars, oop);
            let table = resolve_arg(&args[1], vars, oop);
            if let Some(conn) = oop.db_connections.get(&alias) {
                let n: i64 = conn.query_row(&format!("SELECT COUNT(*) FROM {}", table), [], |r| r.get(0)).unwrap_or(-1);
                apply_return(vars, oop, result_var, Some(n.to_string()));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_tables ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let alias = resolve_arg(parts[0].trim(), vars, oop);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        if let Some(conn) = oop.db_connections.get(&alias) {
            let mut tables: Vec<String> = Vec::new();
            if let Ok(mut stmt) = conn.prepare("SELECT name FROM sqlite_master WHERE type='table'") {
                if let Ok(mut rows) = stmt.query([]) {
                    while let Ok(Some(row)) = rows.next() {
                        if let Ok(name) = row.get::<_, String>(0) { tables.push(name); }
                    }
                }
            }
            if let Some(v) = result_var { oop.lists.insert(v, tables); }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_begin ") {
        let alias = resolve_arg(rest.trim(), vars, oop);
        if let Some(conn) = oop.db_connections.get(&alias) { let _ = conn.execute("BEGIN", []); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_commit ") {
        let alias = resolve_arg(rest.trim(), vars, oop);
        if let Some(conn) = oop.db_connections.get(&alias) { let _ = conn.execute("COMMIT", []); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_rollback ") {
        let alias = resolve_arg(rest.trim(), vars, oop);
        if let Some(conn) = oop.db_connections.get(&alias) { let _ = conn.execute("ROLLBACK", []); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("json_stringify ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            if let Some(d) = oop.dicts.get(name) {
                let v: serde_json::Value = d.iter().map(|(k, v)| (k.clone(), serde_json::Value::String(v.clone()))).collect::<serde_json::Map<_, _>>().into();
                oop.string_vars.insert(var, v.to_string());
            } else if let Some(l) = oop.lists.get(name) {
                let v: serde_json::Value = l.iter().map(|s| serde_json::Value::String(s.clone())).collect::<Vec<_>>().into();
                oop.string_vars.insert(var, v.to_string());
            } else if let Some(s) = oop.string_vars.get(name) {
                oop.string_vars.insert(var, format!("\"{}\"", s.replace('"', "\\\"")));
            } else if let Some(n) = vars.get(name) {
                oop.string_vars.insert(var, n.to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("json_pretty ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let raw = resolve_arg(parts[1].trim(), vars, oop);
            let pretty = serde_json::from_str::<serde_json::Value>(&raw).and_then(|v| serde_json::to_string_pretty(&v)).unwrap_or_else(|_| raw);
            oop.string_vars.insert(var, pretty);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("repeat_call ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
            let cmd = resolve_arg(&args[1], vars, oop);
            for _ in 0..n {
                if !execute(&cmd, vars, server_cfg, oop) {
                    return false;
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("fibonacci ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let (mut a, mut b): (i64, i64) = (0, 1);
            for _ in 0..n { let t = a + b; a = b; b = t; }
            vars.insert(var, a);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("choose ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let k: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                if k < 0 || k > n { vars.insert(var, 0); }
                else {
                    let k = k.min(n - k);
                    let mut result: i64 = 1;
                    for i in 0..k { result = result * (n - i) / (i + 1); }
                    vars.insert(var, result);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("perms ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let k: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let mut result: i64 = 1;
                for i in 0..k { result = result.saturating_mul(n - i); }
                vars.insert(var, result);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("distance ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 4 {
                let x1: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let y1: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                let x2: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
                let y2: f64 = resolve_arg(&args[3], vars, oop).parse().unwrap_or(0.0);
                oop.string_vars.insert(var, ((x2-x1).powi(2) + (y2-y1).powi(2)).sqrt().to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("manhattan ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 4 {
                let x1: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let y1: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                let x2: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
                let y2: f64 = resolve_arg(&args[3], vars, oop).parse().unwrap_or(0.0);
                let d = (x2-x1).abs() + (y2-y1).abs();
                if d.fract() == 0.0 { vars.insert(var, d as i64); }
                else { oop.string_vars.insert(var, d.to_string()); }
            }
        }
        return true;
    }

    macro_rules! print_const {
        ($name:expr, $val:expr) => {
            if line == $name {
                println!("{}", $val);
                return true;
            }
        };
    }

    print_const!("speed_of_sound", "343 m/s");
    print_const!("earth_gravity", "9.81 m/s²");
    print_const!("mars_gravity", "3.711 m/s²");
    print_const!("moon_gravity", "1.62 m/s²");
    print_const!("jupiter_gravity", "24.79 m/s²");
    print_const!("earth_mass", "5.972e24 kg");
    print_const!("sun_mass", "1.989e30 kg");
    print_const!("moon_mass", "7.347e22 kg");
    print_const!("light_year", "9.461e15 m");
    print_const!("parsec", "3.086e16 m");
    print_const!("ly_to_km", "9.461e12 km");
    print_const!("calories_per_kj", "0.239");
    print_const!("kj_per_calorie", "4.184");
    print_const!("psi_per_bar", "14.504");
    print_const!("bar_per_atm", "1.01325");
    print_const!("hp_per_kw", "1.341");
    print_const!("kw_per_hp", "0.7457");

    macro_rules! short_help {
        ($name:expr, $msg:expr) => {
            if line == $name {
                println!("{}", $msg);
                return true;
            }
        };
    }

    short_help!("ayaan_man", "AyaanScript+ — type 'help' for a categorized reference.");
    short_help!("man", "type 'help' for command reference.");
    short_help!("tutorial", "Visit https://crates.io/crates/ayaan or check the included game.ayaan.");
    short_help!("examples", "Try: game.ayaan, zoo.ayaan, calc.ayaan, eggs.ayaan");
    short_help!("about", "AyaanScript+ — a tiny scripting language with 1900+ commands.");
    short_help!("docs", "Run individual commands to see their behavior. Code is the docs.");
    short_help!("welcome_msg", "Welcome to AyaanScript+ — happy coding! 🐔");
    short_help!("hello_ayaan", "Hi from AyaanScript+!");

    macro_rules! emit_color_at {
        ($name:expr, $code:expr) => {
            if line == $name {
                print!("\x1b[{}m", $code);
                let _ = io::stdout().flush();
                return true;
            }
        };
    }

    emit_color_at!("c_black", "30"); emit_color_at!("c_red", "31");
    emit_color_at!("c_green", "32"); emit_color_at!("c_yellow", "33");
    emit_color_at!("c_blue", "34"); emit_color_at!("c_magenta", "35");
    emit_color_at!("c_cyan", "36"); emit_color_at!("c_white", "37");
    emit_color_at!("c_default", "39");
    emit_color_at!("c_bright_black", "90"); emit_color_at!("c_bright_red", "91");
    emit_color_at!("c_bright_green", "92"); emit_color_at!("c_bright_yellow", "93");
    emit_color_at!("c_bright_blue", "94"); emit_color_at!("c_bright_magenta", "95");
    emit_color_at!("c_bright_cyan", "96"); emit_color_at!("c_bright_white", "97");
    emit_color_at!("bg_black", "40"); emit_color_at!("bg_white", "47");
    emit_color_at!("bg_magenta", "45"); emit_color_at!("bg_cyan", "46");
    emit_color_at!("c_reset", "0");
    emit_color_at!("c_bold", "1"); emit_color_at!("c_dim", "2");
    emit_color_at!("c_italic", "3"); emit_color_at!("c_underline", "4");
    emit_color_at!("c_blink", "5"); emit_color_at!("c_invert", "7");
    emit_color_at!("c_hidden", "8"); emit_color_at!("c_strike", "9");

    macro_rules! const_num {
        ($name:expr, $val:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($name, " ")) {
                let var = rest.trim().to_string();
                oop.string_vars.insert(var, $val.to_string());
                return true;
            }
            if line == $name {
                println!("{}", $val);
                return true;
            }
        };
    }

    const_num!("const_pi", std::f64::consts::PI);
    const_num!("const_e", std::f64::consts::E);
    const_num!("const_tau", std::f64::consts::TAU);
    const_num!("const_sqrt2", std::f64::consts::SQRT_2);
    const_num!("const_ln2", std::f64::consts::LN_2);
    const_num!("const_ln10", std::f64::consts::LN_10);
    const_num!("const_log2e", std::f64::consts::LOG2_E);
    const_num!("const_log10e", std::f64::consts::LOG10_E);
    const_num!("const_inf", "inf");
    const_num!("const_neg_inf", "-inf");
    const_num!("const_nan", "NaN");
    const_num!("const_min_i64", i64::MIN);
    const_num!("const_max_i64", i64::MAX);
    const_num!("const_min_u8", 0);
    const_num!("const_max_u8", 255);
    const_num!("const_min_u16", 0);
    const_num!("const_max_u16", 65535);
    const_num!("const_min_u32", 0);
    const_num!("const_max_u32", u32::MAX);

    macro_rules! say_str {
        ($name:expr, $msg:expr) => {
            if line == $name {
                println!("{}", $msg);
                return true;
            }
        };
    }

    say_str!("zero", "0"); say_str!("one", "1"); say_str!("two", "2");
    say_str!("three", "3"); say_str!("four", "4"); say_str!("five", "5");
    say_str!("six", "6"); say_str!("seven", "7"); say_str!("eight", "8");
    say_str!("nine", "9"); say_str!("ten", "10"); say_str!("eleven", "11");
    say_str!("twelve", "12"); say_str!("hundred", "100"); say_str!("thousand", "1000");
    say_str!("million", "1000000"); say_str!("billion", "1000000000");
    say_str!("trillion", "1000000000000");

    say_str!("alpha", "α"); say_str!("beta", "β"); say_str!("gamma", "γ");
    say_str!("delta", "δ"); say_str!("epsilon", "ε"); say_str!("zeta", "ζ");
    say_str!("eta", "η"); say_str!("theta", "θ"); say_str!("iota", "ι");
    say_str!("kappa", "κ"); say_str!("lambda", "λ"); say_str!("mu", "μ");
    say_str!("nu", "ν"); say_str!("xi", "ξ"); say_str!("omicron", "ο");
    say_str!("rho", "ρ"); say_str!("sigma", "σ"); say_str!("upsilon", "υ");
    say_str!("phi_letter", "φ"); say_str!("chi", "χ"); say_str!("psi", "ψ");
    say_str!("omega", "ω");

    say_str!("plus", "+"); say_str!("minus", "−"); say_str!("multiply_sign", "×");
    say_str!("divide_sign", "÷"); say_str!("plusminus", "±"); say_str!("not_equal", "≠");
    say_str!("less_equal", "≤"); say_str!("greater_equal", "≥"); say_str!("approx", "≈");
    say_str!("infinity", "∞"); say_str!("therefore", "∴"); say_str!("because", "∵");
    say_str!("integral", "∫"); say_str!("partial", "∂"); say_str!("nabla", "∇");
    say_str!("sum_sign", "Σ"); say_str!("product_sign", "∏"); say_str!("sqrt_sign", "√");
    say_str!("emdash", "—"); say_str!("endash", "–"); say_str!("ellipsis", "…");
    say_str!("bullet", "•"); say_str!("section", "§"); say_str!("paragraph", "¶");
    say_str!("dagger", "†"); say_str!("doubledagger", "‡");
    say_str!("registered", "®"); say_str!("trademark", "™"); say_str!("copyright", "©");
    say_str!("degree", "°"); say_str!("micro", "µ");

    say_str!("arrow_left_str", "←"); say_str!("arrow_right_str", "→");
    say_str!("arrow_up_str", "↑"); say_str!("arrow_down_str", "↓");
    say_str!("arrow_upleft", "↖"); say_str!("arrow_upright", "↗");
    say_str!("arrow_downleft", "↙"); say_str!("arrow_downright", "↘");
    say_str!("double_arrow_right", "⇒"); say_str!("double_arrow_left", "⇐");
    say_str!("arrows_lr", "↔"); say_str!("arrows_ud", "↕");

    say_str!("check_mark", "✓"); say_str!("cross_mark", "✗"); say_str!("double_check", "✓✓");
    say_str!("heart_outline", "♡"); say_str!("heart_filled", "♥");
    say_str!("club_card", "♣"); say_str!("diamond_card", "♦");
    say_str!("spade_card", "♠"); say_str!("star_outline", "☆"); say_str!("star_filled", "★");
    say_str!("music_note", "♪"); say_str!("music_notes", "♫"); say_str!("flat", "♭"); say_str!("sharp", "♯");
    say_str!("yin_yang", "☯"); say_str!("peace_sign", "☮"); say_str!("recycle", "♻");
    say_str!("warning_sign", "⚠"); say_str!("radioactive", "☢"); say_str!("biohazard", "☣");

    say_str!("smiley", "☺"); say_str!("frowny", "☹"); say_str!("skull_alt", "☠");
    say_str!("phone_alt", "☎"); say_str!("scissors_alt", "✂"); say_str!("plane_alt", "✈");
    say_str!("snowflake_alt", "❄"); say_str!("sparkle_alt", "❅");
    say_str!("envelope_alt", "✉"); say_str!("pencil_alt", "✎");
    say_str!("pen_alt", "✒"); say_str!("flower_alt", "✿");

    say_str!("block_full", "█"); say_str!("block_dark", "▓"); say_str!("block_med", "▒"); say_str!("block_light", "░");
    say_str!("box_upper", "▀"); say_str!("box_lower", "▄"); say_str!("box_left", "▌"); say_str!("box_right", "▐");
    say_str!("triangle_up", "▲"); say_str!("triangle_down", "▼"); say_str!("triangle_left", "◀"); say_str!("triangle_right", "▶");
    say_str!("circle_filled", "●"); say_str!("circle_outline", "○"); say_str!("square_filled", "■"); say_str!("square_outline", "□");
    say_str!("diamond_filled", "◆"); say_str!("diamond_outline", "◇");

    say_str!("box_h", "─"); say_str!("box_v", "│");
    say_str!("box_tl", "┌"); say_str!("box_tr", "┐"); say_str!("box_bl", "└"); say_str!("box_br", "┘");
    say_str!("box_t", "┬"); say_str!("box_b", "┴"); say_str!("box_l", "├"); say_str!("box_r", "┤"); say_str!("box_cross", "┼");

    say_str!("dbox_h", "═"); say_str!("dbox_v", "║");
    say_str!("dbox_tl", "╔"); say_str!("dbox_tr", "╗"); say_str!("dbox_bl", "╚"); say_str!("dbox_br", "╝");

    macro_rules! sound_effect {
        ($name:expr, $msg:expr) => {
            if line == $name {
                println!("{}", $msg);
                return true;
            }
        };
    }

    sound_effect!("woosh", "*woosh*"); sound_effect!("ka_pow", "*KA-POW*");
    sound_effect!("smash", "💥 *SMASH*"); sound_effect!("thump", "*thump*");
    sound_effect!("splash", "💦 *splash*"); sound_effect!("ding_ding", "🔔 *ding ding*");
    sound_effect!("toot", "📣 *toot*"); sound_effect!("honk_honk", "*honk honk*");
    sound_effect!("vroom", "🚗 *vroom*"); sound_effect!("zoom_zoom", "💨 *zoom zoom*");
    sound_effect!("brr", "❄️ *brr*"); sound_effect!("phew", "*phew*");
    sound_effect!("ahh", "*ahhhhh*"); sound_effect!("ohh", "*ohhh*");
    sound_effect!("ow", "Ow!"); sound_effect!("ouch", "Ouch!");
    sound_effect!("yikes_alert", "😬 yikes"); sound_effect!("eek", "Eek!");
    sound_effect!("uh_oh", "Uh oh."); sound_effect!("um", "Um..."); sound_effect!("uhh", "Uhhh...");
    sound_effect!("yum", "Yum!"); sound_effect!("yummy", "Mmm yummy");
    sound_effect!("ewww", "Ewww"); sound_effect!("blech", "Blech"); sound_effect!("ugh", "Ugh");
    sound_effect!("meh_meh", "*meh*"); sound_effect!("aww", "Aww");
    sound_effect!("aw_yeah", "Aw yeah!"); sound_effect!("aw_nuts", "Aw, nuts.");
    sound_effect!("dang", "Dang."); sound_effect!("darn", "Darn.");
    sound_effect!("rats", "Rats!"); sound_effect!("shoot", "Shoot.");
    sound_effect!("oh_well", "Oh well."); sound_effect!("c_est_la_vie", "C'est la vie.");
    sound_effect!("oh_no", "Oh no."); sound_effect!("oh_yeah", "OH YEAH!");
    sound_effect!("woohoo", "Woohoo! 🎉"); sound_effect!("yippee", "Yippee!");
    sound_effect!("yeehaw", "Yeehaw!"); sound_effect!("yowza", "Yowza!");
    sound_effect!("oof_loud", "OOF"); sound_effect!("yowl", "*yowl*");

    macro_rules! adj {
        ($name:expr, $msg:expr) => {
            if line == $name { println!("{}", $msg); return true; }
        };
    }

    adj!("big", "Big."); adj!("small", "Small."); adj!("tiny", "Tiny.");
    adj!("huge", "Huge!"); adj!("massive", "Massive!"); adj!("gigantic", "Gigantic!");
    adj!("microscopic", "Microscopic."); adj!("colossal", "Colossal!");
    adj!("enormous", "Enormous!"); adj!("teeny", "Teeny."); adj!("teeny_tiny", "Teeny tiny.");
    adj!("itty_bitty", "Itty bitty."); adj!("monstrous", "Monstrous.");
    adj!("titanic", "Titanic!"); adj!("immense", "Immense.");
    adj!("vast", "Vast."); adj!("spacious", "Spacious."); adj!("cramped", "Cramped.");
    adj!("narrow", "Narrow."); adj!("wide", "Wide."); adj!("tall", "Tall.");
    adj!("short", "Short."); adj!("long", "Long."); adj!("thin", "Thin.");
    adj!("thick", "Thick."); adj!("heavy", "Heavy."); adj!("light_weight", "Light.");
    adj!("hot", "Hot 🔥"); adj!("cold", "Cold ❄️"); adj!("warm", "Warm");
    adj!("cool_temp", "Cool"); adj!("freezing", "Freezing 🥶"); adj!("boiling", "Boiling 🥵");
    adj!("burning", "Burning"); adj!("scorching", "Scorching!");
    adj!("frosty", "Frosty"); adj!("chilly", "Chilly");
    adj!("damp", "Damp."); adj!("wet", "Wet."); adj!("soaked", "Soaked!"); adj!("dry", "Dry.");
    adj!("crispy", "Crispy."); adj!("soggy", "Soggy."); adj!("chewy", "Chewy.");
    adj!("crunchy", "Crunchy."); adj!("mushy", "Mushy."); adj!("fluffy_adj", "Fluffy.");
    adj!("hard", "Hard."); adj!("soft", "Soft."); adj!("smooth", "Smooth.");
    adj!("rough", "Rough."); adj!("bumpy", "Bumpy."); adj!("slippery", "Slippery.");
    adj!("sticky", "Sticky."); adj!("gooey", "Gooey."); adj!("slimy", "Slimy.");
    adj!("squishy", "Squishy."); adj!("spongy", "Spongy."); adj!("rubbery", "Rubbery.");
    adj!("brittle", "Brittle."); adj!("fragile_adj", "Fragile."); adj!("sturdy", "Sturdy.");
    adj!("solid", "Solid."); adj!("durable", "Durable.");
    adj!("fast", "Fast 💨"); adj!("slow", "Slow 🐢"); adj!("quick", "Quick");
    adj!("rapid", "Rapid"); adj!("swift", "Swift"); adj!("sluggish", "Sluggish");
    adj!("speedy", "Speedy"); adj!("zippy", "Zippy"); adj!("snappy", "Snappy");
    adj!("brisk", "Brisk"); adj!("agile", "Agile"); adj!("nimble", "Nimble");
    adj!("clumsy", "Clumsy"); adj!("graceful", "Graceful"); adj!("awkward", "Awkward");
    adj!("smooth_move", "Smooth."); adj!("jerky", "Jerky.");
    adj!("bright", "Bright ✨"); adj!("dim_adj", "Dim"); adj!("dark", "Dark");
    adj!("light_adj", "Light"); adj!("shiny", "Shiny ✨"); adj!("dull_adj", "Dull");
    adj!("glowing", "Glowing"); adj!("sparkling", "Sparkling ✨"); adj!("luminous", "Luminous");
    adj!("radiant", "Radiant"); adj!("gloomy", "Gloomy"); adj!("murky", "Murky");
    adj!("clear", "Clear"); adj!("transparent", "Transparent"); adj!("opaque", "Opaque");
    adj!("translucent", "Translucent");
    adj!("loud", "Loud 🔊"); adj!("quiet", "Quiet 🤫"); adj!("noisy", "Noisy");
    adj!("silent", "Silent"); adj!("deafening", "Deafening"); adj!("whispering", "Whispering");
    adj!("muffled", "Muffled");
    adj!("sweet", "Sweet"); adj!("sour", "Sour"); adj!("salty_adj", "Salty");
    adj!("bitter", "Bitter"); adj!("spicy", "Spicy 🌶️"); adj!("savory", "Savory");
    adj!("bland", "Bland"); adj!("tangy", "Tangy"); adj!("zesty", "Zesty");
    adj!("rich_adj", "Rich"); adj!("creamy", "Creamy"); adj!("buttery", "Buttery");

    if let Some(rest) = line.strip_prefix("set_int ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("set_string ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            oop.string_vars.insert(var, resolve_arg(parts[1].trim(), vars, oop));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("incr ") {
        let var = rest.trim().to_string();
        let v = vars.entry(var).or_insert(0);
        *v += 1;
        return true;
    }

    if let Some(rest) = line.strip_prefix("decr ") {
        let var = rest.trim().to_string();
        let v = vars.entry(var).or_insert(0);
        *v -= 1;
        return true;
    }

    if let Some(rest) = line.strip_prefix("zero_var ") {
        let var = rest.trim().to_string();
        vars.insert(var, 0);
        return true;
    }

    if let Some(rest) = line.strip_prefix("toggle ") {
        let var = rest.trim().to_string();
        let v = vars.entry(var).or_insert(0);
        *v = if *v == 0 { 1 } else { 0 };
        return true;
    }

    if let Some(rest) = line.strip_prefix("max_var ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim().to_string();
            let val: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let cur = vars.get(&name).copied().unwrap_or(i64::MIN);
            vars.insert(name, cur.max(val));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("min_var ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim().to_string();
            let val: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let cur = vars.get(&name).copied().unwrap_or(i64::MAX);
            vars.insert(name, cur.min(val));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dprint ") {
        let name = rest.trim();
        if let Some(d) = oop.dicts.get(name) {
            let mut keys: Vec<&String> = d.keys().collect();
            keys.sort();
            for k in keys {
                println!("  {} = {}", k, d[k]);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lprint ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get(name) {
            for (i, v) in l.iter().enumerate() {
                println!("  [{}] {}", i, v);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("vprint ") {
        let name = rest.trim();
        if let Some(v) = vars.get(name) { println!("{} = {}", name, v); }
        else if let Some(v) = oop.string_vars.get(name) { println!("{} = {:?}", name, v); }
        else { println!("(undefined)"); }
        return true;
    }

    macro_rules! int_unary {
        ($name:expr, $f:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($name, " ")) {
                let parts: Vec<&str> = rest.splitn(2, '=').collect();
                if parts.len() == 2 {
                    let var = parts[0].trim().to_string();
                    let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
                    vars.insert(var, $f(n));
                }
                return true;
            }
        };
    }

    int_unary!("bit_count", |n: i64| n.count_ones() as i64);
    int_unary!("leading_zeros", |n: i64| n.leading_zeros() as i64);
    int_unary!("trailing_zeros", |n: i64| n.trailing_zeros() as i64);
    int_unary!("next_power_of_2", |n: i64| (n as u64).next_power_of_two() as i64);
    int_unary!("is_power_of_2", |n: i64| if n > 0 && (n & (n - 1)) == 0 { 1 } else { 0 });
    int_unary!("digit_sum", |n: i64| n.abs().to_string().chars().filter_map(|c| c.to_digit(10)).map(|d| d as i64).sum::<i64>());
    int_unary!("digit_product", |n: i64| n.abs().to_string().chars().filter_map(|c| c.to_digit(10)).map(|d| d as i64).product::<i64>());
    int_unary!("num_digits", |n: i64| n.abs().to_string().chars().count() as i64);
    int_unary!("reverse_digits", |n: i64| n.abs().to_string().chars().rev().collect::<String>().parse().unwrap_or(0));
    int_unary!("divisor_count", |n: i64| { let n = n.abs(); if n == 0 { 0 } else { (1..=n).filter(|i| n % i == 0).count() as i64 } });
    int_unary!("divisor_sum", |n: i64| { let n = n.abs(); if n == 0 { 0 } else { (1..=n).filter(|i| n % i == 0).sum() } });
    int_unary!("is_perfect", |n: i64| { let n = n.abs(); if n < 2 { 0 } else { if (1..n).filter(|i| n % i == 0).sum::<i64>() == n { 1 } else { 0 } } });
    int_unary!("collatz_length", |n: i64| { let mut n = n; let mut count = 0; while n > 1 { if n % 2 == 0 { n /= 2; } else { n = 3*n+1; } count += 1; } count });
    int_unary!("digit_root", |n: i64| { let mut n = n.abs(); while n >= 10 { n = n.to_string().chars().filter_map(|c| c.to_digit(10)).map(|d| d as i64).sum(); } n });

    if let Some(rest) = line.strip_prefix("nth_prime ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(1);
            let mut count = 0; let mut num = 1i64;
            while count < n {
                num += 1;
                let is_p = if num < 2 { false } else if num < 4 { true } else if num % 2 == 0 { false } else {
                    let mut i = 3i64; let mut p = true;
                    while i*i <= num { if num % i == 0 { p = false; break; } i += 2; } p
                };
                if is_p { count += 1; }
            }
            vars.insert(var, num);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("primes_up_to ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: usize = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let mut sieve = vec![true; n+1];
            if n >= 0 { sieve[0] = false; }
            if n >= 1 { sieve[1] = false; }
            for i in 2..=n { if sieve[i] { let mut j = i*i; while j <= n { sieve[j] = false; j += i; } } }
            let list: Vec<String> = (2..=n).filter(|i| sieve[*i]).map(|i| i.to_string()).collect();
            oop.lists.insert(var, list);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("percentile ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let list_name = args[0].trim();
                let p: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(50.0);
                let mut nums: Vec<f64> = oop.lists.get(list_name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
                nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
                let v = if nums.is_empty() { 0.0 } else {
                    let idx = ((p / 100.0) * (nums.len() - 1) as f64).round() as usize;
                    nums[idx.min(nums.len() - 1)]
                };
                oop.string_vars.insert(var, v.to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lzeros ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: usize = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.lists.insert(var, vec!["0".to_string(); n]);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lones ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: usize = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.lists.insert(var, vec!["1".to_string(); n]);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lfill ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let n: usize = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let value = resolve_arg(&args[1], vars, oop);
                oop.lists.insert(var, vec![value; n]);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lconcat ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            let mut out: Vec<String> = Vec::new();
            for a in &args {
                if let Some(l) = oop.lists.get(a.trim()) { out.extend(l.iter().cloned()); }
            }
            oop.lists.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lprepend ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim();
            let value = resolve_arg(&args[1], vars, oop);
            if let Some(l) = oop.lists.get_mut(name) {
                l.insert(0, value);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lpop_front ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let v = if let Some(l) = oop.lists.get_mut(name) { if !l.is_empty() { Some(l.remove(0)) } else { None } } else { None };
        apply_return(vars, oop, result_var, v);
        return true;
    }

    if let Some(rest) = line.strip_prefix("ltail ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            let l: Vec<String> = oop.lists.get(src).map(|l| l.iter().skip(1).cloned().collect()).unwrap_or_default();
            oop.lists.insert(dest, l);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("linit ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            let l: Vec<String> = oop.lists.get(src).map(|l| { let n = l.len().saturating_sub(1); l.iter().take(n).cloned().collect() }).unwrap_or_default();
            oop.lists.insert(dest, l);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lreverse_copy ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            let mut l: Vec<String> = oop.lists.get(src).cloned().unwrap_or_default();
            l.reverse();
            oop.lists.insert(dest, l);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcompact ") {
        let name = rest.trim();
        if let Some(l) = oop.lists.get_mut(name) { l.retain(|s| !s.is_empty()); }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lis_sorted ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let sorted = oop.lists.get(name).map(|l| l.windows(2).all(|w| w[0] <= w[1])).unwrap_or(true);
            vars.insert(var, if sorted { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lis_unique ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let uq = oop.lists.get(name).map(|l| {
                let mut s: std::collections::HashSet<&String> = std::collections::HashSet::new();
                l.iter().all(|x| s.insert(x))
            }).unwrap_or(true);
            vars.insert(var, if uq { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lreplace_all ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let name = args[0].trim();
            let from = resolve_arg(&args[1], vars, oop);
            let to = resolve_arg(&args[2], vars, oop);
            if let Some(l) = oop.lists.get_mut(name) {
                for v in l.iter_mut() { if *v == from { *v = to.clone(); } }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lall_pos ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let r = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).all(|n| n > 0.0)).unwrap_or(true);
            vars.insert(var, if r { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lall_neg ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let r = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).all(|n| n < 0.0)).unwrap_or(true);
            vars.insert(var, if r { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lall_zero ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let r = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).all(|n| n == 0.0)).unwrap_or(true);
            vars.insert(var, if r { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lany_pos ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let r = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).any(|n| n > 0.0)).unwrap_or(false);
            vars.insert(var, if r { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lany_zero ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let r = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).any(|n| n == 0.0)).unwrap_or(false);
            vars.insert(var, if r { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcount_pos ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let n = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).filter(|n| *n > 0.0).count() as i64).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcount_neg ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let n = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).filter(|n| *n < 0.0).count() as i64).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcount_zero ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let n = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).filter(|n| *n == 0.0).count() as i64).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("str_eq_ci ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a = resolve_arg(&args[0], vars, oop);
                let b = resolve_arg(&args[1], vars, oop);
                vars.insert(var, if a.eq_ignore_ascii_case(&b) { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_palindrome ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let chars: Vec<char> = s.chars().collect();
            let rev: Vec<char> = chars.iter().rev().cloned().collect();
            vars.insert(var, if chars == rev { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("str_is_numeric ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.parse::<f64>().is_ok() { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("str_is_int ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if !s.is_empty() && s.parse::<i64>().is_ok() { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("str_is_float ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            vars.insert(var, if s.contains('.') && s.parse::<f64>().is_ok() { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_pascal ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let out: String = s.split(|c: char| c == '_' || c == '-' || c.is_whitespace())
                .filter(|w| !w.is_empty())
                .map(|w| { let mut c = w.chars(); c.next().unwrap_or('?').to_uppercase().collect::<String>() + &c.as_str().to_lowercase() })
                .collect();
            oop.string_vars.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_constant ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let out: String = s.chars().map(|c| if c == ' ' || c == '-' { '_' } else { c.to_ascii_uppercase() }).collect();
            oop.string_vars.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("json_escape_str ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let out: String = s.chars().map(|c| match c { '"' => "\\\"".to_string(), '\\' => "\\\\".to_string(), '\n' => "\\n".to_string(), '\t' => "\\t".to_string(), '\r' => "\\r".to_string(), _ => c.to_string() }).collect();
            oop.string_vars.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("shell_escape ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            oop.string_vars.insert(var, format!("'{}'", s.replace('\'', "'\\''")));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("str_chunk ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1).max(1);
                let chars: Vec<char> = s.chars().collect();
                let out: Vec<String> = chars.chunks(n).map(|c| c.iter().collect()).collect();
                oop.lists.insert(var, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("str_lines ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let lines: Vec<String> = s.lines().map(String::from).collect();
            oop.lists.insert(var, lines);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("contains_any ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let chars = resolve_arg(&args[1], vars, oop);
                vars.insert(var, if chars.chars().any(|c| s.contains(c)) { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("contains_all ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let chars = resolve_arg(&args[1], vars, oop);
                vars.insert(var, if chars.chars().all(|c| s.contains(c)) { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("str_pad_zero ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let w: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                oop.string_vars.insert(var, format!("{:0width$}", n, width = w));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("round_to ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let n: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let dp: u32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let m = 10f64.powi(dp as i32);
                oop.string_vars.insert(var, format!("{:.*}", dp as usize, (n * m).round() / m));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("url_host ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let u = resolve_arg(parts[1].trim(), vars, oop);
            let no_scheme = u.split("://").nth(1).unwrap_or(&u);
            let host = no_scheme.split('/').next().unwrap_or("").split(':').next().unwrap_or("");
            oop.string_vars.insert(var, host.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("url_path ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let u = resolve_arg(parts[1].trim(), vars, oop);
            let no_scheme = u.split("://").nth(1).unwrap_or(&u);
            let path = no_scheme.find('/').map(|i| &no_scheme[i..]).unwrap_or("/");
            let path = path.split('?').next().unwrap_or("");
            oop.string_vars.insert(var, path.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("url_query ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let u = resolve_arg(parts[1].trim(), vars, oop);
            let q = u.split('?').nth(1).unwrap_or("");
            oop.string_vars.insert(var, q.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("url_scheme ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let u = resolve_arg(parts[1].trim(), vars, oop);
            let scheme = u.split("://").next().unwrap_or("");
            oop.string_vars.insert(var, scheme.to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ip_to_int ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let octets: Vec<u32> = s.split('.').filter_map(|x| x.parse().ok()).collect();
            let n = if octets.len() == 4 { (octets[0] << 24) | (octets[1] << 16) | (octets[2] << 8) | octets[3] } else { 0 };
            vars.insert(var, n as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("int_to_ip ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: u32 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.string_vars.insert(var, format!("{}.{}.{}.{}", (n >> 24) & 0xff, (n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ip_v4_check ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let ok = s.split('.').count() == 4 && s.split('.').all(|p| p.parse::<u8>().is_ok());
            vars.insert(var, if ok { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("random_ipv4 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let mut rng = rand::thread_rng();
        let ip = format!("{}.{}.{}.{}",
            rand::Rng::gen_range(&mut rng, 1..255),
            rand::Rng::gen_range(&mut rng, 0..255),
            rand::Rng::gen_range(&mut rng, 0..255),
            rand::Rng::gen_range(&mut rng, 1..255));
        oop.string_vars.insert(var, ip);
        return true;
    }

    if let Some(rest) = line.strip_prefix("random_port ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let n: i64 = rand::Rng::gen_range(&mut rand::thread_rng(), 1024..65535);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("rand_letter ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let n: u8 = rand::Rng::gen_range(&mut rand::thread_rng(), b'a'..=b'z');
        oop.string_vars.insert(var, (n as char).to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("rand_uppercase ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let n: u8 = rand::Rng::gen_range(&mut rand::thread_rng(), b'A'..=b'Z');
        oop.string_vars.insert(var, (n as char).to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("rand_digit ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let n: i64 = rand::Rng::gen_range(&mut rand::thread_rng(), 0..=9);
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("rand_hex_char ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let h = "0123456789abcdef".as_bytes();
        let i: usize = rand::Rng::gen_range(&mut rand::thread_rng(), 0..16);
        oop.string_vars.insert(var, (h[i] as char).to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_writable ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let w = fs::metadata(&path).map(|m| !m.permissions().readonly()).unwrap_or(false);
            vars.insert(var, if w { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dir_exists ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            vars.insert(var, if path.is_dir() { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_count_in_dir ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let n = fs::read_dir(&path).map(|rd| rd.count() as i64).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("read_first_line ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let first = fs::read_to_string(&path).ok().and_then(|s| s.lines().next().map(String::from)).unwrap_or_default();
            oop.string_vars.insert(var, first);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("read_last_line ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let last = fs::read_to_string(&path).ok().and_then(|s| s.lines().last().map(String::from)).unwrap_or_default();
            oop.string_vars.insert(var, last);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_lines_count ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let n = fs::read_to_string(&path).map(|s| s.lines().count() as i64).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_words_count ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let n = fs::read_to_string(&path).map(|s| s.split_whitespace().count() as i64).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("now_plus_days ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.string_vars.insert(var, (chrono::Local::now() + chrono::Duration::days(d)).format("%Y-%m-%d").to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("now_minus_days ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            oop.string_vars.insert(var, (chrono::Local::now() - chrono::Duration::days(d)).format("%Y-%m-%d").to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("to_unix ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let n = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.and_hms_opt(0, 0, 0).unwrap().and_utc().timestamp()).unwrap_or(0);
            vars.insert(var, n);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("from_unix ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let s = chrono::DateTime::from_timestamp(n, 0).map(|d| d.format("%Y-%m-%d %H:%M:%S").to_string()).unwrap_or_default();
            oop.string_vars.insert(var, s);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("quarter_of ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let m: i64 = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.format("%m").to_string().parse().unwrap_or(0)).unwrap_or(0);
            vars.insert(var, (m + 2) / 3);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("week_of_year ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let w: i64 = chrono::NaiveDate::parse_from_str(&d, "%Y-%m-%d").map(|d| d.format("%V").to_string().parse().unwrap_or(0)).unwrap_or(0);
            vars.insert(var, w);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("days_in_year ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let y: i32 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let leap = (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
            vars.insert(var, if leap { 366 } else { 365 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("days_in_month ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let y: i32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let m: u32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let days = match m { 1|3|5|7|8|10|12 => 31, 4|6|9|11 => 30, 2 => if (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 { 29 } else { 28 }, _ => 0 };
                vars.insert(var, days);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_today ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let d = resolve_arg(parts[1].trim(), vars, oop);
            let today = chrono::Local::now().format("%Y-%m-%d").to_string();
            vars.insert(var, if d == today { 1 } else { 0 });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("midnight_today ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, format!("{} 00:00:00", chrono::Local::now().format("%Y-%m-%d")));
        return true;
    }

    if let Some(rest) = line.strip_prefix("yesterday_iso ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, (chrono::Local::now() - chrono::Duration::days(1)).to_rfc3339());
        return true;
    }

    if let Some(rest) = line.strip_prefix("tomorrow_iso ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, (chrono::Local::now() + chrono::Duration::days(1)).to_rfc3339());
        return true;
    }

    if let Some(rest) = line.strip_prefix("arch_name ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, std::env::consts::ARCH.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("os_family ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, std::env::consts::FAMILY.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("os_name ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, std::env::consts::OS.to_string());
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_root ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let is = env::var("USER").map(|u| u == "root").unwrap_or(false);
        vars.insert(var, if is { 1 } else { 0 });
        return true;
    }

    if let Some(rest) = line.strip_prefix("shell_name ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, env::var("SHELL").unwrap_or_default());
        return true;
    }

    if let Some(rest) = line.strip_prefix("term_name_var ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, env::var("TERM").unwrap_or_default());
        return true;
    }

    if let Some(rest) = line.strip_prefix("lang_env ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        oop.string_vars.insert(var, env::var("LANG").unwrap_or_default());
        return true;
    }

    if let Some(rest) = line.strip_prefix("env_size ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        vars.insert(var, env::vars().count() as i64);
        return true;
    }

    if let Some(rest) = line.strip_prefix("dpick ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if !args.is_empty() {
                let src = args[0].trim();
                let keys: Vec<String> = args.iter().skip(1).map(|a| resolve_arg(a, vars, oop)).collect();
                let mut out: HashMap<String, String> = HashMap::new();
                if let Some(d) = oop.dicts.get(src) {
                    for k in &keys {
                        if let Some(v) = d.get(k) { out.insert(k.clone(), v.clone()); }
                    }
                }
                oop.dicts.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("domit ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if !args.is_empty() {
                let src = args[0].trim();
                let keys: Vec<String> = args.iter().skip(1).map(|a| resolve_arg(a, vars, oop)).collect();
                let mut out: HashMap<String, String> = oop.dicts.get(src).cloned().unwrap_or_default();
                for k in &keys { out.remove(k); }
                oop.dicts.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("dcount_value ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let name = args[0].trim();
                let value = resolve_arg(&args[1], vars, oop);
                let n = oop.dicts.get(name).map(|d| d.values().filter(|v| *v == &value).count() as i64).unwrap_or(0);
                vars.insert(var, n);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("retry ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(1);
            let code = resolve_arg(&args[1], vars, oop);
            let mut tries = 0;
            while tries < n {
                let before = oop.error_message.take();
                if !execute(&code, vars, server_cfg, oop) { return false; }
                if oop.error_message.is_none() {
                    oop.error_message = before;
                    return true;
                }
                tries += 1;
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("test_pass ") {
        let name = resolve_arg(rest.trim(), vars, oop);
        println!("\x1b[32m✓ PASS\x1b[0m {}", name);
        return true;
    }

    if let Some(rest) = line.strip_prefix("test_fail ") {
        let name = resolve_arg(rest.trim(), vars, oop);
        println!("\x1b[31m✗ FAIL\x1b[0m {}", name);
        return true;
    }

    if let Some(rest) = line.strip_prefix("test_skip ") {
        let name = resolve_arg(rest.trim(), vars, oop);
        println!("\x1b[33m- SKIP\x1b[0m {}", name);
        return true;
    }

    macro_rules! alias_to {
        ($alias:expr, $target_prefix:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($alias, " ")) {
                let new_line = format!("{} {}", $target_prefix, rest);
                return execute(&new_line, vars, server_cfg, oop);
            }
        };
    }

    alias_to!("hi_low", "fmin");
    alias_to!("hi_max", "fmax");
    alias_to!("println", "psyska -/");
    alias_to!("print", "psyska -/");
    alias_to!("say", "psyska -/");
    alias_to!("display", "psyska -/");
    alias_to!("show", "psyska -/");
    alias_to!("output", "psyska -/");
    alias_to!("write", "psyska -/");
    alias_to!("print_var", "vprint");
    alias_to!("print_list", "lprint");
    alias_to!("print_dict", "dprint");
    alias_to!("list_size", "lsize");
    alias_to!("dict_size", "dsize");
    alias_to!("str_size", "strlen");
    alias_to!("str_len", "strlen");
    alias_to!("string_length", "strlen");
    alias_to!("list_push", "push");
    alias_to!("list_pop", "pop");
    alias_to!("list_get", "lget");
    alias_to!("list_set", "lset");
    alias_to!("dict_set", "dset");
    alias_to!("dict_get", "dget");
    alias_to!("dict_has", "dhas");
    alias_to!("dict_del", "ddel");
    alias_to!("dict_keys", "dkeys");
    alias_to!("dict_values", "dvalues");
    alias_to!("dict_merge", "dmerge");
    alias_to!("sleep_seconds", "sleep");
    alias_to!("wait", "sleep");
    alias_to!("delay", "sleep");
    alias_to!("pause_for", "sleep");
    alias_to!("random", "rand");
    alias_to!("randint", "rand");
    alias_to!("inc", "incr");
    alias_to!("dec", "decr");
    alias_to!("add_one", "incr");
    alias_to!("sub_one", "decr");
    alias_to!("absolute", "abs");
    alias_to!("magnitude", "abs");
    alias_to!("squared", "square");
    alias_to!("cubed", "cube");
    alias_to!("root", "sqrt");
    alias_to!("ceiling", "ceil");
    alias_to!("rounded", "round");
    alias_to!("truncated", "trunc");
    alias_to!("power", "pow");
    alias_to!("modulo", "mod_op");
    alias_to!("greater", "fmax");
    alias_to!("smaller", "fmin");
    alias_to!("biggest", "max");
    alias_to!("smallest", "min");
    alias_to!("total", "sum");
    alias_to!("average", "avg");
    alias_to!("median", "lmedian");
    alias_to!("variance", "lvariance");
    alias_to!("std_dev", "lstddev");
    alias_to!("count_occurrences", "count_substr");
    alias_to!("char_at", "substr");
    alias_to!("uppercase_str", "upper");
    alias_to!("lowercase_str", "lower");
    alias_to!("capitalize_str", "capitalize");
    alias_to!("title_case", "title");
    alias_to!("reverse_str", "reverse");
    alias_to!("string_contains", "contains");
    alias_to!("string_starts_with", "startswith");
    alias_to!("string_ends_with", "endswith");
    alias_to!("string_replace", "replace");
    alias_to!("string_concat", "concat");
    alias_to!("string_split", "split");
    alias_to!("string_trim", "trim");
    alias_to!("read_file", "readfile");
    alias_to!("write_file", "writefile");
    alias_to!("make_dir", "mkdir");
    alias_to!("remove_dir", "rmdir");
    alias_to!("remove_file", "rm");
    alias_to!("list_dir", "listdir");
    alias_to!("copy_files", "copy");
    alias_to!("move_files", "move");
    alias_to!("file_check", "exists");
    alias_to!("path_exists", "exists");
    alias_to!("base_name", "basename");
    alias_to!("dir_name", "dirname");
    alias_to!("ext_name", "extname");
    alias_to!("join_path", "joinpath");
    alias_to!("abs_path", "abspath");
    alias_to!("md5_hash", "md5");
    alias_to!("sha256_hash", "sha256");
    alias_to!("base64", "base64_encode");
    alias_to!("hash_md5", "md5");
    alias_to!("hash_sha256", "sha256");
    alias_to!("encode_b64", "base64_encode");
    alias_to!("decode_b64", "base64_decode");
    alias_to!("regex_check", "regex_match");
    alias_to!("regex_sub", "regex_replace");
    alias_to!("http_fetch", "http_get");
    alias_to!("http_send", "http_post");
    alias_to!("download_url", "download");
    alias_to!("get_env", "getenv");
    alias_to!("set_env", "setenv");
    alias_to!("load_env", "loadenv");
    alias_to!("log_info", "log info");
    alias_to!("log_warn", "log warn");
    alias_to!("log_error", "log error");
    alias_to!("log_debug", "log debug");
    alias_to!("info", "log info");
    alias_to!("error", "log error");
    alias_to!("debug_msg", "log debug");
    alias_to!("now_time", "now");
    alias_to!("current_time", "now");
    alias_to!("epoch", "now");
    alias_to!("today", "date_today");
    alias_to!("tomorrow", "date_tomorrow");
    alias_to!("yesterday", "date_yesterday");
    alias_to!("date_format", "datefmt");
    alias_to!("ms_sleep", "sleep_ms");
    alias_to!("date_add", "add_days");
    alias_to!("date_diff", "diff_days");
    alias_to!("table_print", "table");
    alias_to!("plot_bar", "barchart");
    alias_to!("plot_spark", "sparkline");
    alias_to!("animation", "spin");
    alias_to!("loading", "spin");
    alias_to!("rand_uuid", "uuid");
    alias_to!("gen_uuid", "uuid");
    alias_to!("gen_id", "uuid");
    alias_to!("box_draw", "box");
    alias_to!("banner_print", "banner");
    alias_to!("show_progress", "progress");
    alias_to!("draw_progress", "progress");
    alias_to!("color_red", "color red");
    alias_to!("color_green", "color green");
    alias_to!("color_blue", "color blue");
    alias_to!("color_yellow", "color yellow");
    alias_to!("color_off", "color reset");
    alias_to!("reset_color", "color reset");

    macro_rules! aka {
        ($alias:expr, $target_prefix:expr) => {
            if let Some(rest) = line.strip_prefix(concat!($alias, " ")) {
                let new_line = format!("{} {}", $target_prefix, rest);
                return execute(&new_line, vars, server_cfg, oop);
            }
        };
    }

    aka!("p", "psyska -/"); aka!("pr", "psyska -/");
    aka!("puts", "psyska -/"); aka!("emit", "psyska -/");
    aka!("dump", "vprint"); aka!("var", "vprint");
    aka!("ld", "lprint"); aka!("dd", "dprint");
    aka!("len", "strlen"); aka!("length", "strlen");
    aka!("size", "lsize"); aka!("count", "lsize");
    aka!("dsize2", "dsize");
    aka!("up", "upper"); aka!("lo", "lower");
    aka!("rev", "reverse"); aka!("trim2", "trim");
    aka!("cat2", "concat"); aka!("join", "ljoin");
    aka!("split2", "split"); aka!("sub", "substr");
    aka!("repl", "replace"); aka!("rep", "repeat_str");
    aka!("starts", "startswith"); aka!("ends", "endswith");
    aka!("has", "contains"); aka!("in_str", "contains");
    aka!("first_ch", "first_letter"); aka!("last_ch", "last_letter");
    aka!("lpad", "pad_left"); aka!("rpad", "pad");
    aka!("ctr", "center"); aka!("rep_n", "repeat_str");
    aka!("dq", "escape_quotes"); aka!("uq", "unescape_quotes");
    aka!("v", "ord"); aka!("ch", "chr");
    aka!("cap", "capitalize"); aka!("ttl", "title");
    aka!("sl", "slugify"); aka!("rw", "reverse_words");
    aka!("nws", "normalize_ws"); aka!("ol", "only_letters");
    aka!("od", "only_digits"); aka!("oa", "only_alnum");
    aka!("rsp", "remove_spaces"); aka!("csp", "collapse_spaces");
    aka!("ch1", "chomp"); aka!("ch2", "chop");
    aka!("rc", "repeat_chars"); aka!("acro", "acronym");
    aka!("init2", "initials"); aka!("ccount", "char_count");
    aka!("bcount", "byte_count"); aka!("lcount", "line_count");
    aka!("vcount", "vowel_count"); aka!("dcount", "digit_count");
    aka!("scount", "space_count"); aka!("ucount", "uppercase_count");
    aka!("lcount2", "lowercase_count"); aka!("conscount", "consonant_count");
    aka!("trunc2", "truncate"); aka!("wds", "words");
    aka!("chs", "chars"); aka!("nw", "nth_word");
    aka!("fw", "first_word"); aka!("lw", "last_word");
    aka!("lft", "left"); aka!("rgt", "right");
    aka!("set_str", "set_string"); aka!("set_i", "set_int");
    aka!("plus1", "incr"); aka!("minus1", "decr");
    aka!("z", "zero_var"); aka!("flip", "toggle");
    aka!("maxv", "max_var"); aka!("minv", "min_var");
    aka!("type", "type_of"); aka!("kind", "type_of");
    aka!("typeof2", "type_of"); aka!("has_v", "has_var");
    aka!("del_v", "unset_var"); aka!("cp_v", "copy_var");
    aka!("sw_v", "swap_vars"); aka!("title_t", "titlebar");
    aka!("up_a", "arrow_up"); aka!("dn_a", "arrow_down");
    aka!("l_a", "arrow_left"); aka!("r_a", "arrow_right");
    aka!("b_on", "bold_on"); aka!("b_off", "bold_off");
    aka!("i_on", "italic_on"); aka!("i_off", "italic_off");
    aka!("u_on", "underline_on"); aka!("u_off", "underline_off");
    aka!("s_on", "strikethrough_on"); aka!("s_off", "strikethrough_off");
    aka!("bl_on", "blink_on"); aka!("bl_off", "blink_off");
    aka!("inv_on", "invert_on"); aka!("inv_off", "invert_off");
    aka!("e", "echo"); aka!("pf", "printf");
    aka!("aeq", "assert_eq"); aka!("ane", "assert_ne");
    aka!("alt", "assert_lt"); aka!("agt", "assert_gt");
    aka!("bench", "benchmark"); aka!("dbc", "db_count");
    aka!("dbt", "db_tables"); aka!("dbb", "db_begin");
    aka!("dbcm", "db_commit"); aka!("dbrb", "db_rollback");
    aka!("jstr", "json_stringify"); aka!("jpp", "json_pretty");
    aka!("repcall", "repeat_call"); aka!("fib", "fibonacci");
    aka!("nck", "choose"); aka!("npk", "perms");
    aka!("dist", "distance"); aka!("man", "manhattan");
    aka!("blend", "lerp"); aka!("rng", "range");
    aka!("ufs", "lsort"); aka!("uds", "lreverse");
    aka!("uniq", "lunique"); aka!("mx", "lmax");
    aka!("mn", "lmin"); aka!("sm", "lsum");
    aka!("av", "lavg"); aka!("shuf", "lshuffle");
    aka!("pick", "lchoice"); aka!("frst", "first");
    aka!("lst", "last"); aka!("li", "lindex");
    aka!("lcp", "lcopy"); aka!("dv", "dvalues");
    aka!("dmg", "dmerge"); aka!("rl", "read_lines");
    aka!("apl", "append_file"); aka!("fsz", "file_size");
    aka!("isd", "is_dir"); aka!("isf", "is_file");
    aka!("bn", "basename"); aka!("dn", "dirname");
    aka!("xn", "extname"); aka!("jp", "joinpath");
    aka!("rf", "rand_float"); aka!("rb", "rand_bool");
    aka!("flip2", "coin"); aka!("dx6", "d6");
    aka!("dx20", "d20"); aka!("wd", "weekday");
    aka!("tms", "timestamp_ms"); aka!("pi2", "pid");
    aka!("plat", "platform"); aka!("hdel", "http_delete");
    aka!("hput", "http_put"); aka!("xy", "gotoxy");
    aka!("hide", "hide_cursor"); aka!("show2", "show_cursor");
    aka!("sav", "save_cursor"); aka!("rst", "restore_cursor");
    aka!("clrl", "clear_line"); aka!("clrb", "clear_below");
    aka!("tsz", "term_size");

    aka!("c2f", "c_to_f"); aka!("f2c", "f_to_c");
    aka!("c2k", "c_to_k"); aka!("k2c", "k_to_c");
    aka!("f2k", "f_to_k"); aka!("k2f", "k_to_f");
    aka!("km2mi", "km_to_mi"); aka!("mi2km", "mi_to_km");
    aka!("m2ft", "m_to_ft"); aka!("ft2m", "ft_to_m");
    aka!("cm2in", "cm_to_in"); aka!("in2cm", "in_to_cm");
    aka!("kg2lb", "kg_to_lb"); aka!("lb2kg", "lb_to_kg");
    aka!("g2oz", "g_to_oz"); aka!("oz2g", "oz_to_g");
    aka!("l2gal", "l_to_gal"); aka!("gal2l", "gal_to_l");
    aka!("ml2oz", "ml_to_floz"); aka!("oz2ml", "floz_to_ml");
    aka!("mph2kmh", "mph_to_kmh"); aka!("kmh2mph", "kmh_to_mph");
    aka!("kts2kmh", "knots_to_kmh"); aka!("kmh2kts", "kmh_to_knots");
    aka!("s2m", "sec_to_min"); aka!("m2s", "min_to_sec");
    aka!("m2h", "min_to_hr"); aka!("h2m", "hr_to_min");
    aka!("h2s", "hr_to_sec"); aka!("s2h", "sec_to_hr");
    aka!("d2h", "days_to_hr"); aka!("h2d", "hr_to_days");
    aka!("b2kb", "bytes_to_kb"); aka!("kb2mb", "kb_to_mb");
    aka!("mb2gb", "mb_to_gb"); aka!("gb2tb", "gb_to_tb");
    aka!("b2mb", "bytes_to_mb"); aka!("b2gb", "bytes_to_gb");

    aka!("sq", "square"); aka!("cb", "cube");
    aka!("neg", "negate"); aka!("dbl", "double");
    aka!("hf", "half"); aka!("tpl", "triple");
    aka!("th", "third"); aka!("pct", "percent");
    aka!("ipct", "inverse_percent"); aka!("inv", "invert");

    aka!("psnake", "to_pascal"); aka!("cnst", "to_constant");
    aka!("jesc", "json_escape_str"); aka!("shesc", "shell_escape");
    aka!("schunk", "str_chunk"); aka!("slines", "str_lines");
    aka!("ca", "contains_any"); aka!("cl", "contains_all");
    aka!("rpz", "str_pad_zero"); aka!("rd", "round_to");

    aka!("uh", "url_host"); aka!("up2", "url_path");
    aka!("uq2", "url_query"); aka!("us", "url_scheme");
    aka!("i2ip", "int_to_ip"); aka!("ip2i", "ip_to_int");
    aka!("isipv4", "ip_v4_check"); aka!("rip", "random_ipv4");
    aka!("rport", "random_port");

    aka!("rndlt", "rand_letter"); aka!("rndup", "rand_uppercase");
    aka!("rndd", "rand_digit"); aka!("rndhx", "rand_hex_char");

    aka!("fw2", "file_writable"); aka!("dx", "dir_exists");
    aka!("fcid", "file_count_in_dir"); aka!("rfl", "read_first_line");
    aka!("rll", "read_last_line"); aka!("flc", "file_lines_count");
    aka!("fwc", "file_words_count");

    aka!("npd", "now_plus_days"); aka!("nmd", "now_minus_days");
    aka!("tu", "to_unix"); aka!("fu", "from_unix");
    aka!("qo", "quarter_of"); aka!("woy", "week_of_year");
    aka!("diy", "days_in_year"); aka!("dim", "days_in_month");
    aka!("ity", "is_today"); aka!("mt", "midnight_today");
    aka!("yi", "yesterday_iso"); aka!("ti", "tomorrow_iso");

    aka!("an", "arch_name"); aka!("of", "os_family");
    aka!("on2", "os_name"); aka!("ir", "is_root");
    aka!("sn", "shell_name"); aka!("tnv", "term_name_var");
    aka!("le", "lang_env"); aka!("es", "env_size");

    aka!("dpi", "dpick"); aka!("doi", "domit");
    aka!("dcv", "dcount_value");

    aka!("rty", "retry"); aka!("tp", "test_pass");
    aka!("tf", "test_fail"); aka!("tsk", "test_skip");

    aka!("ada", "add_days"); aka!("dda", "diff_days");
    aka!("md", "mkdir"); aka!("rd2", "rmdir");
    aka!("rm2", "rm"); aka!("ex", "exists");
    aka!("ll", "listdir"); aka!("cpf", "copy");
    aka!("mvf", "move"); aka!("wf2", "writefile");
    aka!("rdf", "readfile");

    aka!("hm5", "md5"); aka!("hs2", "sha256");
    aka!("hs1", "sha1"); aka!("hs5", "sha512");
    aka!("b64e", "base64_encode"); aka!("b64d", "base64_decode");
    aka!("hxe", "hex_encode"); aka!("hxd", "hex_decode");
    aka!("rms", "rot13"); aka!("rhx", "random_bytes");
    aka!("rpw", "random_password");

    aka!("rgxm", "regex_match"); aka!("rgxr", "regex_replace");

    aka!("hg", "http_get"); aka!("hp", "http_post");
    aka!("dl", "download");

    aka!("jp2", "json_parse"); aka!("jpr", "json_pretty");

    aka!("gv", "getenv"); aka!("sv", "setenv");
    aka!("lv", "loadenv"); aka!("uv", "getuser");
    aka!("hv", "gethome"); aka!("pw", "pwd");
    aka!("aspf", "abspath");

    aka!("ins", "inspect"); aka!("as", "assert");
    aka!("db", "debug"); aka!("lg", "log");
    aka!("lf", "logfile"); aka!("ts", "time_start");
    aka!("te", "time_end");

    aka!("dbo", "db_open"); aka!("dbcl", "db_close");
    aka!("dbe", "db_exec"); aka!("dbq", "db_query");

    aka!("sp", "spin"); aka!("uu", "uuid");
    aka!("hn", "hostname"); aka!("he", "html_escape");
    aka!("ue2", "url_escape");

    aka!("sn2", "spawn"); aka!("tbl", "table");
    aka!("sk", "sparkline"); aka!("bc", "barchart");
    aka!("wf", "watchfile");

    aka!("bnr", "banner"); aka!("bx", "box");
    aka!("pg", "progress"); aka!("clr", "clear");
    aka!("hr2", "hr"); aka!("dv2", "divider");
    aka!("ks", "askstring"); aka!("kyn", "askyesno");

    aka!("ipk", "importpkg"); aka!("iay", "importayaan");

    macro_rules! const_print {
        ($name:expr, $val:expr) => {
            if line == $name { println!("{}", $val); return true; }
        };
    }

    const_print!("ascii_a", "65"); const_print!("ascii_z", "90");
    const_print!("ascii_la", "97"); const_print!("ascii_lz", "122");
    const_print!("ascii_0", "48"); const_print!("ascii_9", "57");
    const_print!("ascii_space", "32"); const_print!("ascii_tab", "9");
    const_print!("ascii_newline", "10"); const_print!("ascii_cr", "13");
    const_print!("ascii_null", "0"); const_print!("ascii_esc", "27");
    const_print!("ascii_del", "127");

    const_print!("unicode_max", "1114111");
    const_print!("utf8_max_bytes", "4");
    const_print!("ipv4_max_octet", "255");
    const_print!("port_max", "65535");
    const_print!("port_min", "0");
    const_print!("port_reserved", "1024");

    const_print!("max_byte", "255"); const_print!("min_byte", "0");
    const_print!("max_word", "65535"); const_print!("min_word", "0");
    const_print!("max_signed_byte", "127"); const_print!("min_signed_byte", "-128");
    const_print!("max_signed_word", "32767"); const_print!("min_signed_word", "-32768");
    const_print!("max_signed_dword", "2147483647");
    const_print!("min_signed_dword", "-2147483648");

    const_print!("kb_size", "1024"); const_print!("mb_size", "1048576");
    const_print!("gb_size", "1073741824"); const_print!("tb_size", "1099511627776");
    const_print!("kib", "1024"); const_print!("mib", "1048576");
    const_print!("gib", "1073741824"); const_print!("tib", "1099511627776");

    const_print!("seconds_per_minute", "60");
    const_print!("seconds_per_hour", "3600");
    const_print!("minutes_per_hour", "60");
    const_print!("hours_per_day", "24");
    const_print!("days_per_week", "7");
    const_print!("days_per_year", "365");
    const_print!("days_per_leap_year", "366");
    const_print!("months_per_year", "12");
    const_print!("weeks_per_year", "52");
    const_print!("seconds_per_day", "86400");
    const_print!("seconds_per_week", "604800");

    const_print!("inches_per_foot", "12");
    const_print!("feet_per_yard", "3");
    const_print!("yards_per_mile", "1760");
    const_print!("feet_per_mile", "5280");
    const_print!("cm_per_m", "100");
    const_print!("m_per_km", "1000");

    const_print!("grams_per_kg", "1000");
    const_print!("ml_per_l", "1000");
    const_print!("oz_per_lb", "16");
    const_print!("lb_per_ton", "2000");
    const_print!("ml_per_gal", "3785");

    const_print!("planets", "8");
    const_print!("continents", "7");
    const_print!("oceans", "5");
    const_print!("seasons", "4");
    const_print!("primary_colors", "3");
    const_print!("dimensions_3d", "3");

    macro_rules! constant_msg {
        ($name:expr, $val:expr) => {
            if line == $name { println!("{}", $val); return true; }
        };
    }

    constant_msg!("hello1", "Hello 1");
    constant_msg!("hello2", "Hello 2");
    constant_msg!("hello3", "Hello 3");
    constant_msg!("hello4", "Hello 4");
    constant_msg!("hello5", "Hello 5");
    constant_msg!("hello6", "Hello 6");
    constant_msg!("hello7", "Hello 7");
    constant_msg!("hello8", "Hello 8");
    constant_msg!("hello9", "Hello 9");
    constant_msg!("hello10", "Hello 10");

    // ====== REAL FUNCTIONAL COMMANDS ======

    if let Some(rest) = line.strip_prefix("levenshtein ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: Vec<char> = resolve_arg(&args[0], vars, oop).chars().collect();
                let b: Vec<char> = resolve_arg(&args[1], vars, oop).chars().collect();
                let (m, n) = (a.len(), b.len());
                let mut dp = vec![vec![0usize; n + 1]; m + 1];
                for i in 0..=m { dp[i][0] = i; }
                for j in 0..=n { dp[0][j] = j; }
                for i in 1..=m {
                    for j in 1..=n {
                        let cost = if a[i-1] == b[j-1] { 0 } else { 1 };
                        dp[i][j] = (dp[i-1][j] + 1).min(dp[i][j-1] + 1).min(dp[i-1][j-1] + cost);
                    }
                }
                vars.insert(var, dp[m][n] as i64);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("hamming_distance ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a = resolve_arg(&args[0], vars, oop);
                let b = resolve_arg(&args[1], vars, oop);
                let d: i64 = a.chars().zip(b.chars()).filter(|(x, y)| x != y).count() as i64
                    + (a.chars().count() as i64 - b.chars().count() as i64).abs();
                vars.insert(var, d);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("jaccard ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: std::collections::HashSet<char> = resolve_arg(&args[0], vars, oop).chars().collect();
                let b: std::collections::HashSet<char> = resolve_arg(&args[1], vars, oop).chars().collect();
                let intersect = a.intersection(&b).count() as f64;
                let union = a.union(&b).count() as f64;
                let j = if union == 0.0 { 0.0 } else { intersect / union };
                oop.string_vars.insert(var, j.to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("caesar_encode ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let shift: i32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(3);
                let shift = ((shift % 26) + 26) % 26;
                let out: String = s.chars().map(|c| match c {
                    'a'..='z' => (((c as u8 - b'a' + shift as u8) % 26) + b'a') as char,
                    'A'..='Z' => (((c as u8 - b'A' + shift as u8) % 26) + b'A') as char,
                    _ => c,
                }).collect();
                oop.string_vars.insert(var, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("caesar_decode ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let s = resolve_arg(&args[0], vars, oop);
                let shift: i32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(3);
                let shift = ((26 - shift % 26) + 26) % 26;
                let out: String = s.chars().map(|c| match c {
                    'a'..='z' => (((c as u8 - b'a' + shift as u8) % 26) + b'a') as char,
                    'A'..='Z' => (((c as u8 - b'A' + shift as u8) % 26) + b'A') as char,
                    _ => c,
                }).collect();
                oop.string_vars.insert(var, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("atbash ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let out: String = s.chars().map(|c| match c {
                'a'..='z' => (b'z' - (c as u8 - b'a')) as char,
                'A'..='Z' => (b'Z' - (c as u8 - b'A')) as char,
                _ => c,
            }).collect();
            oop.string_vars.insert(var, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("letter_freq ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let mut counts: HashMap<String, String> = HashMap::new();
            for c in s.chars().filter(|c| c.is_alphabetic()) {
                let k = c.to_ascii_lowercase().to_string();
                let cur: i64 = counts.get(&k).and_then(|v| v.parse().ok()).unwrap_or(0);
                counts.insert(k, (cur + 1).to_string());
            }
            oop.dicts.insert(dest, counts);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("word_freq ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let mut counts: HashMap<String, String> = HashMap::new();
            for w in s.split_whitespace() {
                let cur: i64 = counts.get(w).and_then(|v| v.parse().ok()).unwrap_or(0);
                counts.insert(w.to_string(), (cur + 1).to_string());
            }
            oop.dicts.insert(dest, counts);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("is_anagram ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a = resolve_arg(&args[0], vars, oop);
                let b = resolve_arg(&args[1], vars, oop);
                let mut ac: Vec<char> = a.chars().filter(|c| c.is_alphanumeric()).map(|c| c.to_ascii_lowercase()).collect();
                let mut bc: Vec<char> = b.chars().filter(|c| c.is_alphanumeric()).map(|c| c.to_ascii_lowercase()).collect();
                ac.sort(); bc.sort();
                vars.insert(var, if ac == bc { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("prime_factors ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let mut n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            let mut factors: Vec<String> = Vec::new();
            let mut d = 2;
            while d * d <= n {
                while n % d == 0 { factors.push(d.to_string()); n /= d; }
                d += 1;
            }
            if n > 1 { factors.push(n.to_string()); }
            oop.lists.insert(dest, factors);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("mod_pow ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 3 {
                let base: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let mut exp: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let m: i64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(1);
                let mut result: i64 = 1;
                let mut b = base % m;
                while exp > 0 {
                    if exp & 1 == 1 { result = (result * b) % m; }
                    exp >>= 1;
                    b = (b * b) % m;
                }
                vars.insert(var, result);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gcd3 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 3 {
                fn g(mut a: i64, mut b: i64) -> i64 { while b != 0 { let t = b; b = a % b; a = t; } a.abs() }
                let a: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let b: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let c: i64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0);
                vars.insert(var, g(g(a, b), c));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("nth_root ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let x: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let n: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1.0);
                oop.string_vars.insert(var, x.powf(1.0 / n).to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("triangular ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let n: i64 = resolve_arg(parts[1].trim(), vars, oop).parse().unwrap_or(0);
            vars.insert(var, n * (n + 1) / 2);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("set_union ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let mut s: std::collections::BTreeSet<String> = std::collections::BTreeSet::new();
                if let Some(l) = oop.lists.get(args[0].trim()) { s.extend(l.iter().cloned()); }
                if let Some(l) = oop.lists.get(args[1].trim()) { s.extend(l.iter().cloned()); }
                oop.lists.insert(dest, s.into_iter().collect());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("set_intersect ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: std::collections::HashSet<String> = oop.lists.get(args[0].trim()).map(|l| l.iter().cloned().collect()).unwrap_or_default();
                let b: std::collections::HashSet<String> = oop.lists.get(args[1].trim()).map(|l| l.iter().cloned().collect()).unwrap_or_default();
                let mut out: Vec<String> = a.intersection(&b).cloned().collect();
                out.sort();
                oop.lists.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("set_diff ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: Vec<String> = oop.lists.get(args[0].trim()).cloned().unwrap_or_default();
                let b: std::collections::HashSet<String> = oop.lists.get(args[1].trim()).map(|l| l.iter().cloned().collect()).unwrap_or_default();
                let out: Vec<String> = a.into_iter().filter(|x| !b.contains(x)).collect();
                oop.lists.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("set_eq ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: std::collections::HashSet<String> = oop.lists.get(args[0].trim()).map(|l| l.iter().cloned().collect()).unwrap_or_default();
                let b: std::collections::HashSet<String> = oop.lists.get(args[1].trim()).map(|l| l.iter().cloned().collect()).unwrap_or_default();
                vars.insert(var, if a == b { 1 } else { 0 });
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lwindow ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let src = args[0].trim();
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1);
                let l: Vec<String> = oop.lists.get(src).cloned().unwrap_or_default();
                let mut out: Vec<String> = Vec::new();
                if l.len() >= n {
                    for i in 0..=(l.len() - n) {
                        out.push(l[i..i + n].join(","));
                    }
                }
                oop.lists.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lscan ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            let l: Vec<String> = oop.lists.get(src).cloned().unwrap_or_default();
            let mut acc: f64 = 0.0;
            let mut out: Vec<String> = Vec::with_capacity(l.len());
            for x in &l {
                acc += x.parse::<f64>().unwrap_or(0.0);
                out.push(if acc.fract() == 0.0 { (acc as i64).to_string() } else { acc.to_string() });
            }
            oop.lists.insert(dest, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("crc32 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let mut crc: u32 = 0xffffffff;
            for b in s.bytes() {
                crc ^= b as u32;
                for _ in 0..8 {
                    crc = if crc & 1 == 1 { (crc >> 1) ^ 0xedb88320 } else { crc >> 1 };
                }
            }
            vars.insert(var, (crc ^ 0xffffffff) as i64);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("hmac_sha256 ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                use sha2::{Digest, Sha256};
                let key = resolve_arg(&args[0], vars, oop);
                let msg = resolve_arg(&args[1], vars, oop);
                let mut key_bytes = key.into_bytes();
                if key_bytes.len() > 64 {
                    let mut h = Sha256::new(); h.update(&key_bytes);
                    key_bytes = h.finalize().to_vec();
                }
                key_bytes.resize(64, 0);
                let opad: Vec<u8> = key_bytes.iter().map(|b| b ^ 0x5c).collect();
                let ipad: Vec<u8> = key_bytes.iter().map(|b| b ^ 0x36).collect();
                let mut h1 = Sha256::new(); h1.update(&ipad); h1.update(msg.as_bytes());
                let inner = h1.finalize();
                let mut h2 = Sha256::new(); h2.update(&opad); h2.update(&inner);
                oop.string_vars.insert(var, format!("{:x}", h2.finalize()));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_grep ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let path = expand_path(&resolve_arg(&args[0], vars, oop));
                let pat = resolve_arg(&args[1], vars, oop);
                let lines: Vec<String> = fs::read_to_string(&path).map(|s|
                    s.lines().filter(|l| l.contains(&pat)).map(String::from).collect()
                ).unwrap_or_default();
                oop.lists.insert(dest, lines);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("count_lines_matching ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let path = expand_path(&resolve_arg(&args[0], vars, oop));
                let pat = resolve_arg(&args[1], vars, oop);
                let n = fs::read_to_string(&path).map(|s|
                    s.lines().filter(|l| l.contains(&pat)).count() as i64
                ).unwrap_or(0);
                vars.insert(var, n);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_tail ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let path = expand_path(&resolve_arg(&args[0], vars, oop));
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(10);
                let lines: Vec<String> = fs::read_to_string(&path).map(|s| {
                    let all: Vec<&str> = s.lines().collect();
                    let start = all.len().saturating_sub(n);
                    all[start..].iter().map(|x| x.to_string()).collect()
                }).unwrap_or_default();
                oop.lists.insert(dest, lines);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_head ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let path = expand_path(&resolve_arg(&args[0], vars, oop));
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(10);
                let lines: Vec<String> = fs::read_to_string(&path).map(|s|
                    s.lines().take(n).map(String::from).collect()
                ).unwrap_or_default();
                oop.lists.insert(dest, lines);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("parse_query ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let mut d: HashMap<String, String> = HashMap::new();
            for pair in s.split('&') {
                let mut kv = pair.splitn(2, '=');
                let k = url_decode(kv.next().unwrap_or(""));
                let v = url_decode(kv.next().unwrap_or(""));
                if !k.is_empty() { d.insert(k, v); }
            }
            oop.dicts.insert(dest, d);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("form_encode ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let name = parts[1].trim();
            let s = oop.dicts.get(name).map(|d| {
                let mut keys: Vec<&String> = d.keys().collect();
                keys.sort();
                keys.iter().map(|k| {
                    let v = &d[*k];
                    let ke: String = k.bytes().map(|b| if b.is_ascii_alphanumeric() || b == b'-' || b == b'_' || b == b'.' || b == b'~' { (b as char).to_string() } else { format!("%{:02X}", b) }).collect();
                    let ve: String = v.bytes().map(|b| if b.is_ascii_alphanumeric() || b == b'-' || b == b'_' || b == b'.' || b == b'~' { (b as char).to_string() } else { format!("%{:02X}", b) }).collect();
                    format!("{}={}", ke, ve)
                }).collect::<Vec<_>>().join("&")
            }).unwrap_or_default();
            oop.string_vars.insert(var, s);
        }
        return true;
    }

    if line == "clear_to_eol" { print!("\x1b[K"); let _ = io::stdout().flush(); return true; }
    if line == "scroll_up" { print!("\x1b[S"); let _ = io::stdout().flush(); return true; }
    if line == "scroll_down" { print!("\x1b[T"); let _ = io::stdout().flush(); return true; }
    if line == "save_screen" { print!("\x1b[?47h"); let _ = io::stdout().flush(); return true; }
    if line == "restore_screen" { print!("\x1b[?47l"); let _ = io::stdout().flush(); return true; }
    if line == "alt_screen" { print!("\x1b[?1049h"); let _ = io::stdout().flush(); return true; }
    if line == "normal_screen" { print!("\x1b[?1049l"); let _ = io::stdout().flush(); return true; }

    if let Some(rest) = line.strip_prefix("db_insert ") {
        let args = split_args(rest);
        if args.len() >= 3 {
            let alias = resolve_arg(&args[0], vars, oop);
            let table = resolve_arg(&args[1], vars, oop);
            let values: Vec<String> = args.iter().skip(2).map(|a| {
                let v = resolve_arg(a, vars, oop);
                format!("'{}'", v.replace('\'', "''"))
            }).collect();
            let sql = format!("INSERT INTO {} VALUES ({})", table, values.join(","));
            if let Some(conn) = oop.db_connections.get(&alias) {
                let _ = conn.execute(&sql, []);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("db_exists ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let alias = resolve_arg(&args[0], vars, oop);
            let table = resolve_arg(&args[1], vars, oop);
            let exists: i64 = if let Some(conn) = oop.db_connections.get(&alias) {
                conn.query_row(
                    "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=?",
                    [&table], |r| r.get(0)
                ).unwrap_or(0)
            } else { 0 };
            apply_return(vars, oop, result_var, Some(exists.to_string()));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("longest_common ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a: Vec<char> = resolve_arg(&args[0], vars, oop).chars().collect();
                let b: Vec<char> = resolve_arg(&args[1], vars, oop).chars().collect();
                let (m, n) = (a.len(), b.len());
                let mut dp = vec![vec![0usize; n+1]; m+1];
                let mut best = (0, 0);
                for i in 1..=m {
                    for j in 1..=n {
                        if a[i-1] == b[j-1] {
                            dp[i][j] = dp[i-1][j-1] + 1;
                            if dp[i][j] > best.0 { best = (dp[i][j], i); }
                        }
                    }
                }
                let s: String = a[best.1 - best.0..best.1].iter().collect();
                oop.string_vars.insert(var, s);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("normalize_path ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let p = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let np = p.canonicalize().unwrap_or(p);
            oop.string_vars.insert(var, np.to_string_lossy().to_string());
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("find_files ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let path = expand_path(&resolve_arg(&args[0], vars, oop));
                let ext = resolve_arg(&args[1], vars, oop);
                let mut out: Vec<String> = Vec::new();
                if let Ok(rd) = fs::read_dir(&path) {
                    for e in rd.flatten() {
                        if let Some(n) = e.file_name().to_str() {
                            if n.ends_with(&ext) { out.push(n.to_string()); }
                        }
                    }
                }
                out.sort();
                oop.lists.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_replace ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let path = expand_path(&resolve_arg(&args[0], vars, oop));
            let from = resolve_arg(&args[1], vars, oop);
            let to = resolve_arg(&args[2], vars, oop);
            if let Ok(s) = fs::read_to_string(&path) {
                let _ = fs::write(&path, s.replace(&from, &to));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("env_dict ") {
        let dest = rest.trim().to_string();
        let d: HashMap<String, String> = env::vars().collect();
        oop.dicts.insert(dest, d);
        return true;
    }

    if let Some(rest) = line.strip_prefix("mac_format ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let s = resolve_arg(parts[1].trim(), vars, oop);
            let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_hexdigit()).collect();
            if chars.len() >= 12 {
                let mut out = String::new();
                for i in 0..6 {
                    if i > 0 { out.push(':'); }
                    out.push(chars[i*2]); out.push(chars[i*2+1]);
                }
                oop.string_vars.insert(var, out.to_lowercase());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("random_mac ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let mut rng = rand::thread_rng();
        let mac: String = (0..6).map(|i| {
            let n: u8 = rand::Rng::gen_range(&mut rng, 0..=255);
            if i == 0 { format!("{:02x}", n & 0xfe) } else { format!("{:02x}", n) }
        }).collect::<Vec<_>>().join(":");
        oop.string_vars.insert(var, mac);
        return true;
    }

    if let Some(rest) = line.strip_prefix("json_get_path ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let raw = resolve_arg(&args[0], vars, oop);
                let path = resolve_arg(&args[1], vars, oop);
                match serde_json::from_str::<serde_json::Value>(&raw) {
                    Ok(mut v) => {
                        for seg in path.split('.') {
                            v = if let Ok(i) = seg.parse::<usize>() {
                                v.get(i).cloned().unwrap_or(serde_json::Value::Null)
                            } else {
                                v.get(seg).cloned().unwrap_or(serde_json::Value::Null)
                            };
                        }
                        oop.string_vars.insert(var, json_to_str(&v));
                    }
                    Err(e) => { oop.error_message = Some(format!("json_get_path: {}", e)); }
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("clamp_int ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 3 {
                let n: i64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0);
                let lo: i64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
                let hi: i64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0);
                vars.insert(var, n.max(lo).min(hi));
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("normalize ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 3 {
                let x: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let lo: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                let hi: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(1.0);
                let range = (hi - lo).max(1e-12);
                oop.string_vars.insert(var, ((x - lo) / range).to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("map_range ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 5 {
                let x: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let in_lo: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                let in_hi: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(1.0);
                let out_lo: f64 = resolve_arg(&args[3], vars, oop).parse().unwrap_or(0.0);
                let out_hi: f64 = resolve_arg(&args[4], vars, oop).parse().unwrap_or(1.0);
                let in_range = (in_hi - in_lo).max(1e-12);
                let v = (x - in_lo) / in_range * (out_hi - out_lo) + out_lo;
                oop.string_vars.insert(var, v.to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("percentile_25 ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let mut nums: Vec<f64> = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
        nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
        let v = if nums.is_empty() { 0.0 } else { nums[nums.len() / 4] };
        apply_return(vars, oop, result_var, Some(v.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("percentile_75 ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let mut nums: Vec<f64> = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
        nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
        let v = if nums.is_empty() { 0.0 } else { nums[(nums.len() * 3) / 4] };
        apply_return(vars, oop, result_var, Some(v.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("iqr ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let mut nums: Vec<f64> = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
        nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
        let v = if nums.len() < 2 { 0.0 } else { nums[(nums.len() * 3) / 4] - nums[nums.len() / 4] };
        apply_return(vars, oop, result_var, Some(v.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("range_stat ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let nums: Vec<f64> = oop.lists.get(name).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
        let v = if nums.is_empty() { 0.0 } else {
            let mn = nums.iter().cloned().fold(f64::INFINITY, f64::min);
            let mx = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
            mx - mn
        };
        apply_return(vars, oop, result_var, Some(v.to_string()));
        return true;
    }

    if let Some(rest) = line.strip_prefix("lzip ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() >= 2 {
                let a: Vec<String> = oop.lists.get(args[0].trim()).cloned().unwrap_or_default();
                let b: Vec<String> = oop.lists.get(args[1].trim()).cloned().unwrap_or_default();
                let sep = if args.len() >= 3 { resolve_arg(&args[2], vars, oop) } else { "|".to_string() };
                let out: Vec<String> = a.iter().zip(b.iter()).map(|(x, y)| format!("{}{}{}", x, sep, y)).collect();
                oop.lists.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcumsum ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            let l: Vec<f64> = oop.lists.get(src).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
            let mut acc = 0.0;
            let out: Vec<String> = l.iter().map(|x| { acc += x; if acc.fract() == 0.0 { (acc as i64).to_string() } else { acc.to_string() } }).collect();
            oop.lists.insert(dest, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lcumprod ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let src = parts[1].trim();
            let l: Vec<f64> = oop.lists.get(src).map(|l| l.iter().filter_map(|x| x.parse::<f64>().ok()).collect()).unwrap_or_default();
            let mut acc = 1.0;
            let out: Vec<String> = l.iter().map(|x| { acc *= x; if acc.fract() == 0.0 { (acc as i64).to_string() } else { acc.to_string() } }).collect();
            oop.lists.insert(dest, out);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("lpartition ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let src = args[0].trim();
                let n: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1).max(1);
                let l: Vec<String> = oop.lists.get(src).cloned().unwrap_or_default();
                let out: Vec<String> = l.chunks(n).map(|c| c.join(",")).collect();
                oop.lists.insert(dest, out);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("months_between ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a = resolve_arg(&args[0], vars, oop);
                let b = resolve_arg(&args[1], vars, oop);
                let pa = chrono::NaiveDate::parse_from_str(&a, "%Y-%m-%d").ok();
                let pb = chrono::NaiveDate::parse_from_str(&b, "%Y-%m-%d").ok();
                let m = match (pa, pb) {
                    (Some(a), Some(b)) => ((b - a).num_days() / 30) as i64,
                    _ => 0,
                };
                vars.insert(var, m);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("years_between ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let a = resolve_arg(&args[0], vars, oop);
                let b = resolve_arg(&args[1], vars, oop);
                let pa = chrono::NaiveDate::parse_from_str(&a, "%Y-%m-%d").ok();
                let pb = chrono::NaiveDate::parse_from_str(&b, "%Y-%m-%d").ok();
                let y = match (pa, pb) {
                    (Some(a), Some(b)) => ((b - a).num_days() / 365) as i64,
                    _ => 0,
                };
                vars.insert(var, y);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("regex_capture ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let pat = resolve_arg(&args[0], vars, oop);
                let text = resolve_arg(&args[1], vars, oop);
                if let Ok(re) = regex::Regex::new(&pat) {
                    let caps: Vec<String> = re.captures(&text).map(|c| c.iter().skip(1).filter_map(|m| m.map(|x| x.as_str().to_string())).collect()).unwrap_or_default();
                    oop.lists.insert(dest, caps);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("regex_all_matches ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let dest = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 2 {
                let pat = resolve_arg(&args[0], vars, oop);
                let text = resolve_arg(&args[1], vars, oop);
                if let Ok(re) = regex::Regex::new(&pat) {
                    let matches: Vec<String> = re.find_iter(&text).map(|m| m.as_str().to_string()).collect();
                    oop.lists.insert(dest, matches);
                }
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("file_size_human ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let path = expand_path(&resolve_arg(parts[1].trim(), vars, oop));
            let n = fs::metadata(&path).map(|m| m.len() as f64).unwrap_or(0.0);
            let units = ["B", "KB", "MB", "GB", "TB"];
            let mut size = n; let mut unit = 0;
            while size >= 1024.0 && unit < units.len() - 1 { size /= 1024.0; unit += 1; }
            oop.string_vars.insert(var, format!("{:.2} {}", size, units[unit]));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ldiff_lists ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a: Vec<String> = oop.lists.get(args[0].trim()).cloned().unwrap_or_default();
            let b: Vec<String> = oop.lists.get(args[1].trim()).cloned().unwrap_or_default();
            apply_return(vars, oop, result_var, Some(if a == b { "0" } else { "1" }.to_string()));
        }
        return true;
    }

    // ===== ASYNC TASKS =====
    if let Some(rest) = line.strip_prefix("async ") {
        let args: Vec<&str> = rest.splitn(2, char::is_whitespace).collect();
        if args.len() >= 1 {
            let name = args[0].trim().to_string();
            let body = if args.len() >= 2 { resolve_arg(args[1].trim(), vars, oop) } else { String::new() };
            let handle = std::thread::spawn(move || -> String {
                let output = std::process::Command::new("sh").arg("-c").arg(&body).output();
                output.map(|o| String::from_utf8_lossy(&o.stdout).trim_end().to_string()).unwrap_or_default()
            });
            // Store the result placeholder so await can pick it up
            oop.string_vars.insert(format!("__async_{}", name), "pending".to_string());
            // Block-ish: spawn but wait briefly to allow short tasks to finish
            let result = handle.join().unwrap_or_default();
            oop.string_vars.insert(format!("__async_{}", name), result);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("await ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let name = parts[0].trim();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let v = oop.string_vars.get(&format!("__async_{}", name)).cloned();
        apply_return(vars, oop, result_var, v);
        return true;
    }

    // ===== PIPE OPERATOR =====
    if line.contains(" |> ") {
        let parts: Vec<&str> = line.split(" |> ").collect();
        if parts.len() >= 2 {
            // First part is the starting value or expression
            let mut current = parts[0].trim().to_string();
            // Each subsequent part is a function name to call with current as arg
            for f in parts.iter().skip(1) {
                let fname = f.trim();
                let result_var = format!("__pipe_{}", oop.string_vars.len());
                let cmd = format!("call {} {} -> {}", fname, current, result_var);
                if !execute(&cmd, vars, server_cfg, oop) { return false; }
                current = oop.string_vars.get(&result_var).cloned()
                    .or_else(|| vars.get(&result_var).map(|v| v.to_string()))
                    .unwrap_or_default();
                oop.string_vars.remove(&result_var);
                vars.remove(&result_var);
            }
            println!("{}", current);
        }
        return true;
    }

    // ===== DECORATORS =====
    if let Some(rest) = line.strip_prefix("@timed ") {
        // @timed call funcname args
        // Times the next call and prints elapsed
        if let Some(call_rest) = rest.strip_prefix("call ") {
            let label = call_rest.split_whitespace().next().unwrap_or("?").to_string();
            let start = std::time::Instant::now();
            let actual_cmd = format!("call {}", call_rest);
            let ok = execute(&actual_cmd, vars, server_cfg, oop);
            let elapsed = start.elapsed();
            println!("\x1b[2m[timed] {} took {:?}\x1b[0m", label, elapsed);
            return ok;
        }
        return execute(rest, vars, server_cfg, oop);
    }

    if let Some(rest) = line.strip_prefix("@logged ") {
        println!("\x1b[36m[call]\x1b[0m {}", rest);
        return execute(rest, vars, server_cfg, oop);
    }

    if let Some(rest) = line.strip_prefix("@once ") {
        // @once name <command> — only runs the first time within this session
        let parts: Vec<&str> = rest.splitn(2, char::is_whitespace).collect();
        if parts.len() == 2 {
            let key = format!("__once_{}", parts[0]);
            if oop.string_vars.contains_key(&key) {
                return true;
            }
            oop.string_vars.insert(key, "done".to_string());
            return execute(parts[1], vars, server_cfg, oop);
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("@retry ") {
        // @retry N <command>
        let parts: Vec<&str> = rest.splitn(2, char::is_whitespace).collect();
        if parts.len() == 2 {
            let n: i64 = parts[0].parse().unwrap_or(1);
            for i in 0..n {
                let before = oop.error_message.take();
                if !execute(parts[1], vars, server_cfg, oop) { return false; }
                if oop.error_message.is_none() {
                    oop.error_message = before;
                    return true;
                }
                if i + 1 < n {
                    println!("\x1b[33m[retry]\x1b[0m attempt {} failed, retrying...", i + 1);
                }
            }
        }
        return true;
    }

    // ===== CLOSURES (lambda) =====
    if let Some(rest) = line.strip_prefix("lambda ") {
        // lambda name(params) body  --  define inline as anonymous function
        let parts: Vec<&str> = rest.splitn(2, '(').collect();
        if parts.len() == 2 {
            let name = parts[0].trim().to_string();
            let rest2: Vec<&str> = parts[1].splitn(2, ')').collect();
            if rest2.len() == 2 {
                let params: Vec<String> = rest2[0].split(',').map(|s| s.trim().to_string()).filter(|s| !s.is_empty()).collect();
                let body_str = rest2[1].trim().to_string();
                oop.functions.insert(name, FuncDef { params, body: vec![body_str] });
            }
        }
        return true;
    }

    // ===== PATTERN MATCHING (simple) =====
    if let Some(rest) = line.strip_prefix("matchv ") {
        // matchv value case1 result1 case2 result2 ... default value -> var
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() >= 3 {
            let value = resolve_arg(&args[0], vars, oop);
            let mut matched: Option<String> = None;
            let mut i = 1;
            while i + 1 < args.len() {
                let case = resolve_arg(&args[i], vars, oop);
                if case == value || case == "_" {
                    matched = Some(resolve_arg(&args[i + 1], vars, oop));
                    break;
                }
                i += 2;
            }
            if matched.is_none() && args.len() % 2 == 0 {
                matched = Some(resolve_arg(&args[args.len() - 1], vars, oop));
            }
            apply_return(vars, oop, result_var, matched);
        }
        return true;
    }

    // ===== WEBSOCKET stub (placeholder for future real impl) =====
    if let Some(rest) = line.strip_prefix("ws_broadcast ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        // Store in shared dict for retrieval by HTTP route handlers
        let key = format!("__ws_msg_{}", oop.string_vars.len());
        oop.string_vars.insert(key.clone(), msg.clone());
        oop.string_vars.insert("__ws_last__".to_string(), msg);
        return true;
    }

    if let Some(rest) = line.strip_prefix("ws_last ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let last = oop.string_vars.get("__ws_last__").cloned().unwrap_or_default();
        oop.string_vars.insert(var, last);
        return true;
    }

    // ===== REAL WEBSOCKET SERVER =====
    if let Some(rest) = line.strip_prefix("ws_serve ") {
        let port: u16 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(3030);
        let state = ws_global();
        let bind = format!("0.0.0.0:{}", port);
        let listener = match TcpListener::bind(&bind) {
            Ok(l) => l,
            Err(e) => {
                println!("ws_serve: bind failed: {}", e);
                return true;
            }
        };
        println!("\x1b[36m[ws]\x1b[0m listening on ws://0.0.0.0:{}", port);
        let clients = state.clients.clone();
        let incoming = state.incoming.clone();
        thread::spawn(move || {
            for stream in listener.incoming().flatten() {
                let clients2 = clients.clone();
                let incoming2 = incoming.clone();
                thread::spawn(move || {
                    let ws = match tungstenite::accept(stream) {
                        Ok(ws) => ws,
                        Err(_) => return,
                    };
                    let ws_arc = Arc::new(Mutex::new(ws));
                    clients2.lock().unwrap().push(ws_arc.clone());
                    loop {
                        let msg = {
                            let mut w = ws_arc.lock().unwrap();
                            w.read()
                        };
                        match msg {
                            Ok(tungstenite::Message::Text(t)) => {
                                incoming2.lock().unwrap().push_back(t.to_string());
                            }
                            Ok(tungstenite::Message::Close(_)) | Err(_) => {
                                clients2
                                    .lock()
                                    .unwrap()
                                    .retain(|c| !Arc::ptr_eq(c, &ws_arc));
                                break;
                            }
                            _ => {}
                        }
                    }
                });
            }
        });
        return true;
    }

    if let Some(rest) = line.strip_prefix("ws_send ") {
        let msg = resolve_arg(rest.trim(), vars, oop);
        let state = ws_global();
        let clients: Vec<_> = state.clients.lock().unwrap().clone();
        let mut sent = 0;
        for c in clients {
            if let Ok(mut w) = c.lock() {
                if w.send(tungstenite::Message::Text(msg.clone().into())).is_ok() {
                    sent += 1;
                }
            }
        }
        oop.string_vars
            .insert("__ws_last__".to_string(), msg);
        vars.insert("__ws_sent_count__".to_string(), sent);
        return true;
    }

    if let Some(rest) = line.strip_prefix("ws_clients ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let n = ws_global().clients.lock().unwrap().len() as i64;
        vars.insert(var, n);
        return true;
    }

    if let Some(rest) = line.strip_prefix("ws_recv ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let msg = ws_global().incoming.lock().unwrap().pop_front();
        apply_return(vars, oop, result_var, msg);
        return true;
    }

    if line == "ws_close_all" {
        let clients: Vec<_> = ws_global().clients.lock().unwrap().drain(..).collect();
        for c in clients {
            if let Ok(mut w) = c.lock() {
                let _ = w.close(None);
            }
        }
        return true;
    }

    // ===== BROWSER-WINDOW GUI =====
    // gui_show "<html>" — opens default browser to display the HTML
    if let Some(rest) = line.strip_prefix("gui_show ") {
        let html = resolve_arg(rest.trim(), vars, oop);
        let tmp = env::temp_dir().join(format!("ayaan_gui_{}.html", std::process::id()));
        if fs::write(&tmp, &html).is_ok() {
            let path = tmp.to_string_lossy().to_string();
            let opener = if cfg!(target_os = "macos") {
                ("open", path.clone())
            } else if cfg!(target_os = "windows") {
                ("cmd", format!("/c start {}", path))
            } else {
                ("xdg-open", path.clone())
            };
            let _ = Command::new(opener.0).arg(opener.1).spawn();
            println!("\x1b[36m[gui]\x1b[0m opened {}", tmp.display());
        }
        return true;
    }

    // ===== NATIVE GUI WINDOW (minifb) =====
    // gui_native title width height — open a real native window
    if let Some(rest) = line.strip_prefix("gui_native ") {
        let args = split_args(rest);
        if args.len() >= 3 {
            let title = resolve_arg(&args[0], vars, oop);
            let w: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(640);
            let h: usize = resolve_arg(&args[2], vars, oop).parse().unwrap_or(480);
            // Suppress minifb's Wayland decoration warning by redirecting
            // stderr to /dev/null for just the window creation call.
            let win = suppress_stderr(|| minifb::Window::new(
                &title,
                w,
                h,
                minifb::WindowOptions { resize: false, ..Default::default() },
            ));
            match win {
                Ok(window) => {
                    GUI_WIN.with(|w| *w.borrow_mut() = Some(window));
                    GUI_BUF.with(|b| *b.borrow_mut() = vec![0u32; w * h]);
                    GUI_W.with(|c| c.set(w));
                    GUI_H.with(|c| c.set(h));
                }
                Err(e) => println!("gui_native: failed to open window: {}", e),
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_clear ") {
        let color = color_to_u32(&resolve_arg(rest.trim(), vars, oop));
        GUI_BUF.with(|b| {
            let mut buf = b.borrow_mut();
            for p in buf.iter_mut() { *p = color; }
        });
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_pixel ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let x: i64 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y: i64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let color = color_to_u32(&resolve_arg(&args[2], vars, oop));
            let w = GUI_W.with(|c| c.get());
            let h = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| gui_put_pixel(&mut b.borrow_mut(), w, h, x, y, color));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_fill_rect ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let x: i64 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y: i64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let w: i64 = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let h: i64 = parse_i64_loose(&resolve_arg(&args[3], vars, oop));
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                for dy in 0..h {
                    for dx in 0..w {
                        gui_put_pixel(&mut buf, bw, bh, x + dx, y + dy, color);
                    }
                }
            });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_rect ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let x: i64 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y: i64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let w: i64 = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let h: i64 = parse_i64_loose(&resolve_arg(&args[3], vars, oop));
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                for dx in 0..w {
                    gui_put_pixel(&mut buf, bw, bh, x + dx, y, color);
                    gui_put_pixel(&mut buf, bw, bh, x + dx, y + h - 1, color);
                }
                for dy in 0..h {
                    gui_put_pixel(&mut buf, bw, bh, x, y + dy, color);
                    gui_put_pixel(&mut buf, bw, bh, x + w - 1, y + dy, color);
                }
            });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_line ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let mut x0: i64 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let mut y0: i64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let x1: i64 = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let y1: i64 = parse_i64_loose(&resolve_arg(&args[3], vars, oop));
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            // Bresenham
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                let dx = (x1 - x0).abs();
                let dy = -(y1 - y0).abs();
                let sx = if x0 < x1 { 1 } else { -1 };
                let sy = if y0 < y1 { 1 } else { -1 };
                let mut err = dx + dy;
                loop {
                    gui_put_pixel(&mut buf, bw, bh, x0, y0, color);
                    if x0 == x1 && y0 == y1 { break; }
                    let e2 = 2 * err;
                    if e2 >= dy { err += dy; x0 += sx; }
                    if e2 <= dx { err += dx; y0 += sy; }
                }
            });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_circle ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let cx: i64 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let cy: i64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let r: i64 = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let color = color_to_u32(&resolve_arg(&args[3], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                let mut x = r; let mut y: i64 = 0; let mut err: i64 = 0;
                while x >= y {
                    gui_put_pixel(&mut buf, bw, bh, cx + x, cy + y, color);
                    gui_put_pixel(&mut buf, bw, bh, cx + y, cy + x, color);
                    gui_put_pixel(&mut buf, bw, bh, cx - y, cy + x, color);
                    gui_put_pixel(&mut buf, bw, bh, cx - x, cy + y, color);
                    gui_put_pixel(&mut buf, bw, bh, cx - x, cy - y, color);
                    gui_put_pixel(&mut buf, bw, bh, cx - y, cy - x, color);
                    gui_put_pixel(&mut buf, bw, bh, cx + y, cy - x, color);
                    gui_put_pixel(&mut buf, bw, bh, cx + x, cy - y, color);
                    y += 1;
                    err += 1 + 2 * y;
                    if 2 * (err - x) + 1 > 0 { x -= 1; err += 1 - 2 * x; }
                }
            });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_fill_circle ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let cx: i64 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let cy: i64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let r: i64 = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let color = color_to_u32(&resolve_arg(&args[3], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                for dy in -r..=r {
                    for dx in -r..=r {
                        if dx*dx + dy*dy <= r*r {
                            gui_put_pixel(&mut buf, bw, bh, cx + dx, cy + dy, color);
                        }
                    }
                }
            });
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_text ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let x: i64 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y: i64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let text = resolve_arg(&args[2], vars, oop);
            let color = color_to_u32(&resolve_arg(&args[3], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| gui_draw_text_at(&mut b.borrow_mut(), bw, bh, x, y, &text, color));
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_fps ") {
        let n: u32 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(60).max(1);
        GUI_FPS.with(|c| c.set(n));
        return true;
    }

    if line == "gui_update" {
        // FPS cap
        let target = GUI_FPS.with(|c| c.get());
        let target_us: u128 = 1_000_000 / target as u128;
        let last = GUI_LAST_FRAME.with(|c| c.get());
        if let Some(last) = last {
            let elapsed = last.elapsed().as_micros();
            if elapsed < target_us {
                std::thread::sleep(Duration::from_micros((target_us - elapsed) as u64));
            }
        }
        GUI_LAST_FRAME.with(|c| c.set(Some(std::time::Instant::now())));

        let w = GUI_W.with(|c| c.get());
        let h = GUI_H.with(|c| c.get());
        GUI_WIN.with(|win| {
            if let Some(window) = win.borrow_mut().as_mut() {
                GUI_BUF.with(|b| {
                    let _ = window.update_with_buffer(&b.borrow(), w, h);
                });
            }
        });
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_open ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        let var = if parts.len() == 2 { parts[0].trim().to_string() } else { rest.trim().to_string() };
        let open = GUI_WIN.with(|win| {
            win.borrow().as_ref().map(|w| w.is_open()).unwrap_or(false)
        });
        vars.insert(var, if open { 1 } else { 0 });
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_mouse_x ") {
        let var = rest.trim().to_string();
        let x: i64 = GUI_WIN.with(|win| {
            win.borrow().as_ref()
                .and_then(|w| w.get_mouse_pos(minifb::MouseMode::Clamp))
                .map(|(x, _)| x as i64)
                .unwrap_or(0)
        });
        vars.insert(var, x);
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_mouse_y ") {
        let var = rest.trim().to_string();
        let y: i64 = GUI_WIN.with(|win| {
            win.borrow().as_ref()
                .and_then(|w| w.get_mouse_pos(minifb::MouseMode::Clamp))
                .map(|(_, y)| y as i64)
                .unwrap_or(0)
        });
        vars.insert(var, y);
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_mouse_down ") {
        let var = rest.trim().to_string();
        let down: i64 = GUI_WIN.with(|win| {
            win.borrow().as_ref()
                .map(|w| if w.get_mouse_down(minifb::MouseButton::Left) { 1 } else { 0 })
                .unwrap_or(0)
        });
        vars.insert(var, down);
        return true;
    }

    if let Some(rest) = line.strip_prefix("gui_key_down ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let key = resolve_arg(parts[0].trim(), vars, oop);
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let pressed: i64 = GUI_WIN.with(|win| {
            let w = win.borrow();
            let w = match w.as_ref() { Some(w) => w, None => return 0 };
            let k = match parse_minifb_key(&key) {
                Some(k) => k,
                None => return 0,
            };
            if w.is_key_down(k) { 1 } else { 0 }
        });
        apply_return(vars, oop, result_var, Some(pressed.to_string()));
        return true;
    }

    if line == "gui_close" {
        // Wrap the Window drop in suppress_stderr — minifb's Wayland backend
        // leaks "wl_buffer/wl_shm_pool destroyed while still attached" warnings
        // straight to stdout during teardown. Cosmetic only, but very noisy.
        suppress_stderr(|| {
            GUI_WIN.with(|w| *w.borrow_mut() = None);
        });
        GUI_BUF.with(|b| b.borrow_mut().clear());
        return true;
    }

    // ===== EXTENDED NATIVE GUI =====

    // gui_fill_triangle x1 y1 x2 y2 x3 y3 color
    if let Some(rest) = line.strip_prefix("gui_fill_triangle ") {
        let args = split_args(rest);
        if args.len() == 7 {
            let mut x1 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let mut y1 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let mut x2 = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let mut y2 = parse_i64_loose(&resolve_arg(&args[3], vars, oop));
            let mut x3 = parse_i64_loose(&resolve_arg(&args[4], vars, oop));
            let mut y3 = parse_i64_loose(&resolve_arg(&args[5], vars, oop));
            let color = color_to_u32(&resolve_arg(&args[6], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            if y1 > y2 { std::mem::swap(&mut x1, &mut x2); std::mem::swap(&mut y1, &mut y2); }
            if y1 > y3 { std::mem::swap(&mut x1, &mut x3); std::mem::swap(&mut y1, &mut y3); }
            if y2 > y3 { std::mem::swap(&mut x2, &mut x3); std::mem::swap(&mut y2, &mut y3); }
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                let total = y3 - y1;
                if total > 0 {
                    for y in y1..=y3 {
                        let second = y > y2 || y2 == y1;
                        let seg_h = if second { y3 - y2 } else { y2 - y1 };
                        if seg_h == 0 { continue; }
                        let alpha = (y - y1) as f64 / total as f64;
                        let beta = (y - (if second { y2 } else { y1 })) as f64 / seg_h as f64;
                        let ax = x1 as f64 + (x3 - x1) as f64 * alpha;
                        let bx = if second {
                            x2 as f64 + (x3 - x2) as f64 * beta
                        } else {
                            x1 as f64 + (x2 - x1) as f64 * beta
                        };
                        let (lo, hi) = if ax < bx { (ax as i64, bx as i64) } else { (bx as i64, ax as i64) };
                        for x in lo..=hi {
                            gui_put_pixel(&mut buf, bw, bh, x, y, color);
                        }
                    }
                }
            });
        }
        return true;
    }

    // gui_text_big x y "msg" "color" scale
    if let Some(rest) = line.strip_prefix("gui_text_big ") {
        let args = split_args(rest);
        if args.len() >= 5 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let text = resolve_arg(&args[2], vars, oop);
            let color = color_to_u32(&resolve_arg(&args[3], vars, oop));
            let scale = parse_i64_loose(&resolve_arg(&args[4], vars, oop)).max(1);
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                let mut cx = x;
                for ch in text.chars() {
                    let g = font_5x7(ch);
                    for (row, byte) in g.iter().enumerate() {
                        for col in 0..5 {
                            if byte & (1 << (4 - col)) != 0 {
                                for sx in 0..scale {
                                    for sy in 0..scale {
                                        gui_put_pixel(
                                            &mut buf, bw, bh,
                                            cx + col as i64 * scale + sx,
                                            y + row as i64 * scale + sy,
                                            color,
                                        );
                                    }
                                }
                            }
                        }
                    }
                    cx += 6 * scale;
                }
            });
        }
        return true;
    }

    // gui_get_pixel x y -> var  (returns 0xRRGGBB packed as int)
    if let Some(rest) = line.strip_prefix("gui_get_pixel ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let w = GUI_W.with(|c| c.get());
            let h = GUI_H.with(|c| c.get());
            let color = if x < 0 || y < 0 || x as usize >= w || y as usize >= h {
                0u32
            } else {
                GUI_BUF.with(|b| b.borrow()[y as usize * w + x as usize])
            };
            apply_return(vars, oop, result_var, Some(color.to_string()));
        }
        return true;
    }

    // gui_screenshot "path.ppm" — save framebuffer as PPM
    if let Some(rest) = line.strip_prefix("gui_screenshot ") {
        let path = expand_path(&resolve_arg(rest.trim(), vars, oop));
        let w = GUI_W.with(|c| c.get());
        let h = GUI_H.with(|c| c.get());
        let mut data: Vec<u8> = Vec::with_capacity(w * h * 3 + 64);
        data.extend_from_slice(format!("P6\n{} {}\n255\n", w, h).as_bytes());
        GUI_BUF.with(|b| {
            let buf = b.borrow();
            for &px in buf.iter() {
                data.push(((px >> 16) & 0xFF) as u8);
                data.push(((px >> 8) & 0xFF) as u8);
                data.push((px & 0xFF) as u8);
            }
        });
        match std::fs::write(&path, data) {
            Ok(_) => println!("\x1b[36m[gui]\x1b[0m saved {}", path.display()),
            Err(e) => println!("gui_screenshot failed: {}", e),
        }
        return true;
    }

    // gui_gradient_rect x y w h color1 color2 — vertical gradient
    if let Some(rest) = line.strip_prefix("gui_gradient_rect ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let w = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let h = parse_i64_loose(&resolve_arg(&args[3], vars, oop));
            let c1 = color_to_u32(&resolve_arg(&args[4], vars, oop));
            let c2 = color_to_u32(&resolve_arg(&args[5], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            let r1 = ((c1 >> 16) & 0xFF) as i64;
            let g1 = ((c1 >> 8) & 0xFF) as i64;
            let b1 = (c1 & 0xFF) as i64;
            let r2 = ((c2 >> 16) & 0xFF) as i64;
            let g2 = ((c2 >> 8) & 0xFF) as i64;
            let b2 = (c2 & 0xFF) as i64;
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                for dy in 0..h {
                    let t = if h <= 1 { 0.0 } else { dy as f64 / (h - 1) as f64 };
                    let r = (r1 as f64 + (r2 - r1) as f64 * t) as u32;
                    let g = (g1 as f64 + (g2 - g1) as f64 * t) as u32;
                    let b3 = (b1 as f64 + (b2 - b1) as f64 * t) as u32;
                    let color = (r << 16) | (g << 8) | b3;
                    for dx in 0..w {
                        gui_put_pixel(&mut buf, bw, bh, x + dx, y + dy, color);
                    }
                }
            });
        }
        return true;
    }

    // gui_alpha_pixel x y "color" alpha(0-255)
    if let Some(rest) = line.strip_prefix("gui_alpha_pixel ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let new_c = color_to_u32(&resolve_arg(&args[2], vars, oop));
            let alpha = parse_i64_loose(&resolve_arg(&args[3], vars, oop)).clamp(0, 255) as u32;
            let w = GUI_W.with(|c| c.get());
            let h = GUI_H.with(|c| c.get());
            if x >= 0 && y >= 0 && (x as usize) < w && (y as usize) < h {
                GUI_BUF.with(|b| {
                    let mut buf = b.borrow_mut();
                    let idx = y as usize * w + x as usize;
                    let old_c = buf[idx];
                    let inv = 255 - alpha;
                    let r = (((old_c >> 16) & 0xFF) * inv + ((new_c >> 16) & 0xFF) * alpha) / 255;
                    let g = (((old_c >> 8) & 0xFF) * inv + ((new_c >> 8) & 0xFF) * alpha) / 255;
                    let b3 = ((old_c & 0xFF) * inv + (new_c & 0xFF) * alpha) / 255;
                    buf[idx] = (r << 16) | (g << 8) | b3;
                });
            }
        }
        return true;
    }

    // gui_set_title "new title"
    if let Some(rest) = line.strip_prefix("gui_set_title ") {
        let title = resolve_arg(rest.trim(), vars, oop);
        GUI_WIN.with(|w| {
            if let Some(win) = w.borrow_mut().as_mut() {
                win.set_title(&title);
            }
        });
        return true;
    }

    // gui_window_w var
    if let Some(rest) = line.strip_prefix("gui_window_w ") {
        let var = rest.trim().to_string();
        vars.insert(var, GUI_W.with(|c| c.get() as i64));
        return true;
    }

    // gui_window_h var
    if let Some(rest) = line.strip_prefix("gui_window_h ") {
        let var = rest.trim().to_string();
        vars.insert(var, GUI_H.with(|c| c.get() as i64));
        return true;
    }

    // gui_mouse_wheel var (scroll delta-y since last call)
    if let Some(rest) = line.strip_prefix("gui_mouse_wheel ") {
        let var = rest.trim().to_string();
        let dy: i64 = GUI_WIN.with(|w| {
            w.borrow()
                .as_ref()
                .and_then(|win| win.get_scroll_wheel())
                .map(|(_, y)| y as i64)
                .unwrap_or(0)
        });
        vars.insert(var, dy);
        return true;
    }

    // gui_is_focused var
    if let Some(rest) = line.strip_prefix("gui_is_focused ") {
        let var = rest.trim().to_string();
        let focused: i64 = GUI_WIN.with(|w| {
            w.borrow_mut().as_mut().map(|win| if win.is_active() { 1 } else { 0 }).unwrap_or(0)
        });
        vars.insert(var, focused);
        return true;
    }

    // gui_polygon listname "color"  — draws polygon outline; list contains "x,y" strings
    if let Some(rest) = line.strip_prefix("gui_polygon ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim().trim_matches('"').to_string();
            let color = color_to_u32(&resolve_arg(&args[1], vars, oop));
            if let Some(points) = oop.lists.get(&name).cloned() {
                let pts: Vec<(i64, i64)> = points.iter().filter_map(|s| {
                    let mut sp = s.split(',');
                    let x: f64 = sp.next()?.trim().parse().ok()?;
                    let y: f64 = sp.next()?.trim().parse().ok()?;
                    Some((x as i64, y as i64))
                }).collect();
                if pts.len() >= 2 {
                    let bw = GUI_W.with(|c| c.get());
                    let bh = GUI_H.with(|c| c.get());
                    GUI_BUF.with(|b| {
                        let mut buf = b.borrow_mut();
                        for i in 0..pts.len() {
                            let (mut x0, mut y0) = pts[i];
                            let (x1t, y1t) = pts[(i + 1) % pts.len()];
                            let dx = (x1t - x0).abs();
                            let dy = -(y1t - y0).abs();
                            let sx = if x0 < x1t { 1i64 } else { -1 };
                            let sy = if y0 < y1t { 1i64 } else { -1 };
                            let mut err = dx + dy;
                            loop {
                                gui_put_pixel(&mut buf, bw, bh, x0, y0, color);
                                if x0 == x1t && y0 == y1t { break; }
                                let e2 = 2 * err;
                                if e2 >= dy { err += dy; x0 += sx; }
                                if e2 <= dx { err += dx; y0 += sy; }
                            }
                        }
                    });
                }
            }
        }
        return true;
    }

    // gui_blit_ppm x y "path"  — draws a P6 binary PPM image at (x,y)
    if let Some(rest) = line.strip_prefix("gui_blit_ppm ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let path = expand_path(&resolve_arg(&args[2], vars, oop));
            if let Ok(data) = std::fs::read(&path) {
                let mut i = 0;
                let mut tokens: Vec<String> = Vec::new();
                while tokens.len() < 4 && i < data.len() {
                    while i < data.len() && (data[i] == b'\n' || data[i] == b' ' || data[i] == b'\r' || data[i] == b'\t') { i += 1; }
                    if i < data.len() && data[i] == b'#' {
                        while i < data.len() && data[i] != b'\n' { i += 1; }
                        continue;
                    }
                    let s = i;
                    while i < data.len() && data[i] != b'\n' && data[i] != b' ' && data[i] != b'\r' && data[i] != b'\t' { i += 1; }
                    if s < i { tokens.push(String::from_utf8_lossy(&data[s..i]).to_string()); }
                }
                if tokens.len() >= 4 && tokens[0] == "P6" {
                    let img_w: usize = tokens[1].parse().unwrap_or(0);
                    let img_h: usize = tokens[2].parse().unwrap_or(0);
                    let pixels = if i < data.len() { &data[i + 1..] } else { &[][..] };
                    let bw = GUI_W.with(|c| c.get());
                    let bh = GUI_H.with(|c| c.get());
                    GUI_BUF.with(|b| {
                        let mut buf = b.borrow_mut();
                        for py in 0..img_h {
                            for px in 0..img_w {
                                let pi = (py * img_w + px) * 3;
                                if pi + 2 >= pixels.len() { break; }
                                let color = ((pixels[pi] as u32) << 16) | ((pixels[pi+1] as u32) << 8) | (pixels[pi+2] as u32);
                                gui_put_pixel(&mut buf, bw, bh, x + px as i64, y + py as i64, color);
                            }
                        }
                    });
                }
            }
        }
        return true;
    }

    // gui_clear_rect x y w h
    if let Some(rest) = line.strip_prefix("gui_clear_rect ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let w = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let h = parse_i64_loose(&resolve_arg(&args[3], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                for dy in 0..h {
                    for dx in 0..w {
                        gui_put_pixel(&mut buf, bw, bh, x + dx, y + dy, 0);
                    }
                }
            });
        }
        return true;
    }

    // gui_ellipse cx cy rx ry "color"  — filled ellipse
    if let Some(rest) = line.strip_prefix("gui_ellipse ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let cx = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let cy = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let rx = parse_i64_loose(&resolve_arg(&args[2], vars, oop)).max(0);
            let ry = parse_i64_loose(&resolve_arg(&args[3], vars, oop)).max(0);
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                if rx == 0 || ry == 0 { return; }
                for dy in -ry..=ry {
                    let dyn_norm = dy as f64 / ry as f64;
                    let x_range = (rx as f64 * (1.0 - dyn_norm * dyn_norm).max(0.0).sqrt()) as i64;
                    for dx in -x_range..=x_range {
                        gui_put_pixel(&mut buf, bw, bh, cx + dx, cy + dy, color);
                    }
                }
            });
        }
        return true;
    }

    // gui_thick_line x0 y0 x1 y1 thickness "color"
    if let Some(rest) = line.strip_prefix("gui_thick_line ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let x0 = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y0 = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let x1 = parse_i64_loose(&resolve_arg(&args[2], vars, oop));
            let y1 = parse_i64_loose(&resolve_arg(&args[3], vars, oop));
            let thick = parse_i64_loose(&resolve_arg(&args[4], vars, oop)).max(1);
            let color = color_to_u32(&resolve_arg(&args[5], vars, oop));
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                let dx = (x1 - x0).abs();
                let dy = -(y1 - y0).abs();
                let sx = if x0 < x1 { 1i64 } else { -1 };
                let sy = if y0 < y1 { 1i64 } else { -1 };
                let mut err = dx + dy;
                let mut x = x0;
                let mut y = y0;
                let r = thick / 2;
                loop {
                    for ddy in -r..=r {
                        for ddx in -r..=r {
                            if ddx * ddx + ddy * ddy <= r * r {
                                gui_put_pixel(&mut buf, bw, bh, x + ddx, y + ddy, color);
                            }
                        }
                    }
                    if x == x1 && y == y1 { break; }
                    let e2 = 2 * err;
                    if e2 >= dy { err += dy; x += sx; }
                    if e2 <= dx { err += dx; y += sy; }
                }
            });
        }
        return true;
    }

    // gui_text_width "text" scale -> var
    if let Some(rest) = line.strip_prefix("gui_text_width ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() >= 1 {
            let text = resolve_arg(&args[0], vars, oop);
            let scale = if args.len() >= 2 {
                parse_i64_loose(&resolve_arg(&args[1], vars, oop)).max(1)
            } else { 1 };
            let width = text.chars().count() as i64 * 6 * scale;
            apply_return(vars, oop, result_var, Some(width.to_string()));
        }
        return true;
    }

    // ===== SMOOTH + 3D GRAPHICS COMMANDS =====

    // gui_aa_line x0 y0 x1 y1 color  — Wu's anti-aliased line
    if let Some(rest) = line.strip_prefix("gui_aa_line ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let x0: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let y0: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let x1: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let y1: f32 = resolve_arg(&args[3], vars, oop).parse().unwrap_or(0.0);
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            wu_line(x0, y0, x1, y1, color);
        }
        return true;
    }

    // gui_aa_circle cx cy r color  — anti-aliased circle outline
    if let Some(rest) = line.strip_prefix("gui_aa_circle ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let cx: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let cy: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let r: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let color = color_to_u32(&resolve_arg(&args[3], vars, oop));
            // sample N segments and Wu-line between them
            let n = ((r * 6.28).max(32.0)) as i32;
            let mut prev_x = cx + r;
            let mut prev_y = cy;
            for i in 1..=n {
                let a = (i as f32) * 6.2831853 / (n as f32);
                let nx = cx + r * a.cos();
                let ny = cy + r * a.sin();
                wu_line(prev_x, prev_y, nx, ny, color);
                prev_x = nx;
                prev_y = ny;
            }
        }
        return true;
    }

    // gui_shade_triangle x1 y1 c1 x2 y2 c2 x3 y3 c3 — Gouraud-shaded 2D triangle (no z-buffer)
    if let Some(rest) = line.strip_prefix("gui_shade_triangle ") {
        let args = split_args(rest);
        if args.len() == 9 {
            let mut get = |i: usize| -> f32 {
                resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0)
            };
            let x1 = get(0); let y1 = get(1);
            let c1 = color_to_u32(&resolve_arg(&args[2], vars, oop));
            let x2 = get(3); let y2 = get(4);
            let c2 = color_to_u32(&resolve_arg(&args[5], vars, oop));
            let x3 = get(6); let y3 = get(7);
            let c3 = color_to_u32(&resolve_arg(&args[8], vars, oop));
            let rgb = |c: u32| (((c >> 16) & 0xFF) as u8, ((c >> 8) & 0xFF) as u8, (c & 0xFF) as u8);
            // Place at depth=0 so z-buffer doesn't matter (use dummy buf if no z-buf)
            // Use a non-z-buffer version: temporarily plot with no depth test
            // Simpler: ensure z-buffer is at least as big, fill with a fake very-far depth so anything wins
            let bw = GUI_W.with(|c| c.get());
            let bh = GUI_H.with(|c| c.get());
            GUI_ZBUF.with(|zb| {
                let mut z = zb.borrow_mut();
                if z.len() != bw * bh {
                    z.clear();
                    z.resize(bw * bh, f32::INFINITY);
                }
            });
            raster_tri_z_gouraud(
                (x1, y1, 0.0), rgb(c1),
                (x2, y2, 0.0), rgb(c2),
                (x3, y3, 0.0), rgb(c3),
            );
        }
        return true;
    }

    // gui_3d_setup focal cx cy  — set projection parameters
    if let Some(rest) = line.strip_prefix("gui_3d_setup ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let focal: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(600.0);
            let cx: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(400.0);
            let cy: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(400.0);
            GUI_3D_FOCAL.with(|c| c.set(focal));
            GUI_3D_CX.with(|c| c.set(cx));
            GUI_3D_CY.with(|c| c.set(cy));
        }
        return true;
    }

    // gui_3d_rotate ax ay az  — set world rotation (radians)
    if let Some(rest) = line.strip_prefix("gui_3d_rotate ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let ax: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let ay: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let az: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            GUI_3D_AX.with(|c| c.set(ax));
            GUI_3D_AY.with(|c| c.set(ay));
            GUI_3D_AZ.with(|c| c.set(az));
        }
        return true;
    }

    // gui_3d_camera z  — set camera distance behind origin (legacy / simple)
    if let Some(rest) = line.strip_prefix("gui_3d_camera ") {
        let z: f32 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(5.0);
        GUI_3D_CAM_Z.with(|c| c.set(z));
        return true;
    }

    // gui_3d_camera_pos x y z  — set camera world position
    if let Some(rest) = line.strip_prefix("gui_3d_camera_pos ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let x: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let y: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let z: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            GUI_3D_CAM_X.with(|c| c.set(x));
            GUI_3D_CAM_Y.with(|c| c.set(y));
            GUI_3D_CAM_Z.with(|c| c.set(-z));  // store as "distance behind"
        }
        return true;
    }

    // gui_3d_camera_yaw yaw   — horizontal turn (radians)
    if let Some(rest) = line.strip_prefix("gui_3d_camera_yaw ") {
        let v: f32 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(0.0);
        GUI_3D_CAM_YAW.with(|c| c.set(v));
        return true;
    }

    // gui_3d_camera_pitch p   — vertical look (radians)
    if let Some(rest) = line.strip_prefix("gui_3d_camera_pitch ") {
        let v: f32 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(0.0);
        // clamp to avoid flipping
        GUI_3D_CAM_PITCH.with(|c| c.set(v.clamp(-1.55, 1.55)));
        return true;
    }

    // gui_3d_camera_move forward strafe up  — move relative to current look
    // Forward is along camera's facing direction. Strafe is perpendicular (right).
    if let Some(rest) = line.strip_prefix("gui_3d_camera_move ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let f: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let s: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let u: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let yaw = GUI_3D_CAM_YAW.with(|c| c.get());
            // forward in world: rotate (0, 0, 1) by yaw -> (sin yaw, 0, cos yaw)
            let (sy_, cy_) = yaw.sin_cos();
            let fwd_x = sy_;
            let fwd_z = cy_;
            // right = forward × up (with up = (0,1,0)) = (cos yaw, 0, -sin yaw)
            let right_x = cy_;
            let right_z = -sy_;
            let dx = fwd_x * f + right_x * s;
            let dz = fwd_z * f + right_z * s;
            let dy = u;
            GUI_3D_CAM_X.with(|c| c.set(c.get() + dx));
            GUI_3D_CAM_Y.with(|c| c.set(c.get() + dy));
            // cam_z stored as "distance behind origin" — invert sign for world
            GUI_3D_CAM_Z.with(|c| c.set(c.get() - dz));
        }
        return true;
    }

    // gui_3d_camera_follow tx ty tz yaw_offset distance height  — third-person
    // Positions the camera at offset (distance behind, height above) from the
    // target, then looks at the target. Ideal for platformers.
    if let Some(rest) = line.strip_prefix("gui_3d_camera_follow ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let tx = g(0); let ty = g(1); let tz = g(2);
            let yaw_off = g(3);
            let dist = g(4);
            let height = g(5);
            // Position camera behind target (along -yaw_off direction)
            let (sy, cy) = yaw_off.sin_cos();
            let cam_x = tx - sy * dist;
            let cam_z = tz - cy * dist;
            let cam_y = ty + height;
            GUI_3D_CAM_X.with(|c| c.set(cam_x));
            GUI_3D_CAM_Y.with(|c| c.set(cam_y));
            GUI_3D_CAM_Z.with(|c| c.set(-cam_z));
            // Look at target
            let dx = tx - cam_x;
            let dy = ty - cam_y;
            let dz = tz - cam_z;
            let yaw = dx.atan2(dz);
            let horiz = (dx*dx + dz*dz).sqrt();
            let pitch = -dy.atan2(horiz);
            GUI_3D_CAM_YAW.with(|c| c.set(yaw));
            GUI_3D_CAM_PITCH.with(|c| c.set(pitch.clamp(-1.55, 1.55)));
        }
        return true;
    }

    // gui_3d_camera_look_at tx ty tz  — point camera at world target
    if let Some(rest) = line.strip_prefix("gui_3d_camera_look_at ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let tx: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let ty: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let tz: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let cx = GUI_3D_CAM_X.with(|c| c.get());
            let cy = GUI_3D_CAM_Y.with(|c| c.get());
            let cz_world = -GUI_3D_CAM_Z.with(|c| c.get());
            let dx = tx - cx;
            let dy = ty - cy;
            let dz = tz - cz_world;
            let yaw = dx.atan2(dz);
            let horiz = (dx*dx + dz*dz).sqrt();
            let pitch = -dy.atan2(horiz);
            GUI_3D_CAM_YAW.with(|c| c.set(yaw));
            GUI_3D_CAM_PITCH.with(|c| c.set(pitch.clamp(-1.55, 1.55)));
        }
        return true;
    }

    // ===== COLLISION DETECTION HELPERS =====

    // aabb_collide x1 y1 z1 w1 h1 d1   x2 y2 z2 w2 h2 d2 -> var
    // Returns 1 if axis-aligned boxes overlap (positions are centers).
    if let Some(rest) = line.strip_prefix("aabb_collide ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 12 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let (x1, y1, z1, w1, h1, d1) = (g(0), g(1), g(2), g(3), g(4), g(5));
            let (x2, y2, z2, w2, h2, d2) = (g(6), g(7), g(8), g(9), g(10), g(11));
            let hit = (x1 - x2).abs() * 2.0 < (w1 + w2)
                && (y1 - y2).abs() * 2.0 < (h1 + h2)
                && (z1 - z2).abs() * 2.0 < (d1 + d2);
            apply_return(vars, oop, var, Some(if hit { "1" } else { "0" }.to_string()));
        }
        return true;
    }

    // sphere_collide x1 y1 z1 r1   x2 y2 z2 r2 -> var
    if let Some(rest) = line.strip_prefix("sphere_collide ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 8 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let dx = g(0) - g(4);
            let dy = g(1) - g(5);
            let dz = g(2) - g(6);
            let r_sum = g(3) + g(7);
            let hit = dx*dx + dy*dy + dz*dz < r_sum * r_sum;
            apply_return(vars, oop, var, Some(if hit { "1" } else { "0" }.to_string()));
        }
        return true;
    }

    // ray_sphere_hit ox oy oz dx dy dz   sx sy sz r -> var
    // Returns 1 if a ray from origin in direction d intersects the sphere.
    if let Some(rest) = line.strip_prefix("ray_sphere_hit ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 10 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let (ox, oy, oz) = (g(0), g(1), g(2));
            let (dx, dy, dz) = (g(3), g(4), g(5));
            let (sx, sy, sz, r) = (g(6), g(7), g(8), g(9));
            let lx = ox - sx; let ly = oy - sy; let lz = oz - sz;
            let a = dx*dx + dy*dy + dz*dz;
            let b = 2.0 * (lx*dx + ly*dy + lz*dz);
            let c = lx*lx + ly*ly + lz*lz - r*r;
            let disc = b*b - 4.0*a*c;
            let hit = disc >= 0.0;
            apply_return(vars, oop, var, Some(if hit { "1" } else { "0" }.to_string()));
        }
        return true;
    }

    // point_in_aabb px py pz   bx by bz bw bh bd -> var
    // Box position is its center. Returns 1 if point is inside.
    if let Some(rest) = line.strip_prefix("point_in_aabb ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 9 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let (px, py, pz) = (g(0), g(1), g(2));
            let (bx, by, bz, bw, bh, bd) = (g(3), g(4), g(5), g(6), g(7), g(8));
            let hit = (px - bx).abs() * 2.0 < bw
                && (py - by).abs() * 2.0 < bh
                && (pz - bz).abs() * 2.0 < bd;
            apply_return(vars, oop, var, Some(if hit { "1" } else { "0" }.to_string()));
        }
        return true;
    }

    // platform_top px pz   bx by bz bw bh bd -> var
    // If the point (px, pz) is above a platform box (XZ-overlap), returns the
    // top Y of the platform. Otherwise returns -99999. Use for landing checks.
    if let Some(rest) = line.strip_prefix("platform_top ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 8 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let (px, pz) = (g(0), g(1));
            let (bx, by, bz, bw, bh, bd) = (g(2), g(3), g(4), g(5), g(6), g(7));
            let above_xz = (px - bx).abs() * 2.0 < bw && (pz - bz).abs() * 2.0 < bd;
            let top_y = if above_xz { by + bh * 0.5 } else { -99999.0 };
            apply_return(vars, oop, var, Some(format!("{}", top_y)));
        }
        return true;
    }

    // gui_3d_billboard cx cy cz size "color"
    // A camera-facing quad — useful for collectibles, particles, sprites.
    if let Some(rest) = line.strip_prefix("gui_3d_billboard ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let cx = g(0); let cy = g(1); let cz = g(2);
            let s = g(3) * 0.5;
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            // Get camera right + up vectors (in world space)
            let yaw = GUI_3D_CAM_YAW.with(|c| c.get());
            let (sy_, cy_) = yaw.sin_cos();
            // Camera right vector (when pitch = 0): (cos yaw, 0, -sin yaw)
            let rx = cy_; let rz = -sy_;
            // Quad corners (always upright, facing camera horizontally)
            let p1 = (cx - rx*s, cy - s, cz - rz*s);
            let p2 = (cx + rx*s, cy - s, cz + rz*s);
            let p3 = (cx + rx*s, cy + s, cz + rz*s);
            let p4 = (cx - rx*s, cy + s, cz - rz*s);
            let br = ((color >> 16) & 0xFF) as u8;
            let bg = ((color >> 8) & 0xFF) as u8;
            let bb = (color & 0xFF) as u8;
            draw_3d_face(p1, p2, p3, br, bg, bb);
            draw_3d_face(p1, p3, p4, br, bg, bb);
        }
        return true;
    }

    // distance3d x1 y1 z1 x2 y2 z2 -> var
    if let Some(rest) = line.strip_prefix("distance3d ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 6 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let dx = g(3) - g(0); let dy = g(4) - g(1); let dz = g(5) - g(2);
            let d = (dx*dx + dy*dy + dz*dz).sqrt();
            apply_return(vars, oop, var, Some(format!("{}", d)));
        }
        return true;
    }

    // gui_3d_light lx ly lz  — set light direction
    if let Some(rest) = line.strip_prefix("gui_3d_light ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let lx: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let ly: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(-1.0);
            let lz: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let m = (lx*lx + ly*ly + lz*lz).sqrt().max(1e-9);
            GUI_3D_LX.with(|c| c.set(lx/m));
            GUI_3D_LY.with(|c| c.set(ly/m));
            GUI_3D_LZ.with(|c| c.set(lz/m));
        }
        return true;
    }

    // gui_3d_ambient frac  — set ambient light (0..1)
    if let Some(rest) = line.strip_prefix("gui_3d_ambient ") {
        let f: f32 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(0.25);
        GUI_3D_AMBIENT.with(|c| c.set(f.clamp(0.0, 1.0)));
        return true;
    }

    // gui_3d_add_light dx dy dz r g b   — add a colored directional light
    // Direction (dx,dy,dz) is auto-normalized. r/g/b are 0..1 multipliers.
    if let Some(rest) = line.strip_prefix("gui_3d_add_light ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let dx: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let dy: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(-1.0);
            let dz: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let cr: f32 = resolve_arg(&args[3], vars, oop).parse().unwrap_or(1.0);
            let cg: f32 = resolve_arg(&args[4], vars, oop).parse().unwrap_or(1.0);
            let cb: f32 = resolve_arg(&args[5], vars, oop).parse().unwrap_or(1.0);
            let m = (dx*dx + dy*dy + dz*dz).sqrt().max(1e-9);
            GUI_3D_EXTRA_LIGHTS.with(|el| {
                el.borrow_mut().push((dx/m, dy/m, dz/m, cr, cg, cb));
            });
        }
        return true;
    }

    // gui_3d_clear_lights  — remove all extra lights (primary light remains)
    if line == "gui_3d_clear_lights" {
        GUI_3D_EXTRA_LIGHTS.with(|el| el.borrow_mut().clear());
        return true;
    }

    // gui_3d_fog near far "color"  — enable fog
    if let Some(rest) = line.strip_prefix("gui_3d_fog ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let n: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(5.0);
            let f: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(25.0);
            let c = color_to_u32(&resolve_arg(&args[2], vars, oop));
            GUI_3D_FOG_NEAR.with(|x| x.set(n));
            GUI_3D_FOG_FAR.with(|x| x.set(f.max(n + 0.001)));
            GUI_3D_FOG_COLOR.with(|x| x.set(c));
            GUI_3D_FOG_ENABLED.with(|x| x.set(true));
        }
        return true;
    }

    // gui_3d_no_fog  — disable fog
    if line == "gui_3d_no_fog" {
        GUI_3D_FOG_ENABLED.with(|x| x.set(false));
        return true;
    }

    // gui_3d_cull on|off  — toggle backface culling (default on)
    if let Some(rest) = line.strip_prefix("gui_3d_cull ") {
        let v = resolve_arg(rest.trim(), vars, oop).to_lowercase();
        let on = matches!(v.as_str(), "on" | "1" | "true" | "yes");
        GUI_3D_CULL.with(|c| c.set(on));
        return true;
    }

    // gui_3d_specular intensity shininess  — Phong highlights (0=off)
    if let Some(rest) = line.strip_prefix("gui_3d_specular ") {
        let args = split_args(rest);
        if !args.is_empty() {
            let i: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            GUI_3D_SPECULAR.with(|c| c.set(i.clamp(0.0, 2.0)));
            if args.len() >= 2 {
                let s: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(16.0);
                GUI_3D_SHININESS.with(|c| c.set(s.max(1.0)));
            }
        }
        return true;
    }

    // gui_3d_cylinder cx cy cz radius height segs "color"
    if let Some(rest) = line.strip_prefix("gui_3d_cylinder ") {
        let args = split_args(rest);
        if args.len() == 7 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let cx = g(0); let cy = g(1); let cz = g(2);
            let r = g(3); let h = g(4);
            let segs = (parse_i64_loose(&resolve_arg(&args[5], vars, oop)) as i32).max(3).min(96);
            let color = color_to_u32(&resolve_arg(&args[6], vars, oop));
            let base_r = ((color >> 16) & 0xFF) as u8;
            let base_g = ((color >> 8) & 0xFF) as u8;
            let base_b = (color & 0xFF) as u8;
            let pi = std::f32::consts::PI;
            // Side quads (two tris each)
            for i in 0..segs {
                let t0 = (i as f32) / (segs as f32) * 2.0 * pi;
                let t1 = ((i + 1) as f32) / (segs as f32) * 2.0 * pi;
                let p1 = (cx + r*t0.cos(), cy - h*0.5, cz + r*t0.sin());
                let p2 = (cx + r*t1.cos(), cy - h*0.5, cz + r*t1.sin());
                let p3 = (cx + r*t1.cos(), cy + h*0.5, cz + r*t1.sin());
                let p4 = (cx + r*t0.cos(), cy + h*0.5, cz + r*t0.sin());
                for tri in &[(p1, p2, p3), (p1, p3, p4)] {
                    let (a, b, c) = *tri;
                    draw_3d_face(a, b, c, base_r, base_g, base_b);
                }
            }
            // Top + bottom caps
            for i in 0..segs {
                let t0 = (i as f32) / (segs as f32) * 2.0 * pi;
                let t1 = ((i + 1) as f32) / (segs as f32) * 2.0 * pi;
                let top_a = (cx + r*t0.cos(), cy + h*0.5, cz + r*t0.sin());
                let top_b = (cx + r*t1.cos(), cy + h*0.5, cz + r*t1.sin());
                let top_c = (cx, cy + h*0.5, cz);
                draw_3d_face(top_a, top_b, top_c, base_r, base_g, base_b);
                let bot_a = (cx + r*t1.cos(), cy - h*0.5, cz + r*t1.sin());
                let bot_b = (cx + r*t0.cos(), cy - h*0.5, cz + r*t0.sin());
                let bot_c = (cx, cy - h*0.5, cz);
                draw_3d_face(bot_a, bot_b, bot_c, base_r, base_g, base_b);
            }
        }
        return true;
    }

    // gui_3d_cone cx cy cz radius height segs "color"
    if let Some(rest) = line.strip_prefix("gui_3d_cone ") {
        let args = split_args(rest);
        if args.len() == 7 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let cx = g(0); let cy = g(1); let cz = g(2);
            let r = g(3); let h = g(4);
            let segs = (parse_i64_loose(&resolve_arg(&args[5], vars, oop)) as i32).max(3).min(96);
            let color = color_to_u32(&resolve_arg(&args[6], vars, oop));
            let base_r = ((color >> 16) & 0xFF) as u8;
            let base_g = ((color >> 8) & 0xFF) as u8;
            let base_b = (color & 0xFF) as u8;
            let pi = std::f32::consts::PI;
            let apex = (cx, cy + h*0.5, cz);
            for i in 0..segs {
                let t0 = (i as f32) / (segs as f32) * 2.0 * pi;
                let t1 = ((i + 1) as f32) / (segs as f32) * 2.0 * pi;
                let p1 = (cx + r*t0.cos(), cy - h*0.5, cz + r*t0.sin());
                let p2 = (cx + r*t1.cos(), cy - h*0.5, cz + r*t1.sin());
                draw_3d_face(p1, p2, apex, base_r, base_g, base_b);
                // base cap
                let center = (cx, cy - h*0.5, cz);
                draw_3d_face(p2, p1, center, base_r, base_g, base_b);
            }
        }
        return true;
    }

    // gui_3d_shadow on/off [planeY] ["color"]
    if let Some(rest) = line.strip_prefix("gui_3d_shadow ") {
        let args = split_args(rest);
        if !args.is_empty() {
            let v = resolve_arg(&args[0], vars, oop).to_lowercase();
            let on = matches!(v.as_str(), "on" | "1" | "true" | "yes");
            GUI_3D_SHADOW_ENABLED.with(|c| c.set(on));
            if args.len() >= 2 {
                let py: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(-2.0);
                GUI_3D_SHADOW_Y.with(|c| c.set(py));
            }
            if args.len() >= 3 {
                let col = color_to_u32(&resolve_arg(&args[2], vars, oop));
                GUI_3D_SHADOW_COLOR.with(|c| c.set(col));
            }
        }
        return true;
    }

    // gui_3d_load_texture "name" "path"  — auto-detects PNG vs PPM by magic bytes
    if let Some(rest) = line.strip_prefix("gui_3d_load_texture ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = resolve_arg(&args[0], vars, oop);
            let path = expand_path(&resolve_arg(&args[1], vars, oop));
            match std::fs::read(&path) {
                Ok(data) => {
                    if let Some((buf, w, h)) = load_texture_bytes(&data) {
                        GUI_3D_TEXTURES.with(|t| t.borrow_mut().insert(name, (buf, w, h)));
                    } else {
                        println!("gui_3d_load_texture: unrecognized format (need PPM P6 or PNG)");
                    }
                }
                Err(e) => println!("gui_3d_load_texture: {}", e),
            }
        }
        return true;
    }

    // gui_3d_textured_quad cx cy cz size "texname"
    // Draws a flat horizontal textured quad (XZ plane).
    if let Some(rest) = line.strip_prefix("gui_3d_textured_quad ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let cx = g(0); let cy = g(1); let cz = g(2);
            let s = g(3) * 0.5;
            let tex_name = resolve_arg(&args[4], vars, oop);
            GUI_3D_TEXTURES.with(|t| {
                if let Some((pixels, tw, th)) = t.borrow().get(&tex_name) {
                    let corners = [
                        ((cx-s, cy, cz-s), (0.0_f32, 0.0_f32)),
                        ((cx+s, cy, cz-s), (1.0, 0.0)),
                        ((cx+s, cy, cz+s), (1.0, 1.0)),
                        ((cx-s, cy, cz+s), (0.0, 1.0)),
                    ];
                    for tri in &[(0,1,2), (0,2,3)] {
                        let (ia, ib, ic) = *tri;
                        let (wa, uva) = corners[ia];
                        let (wb, uvb) = corners[ib];
                        let (wc, uvc) = corners[ic];
                        let va = rotate_xyz(wa.0, wa.1, wa.2);
                        let vb = rotate_xyz(wb.0, wb.1, wb.2);
                        let vc = rotate_xyz(wc.0, wc.1, wc.2);
                        let p1 = project_3d(va.0, va.1, va.2);
                        let p2 = project_3d(vb.0, vb.1, vb.2);
                        let p3 = project_3d(vc.0, vc.1, vc.2);
                        if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
                            raster_tri_z_textured(p1, uva, p2, uvb, p3, uvc, pixels, *tw, *th);
                        }
                    }
                }
            });
        }
        return true;
    }

    // gui_3d_load_obj "name" "path.obj"  — parse and store mesh
    if let Some(rest) = line.strip_prefix("gui_3d_load_obj ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = resolve_arg(&args[0], vars, oop);
            let path = expand_path(&resolve_arg(&args[1], vars, oop));
            match std::fs::read_to_string(&path) {
                Ok(text) => {
                    let tris = parse_obj(&text);
                    let n = tris.len();
                    GUI_3D_MESHES.with(|m| m.borrow_mut().insert(name.clone(), tris));
                    println!("\x1b[36m[3d]\x1b[0m loaded {} ({} triangles)", name, n);
                }
                Err(e) => println!("gui_3d_load_obj: {}", e),
            }
        }
        return true;
    }

    // gui_3d_draw_mesh "name" cx cy cz scale "color"  — render a loaded mesh
    if let Some(rest) = line.strip_prefix("gui_3d_draw_mesh ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let name = resolve_arg(&args[0], vars, oop);
            let cx: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let cy: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let cz: f32 = resolve_arg(&args[3], vars, oop).parse().unwrap_or(0.0);
            let scale: f32 = resolve_arg(&args[4], vars, oop).parse().unwrap_or(1.0);
            let color = color_to_u32(&resolve_arg(&args[5], vars, oop));
            let br = ((color >> 16) & 0xFF) as u8;
            let bg = ((color >> 8) & 0xFF) as u8;
            let bb = (color & 0xFF) as u8;
            let tris = GUI_3D_MESHES.with(|m| m.borrow().get(&name).cloned());
            if let Some(tris) = tris {
                for t in &tris {
                    let a = (cx + t[0]*scale, cy + t[1]*scale, cz + t[2]*scale);
                    let b = (cx + t[3]*scale, cy + t[4]*scale, cz + t[5]*scale);
                    let c = (cx + t[6]*scale, cy + t[7]*scale, cz + t[8]*scale);
                    draw_3d_face(a, b, c, br, bg, bb);
                }
            }
        }
        return true;
    }

    // gui_3d_plane cx cy cz size "color"  — flat horizontal quad on XZ plane
    if let Some(rest) = line.strip_prefix("gui_3d_plane ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let cx = g(0); let cy = g(1); let cz = g(2);
            let s = g(3) * 0.5;
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            let br = ((color >> 16) & 0xFF) as u8;
            let bg = ((color >> 8) & 0xFF) as u8;
            let bb = (color & 0xFF) as u8;
            let p1 = (cx-s, cy, cz-s);
            let p2 = (cx+s, cy, cz-s);
            let p3 = (cx+s, cy, cz+s);
            let p4 = (cx-s, cy, cz+s);
            draw_3d_face(p1, p2, p3, br, bg, bb);
            draw_3d_face(p1, p3, p4, br, bg, bb);
        }
        return true;
    }

    // gui_3d_clear color  — clear framebuffer and reset z-buffer
    if let Some(rest) = line.strip_prefix("gui_3d_clear ") {
        let color = color_to_u32(&resolve_arg(rest.trim(), vars, oop));
        let bw = GUI_W.with(|c| c.get());
        let bh = GUI_H.with(|c| c.get());
        GUI_BUF.with(|b| {
            let mut buf = b.borrow_mut();
            for p in buf.iter_mut() { *p = color; }
        });
        GUI_ZBUF.with(|zb| {
            let mut z = zb.borrow_mut();
            z.clear();
            z.resize(bw * bh, f32::INFINITY);
        });
        return true;
    }

    // gui_3d_triangle x1 y1 z1 x2 y2 z2 x3 y3 z3 color
    // Rotates -> projects -> Lambertian shades -> rasterizes with z-buffer.
    if let Some(rest) = line.strip_prefix("gui_3d_triangle ") {
        let args = split_args(rest);
        if args.len() == 10 {
            let mut g = |i: usize| -> f32 {
                resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0)
            };
            let (x1,y1,z1) = (g(0), g(1), g(2));
            let (x2,y2,z2) = (g(3), g(4), g(5));
            let (x3,y3,z3) = (g(6), g(7), g(8));
            let color = color_to_u32(&resolve_arg(&args[9], vars, oop));
            let v1 = rotate_xyz(x1,y1,z1);
            let v2 = rotate_xyz(x2,y2,z2);
            let v3 = rotate_xyz(x3,y3,z3);
            // Face normal in world space (cross product of edges)
            let ex = v2.0 - v1.0; let ey = v2.1 - v1.1; let ez = v2.2 - v1.2;
            let fx = v3.0 - v1.0; let fy = v3.1 - v1.1; let fz = v3.2 - v1.2;
            let nx = ey*fz - ez*fy;
            let ny = ez*fx - ex*fz;
            let nz = ex*fy - ey*fx;
            let shade = lambert_shade(nx, ny, nz);
            let r = (((color >> 16) & 0xFF) as f32 * shade).min(255.0) as u32;
            let gn = (((color >> 8) & 0xFF) as f32 * shade).min(255.0) as u32;
            let b3 = ((color & 0xFF) as f32 * shade).min(255.0) as u32;
            let shaded = (r << 16) | (gn << 8) | b3;
            let p1 = project_3d(v1.0, v1.1, v1.2);
            let p2 = project_3d(v2.0, v2.1, v2.2);
            let p3 = project_3d(v3.0, v3.1, v3.2);
            if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
                raster_tri_z(p1, p2, p3, shaded);
            }
        }
        return true;
    }

    // gui_3d_cube cx cy cz size color  — solid shaded 3D cube
    if let Some(rest) = line.strip_prefix("gui_3d_cube ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let mut g = |i: usize| -> f32 {
                resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0)
            };
            let cx = g(0); let cy = g(1); let cz = g(2);
            let s = g(3) * 0.5;
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            // 8 vertices
            let v = [
                (cx-s, cy-s, cz-s), (cx+s, cy-s, cz-s),
                (cx+s, cy+s, cz-s), (cx-s, cy+s, cz-s),
                (cx-s, cy-s, cz+s), (cx+s, cy-s, cz+s),
                (cx+s, cy+s, cz+s), (cx-s, cy+s, cz+s),
            ];
            // 12 triangles (CCW outward normals)
            let tris: [(usize, usize, usize); 12] = [
                (0,2,1),(0,3,2),  // -Z face
                (4,5,6),(4,6,7),  // +Z face
                (0,1,5),(0,5,4),  // -Y face
                (3,7,6),(3,6,2),  // +Y face
                (0,4,7),(0,7,3),  // -X face
                (1,2,6),(1,6,5),  // +X face
            ];
            for (a, b, c) in tris.iter() {
                let (x1,y1,z1) = v[*a];
                let (x2,y2,z2) = v[*b];
                let (x3,y3,z3) = v[*c];
                let v1 = rotate_xyz(x1,y1,z1);
                let v2 = rotate_xyz(x2,y2,z2);
                let v3 = rotate_xyz(x3,y3,z3);
                let ex = v2.0 - v1.0; let ey = v2.1 - v1.1; let ez = v2.2 - v1.2;
                let fx = v3.0 - v1.0; let fy = v3.1 - v1.1; let fz = v3.2 - v1.2;
                let nx = ey*fz - ez*fy;
                let ny = ez*fx - ex*fz;
                let nz = ex*fy - ey*fx;
                let shade = lambert_shade(nx, ny, nz);
                let r = (((color >> 16) & 0xFF) as f32 * shade).min(255.0) as u32;
                let gc = (((color >> 8) & 0xFF) as f32 * shade).min(255.0) as u32;
                let b3 = ((color & 0xFF) as f32 * shade).min(255.0) as u32;
                let shaded = (r << 16) | (gc << 8) | b3;
                let p1 = project_3d(v1.0, v1.1, v1.2);
                let p2 = project_3d(v2.0, v2.1, v2.2);
                let p3 = project_3d(v3.0, v3.1, v3.2);
                if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
                    raster_tri_z(p1, p2, p3, shaded);
                }
            }
        }
        return true;
    }

    // gui_3d_sphere cx cy cz r segs color  — tessellated lit sphere
    if let Some(rest) = line.strip_prefix("gui_3d_sphere ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let mut g = |i: usize| -> f32 {
                resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0)
            };
            let cx = g(0); let cy = g(1); let cz = g(2);
            let r = g(3);
            let segs = (g(4) as i32).max(4).min(64);
            let color = color_to_u32(&resolve_arg(&args[5], vars, oop));
            let rings = segs;
            let slices = segs * 2;
            let pi = std::f32::consts::PI;
            let mut verts: Vec<(f32, f32, f32)> = Vec::with_capacity(((rings+1)*(slices+1)) as usize);
            for i in 0..=rings {
                let phi = (i as f32) / (rings as f32) * pi;
                let y = phi.cos();
                let rs = phi.sin();
                for j in 0..=slices {
                    let theta = (j as f32) / (slices as f32) * 2.0 * pi;
                    let x = theta.cos() * rs;
                    let z = theta.sin() * rs;
                    verts.push((cx + x*r, cy + y*r, cz + z*r));
                }
            }
            let w = slices + 1;
            for i in 0..rings {
                for j in 0..slices {
                    let a = (i * w + j) as usize;
                    let b = (i * w + j + 1) as usize;
                    let c = ((i + 1) * w + j) as usize;
                    let d = ((i + 1) * w + j + 1) as usize;
                    for (i1, i2, i3) in &[(a,c,b), (b,c,d)] {
                        let (x1,y1,z1) = verts[*i1];
                        let (x2,y2,z2) = verts[*i2];
                        let (x3,y3,z3) = verts[*i3];
                        let v1 = rotate_xyz(x1,y1,z1);
                        let v2 = rotate_xyz(x2,y2,z2);
                        let v3 = rotate_xyz(x3,y3,z3);
                        let ex = v2.0 - v1.0; let ey = v2.1 - v1.1; let ez = v2.2 - v1.2;
                        let fx = v3.0 - v1.0; let fy = v3.1 - v1.1; let fz = v3.2 - v1.2;
                        let nx = ey*fz - ez*fy;
                        let ny = ez*fx - ex*fz;
                        let nz = ex*fy - ey*fx;
                        let shade = lambert_shade(nx, ny, nz);
                        let rr = (((color >> 16) & 0xFF) as f32 * shade).min(255.0) as u32;
                        let gc = (((color >> 8) & 0xFF) as f32 * shade).min(255.0) as u32;
                        let b3 = ((color & 0xFF) as f32 * shade).min(255.0) as u32;
                        let shaded = (rr << 16) | (gc << 8) | b3;
                        let p1 = project_3d(v1.0, v1.1, v1.2);
                        let p2 = project_3d(v2.0, v2.1, v2.2);
                        let p3 = project_3d(v3.0, v3.1, v3.2);
                        if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
                            raster_tri_z(p1, p2, p3, shaded);
                        }
                    }
                }
            }
        }
        return true;
    }

    // gui_3d_line x1 y1 z1 x2 y2 z2 color  — 3D line via Wu (no z-test for now)
    if let Some(rest) = line.strip_prefix("gui_3d_line ") {
        let args = split_args(rest);
        if args.len() == 7 {
            let mut g = |i: usize| -> f32 {
                resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0)
            };
            let (x1,y1,z1) = (g(0), g(1), g(2));
            let (x2,y2,z2) = (g(3), g(4), g(5));
            let color = color_to_u32(&resolve_arg(&args[6], vars, oop));
            let v1 = rotate_xyz(x1,y1,z1);
            let v2 = rotate_xyz(x2,y2,z2);
            let p1 = project_3d(v1.0, v1.1, v1.2);
            let p2 = project_3d(v2.0, v2.1, v2.2);
            if let (Some(p1), Some(p2)) = (p1, p2) {
                wu_line(p1.0, p1.1, p2.0, p2.1, color);
            }
        }
        return true;
    }

    // ============================================================
    //  UNIFIED RENDERER (r3d_*)
    //  Auto-dispatches between GPU (gl_*) and CPU (gui_3d_*) backends.
    //  Starts on GPU. If frame rate drops below 30fps for a sustained
    //  window of ~30 frames, automatically switches to CPU. The script
    //  just calls r3d_* commands without any detection logic.
    // ============================================================

    // Internal: ensure a renderer is open. Returns the current backend (1=gpu, 2=cpu).
    // CPU-FIRST priority: opens the minifb (CPU) window by default. GPU is only
    // used if the script explicitly switches via gl_init.
    fn r3d_ensure_open(width: u32, height: u32, title: &str,
                       vars: &mut Vars, oop: &mut OopState,
                       server_cfg: &mut Option<ServerConfig>) -> u32 {
        let cur = R3D_BACKEND.with(|c| c.get());
        if cur != 0 { return cur; }
        let line = format!("gui_native \"{}\" {} {}", title, width, height);
        execute(&line, vars, server_cfg, oop);
        R3D_BACKEND.with(|c| c.set(2));
        2
    }

    // Internal: hot-swap backends. Closes current window and opens the other.
    fn r3d_switch_backend(target: u32, vars: &mut Vars, oop: &mut OopState,
                          server_cfg: &mut Option<ServerConfig>) {
        let cur = R3D_BACKEND.with(|c| c.get());
        if cur == target { return; }
        let w = R3D_W.with(|c| c.get());
        let h = R3D_H.with(|c| c.get());
        let title = R3D_TITLE.with(|t| t.borrow().clone());
        // Close current
        if cur == 1 { GL_STATE.with(|s| *s.borrow_mut() = None); }
        if cur == 2 {
            execute("gui_close", vars, server_cfg, oop);
        }
        // Open target
        if target == 1 {
            if let Ok(state) = gl_init_state(w, h, &title) {
                GL_STATE.with(|s| *s.borrow_mut() = Some(state));
                R3D_BACKEND.with(|c| c.set(1));
                return;
            }
            // GL open failed — fall back to CPU
            let line = format!("gui_native \"{}\" {} {}", title, w, h);
            execute(&line, vars, server_cfg, oop);
            R3D_BACKEND.with(|c| c.set(2));
        } else {
            let line = format!("gui_native \"{}\" {} {}", title, w, h);
            execute(&line, vars, server_cfg, oop);
            R3D_BACKEND.with(|c| c.set(2));
        }
    }

    // r3d_init width height "title"
    if let Some(rest) = line.strip_prefix("r3d_init ") {
        let args = split_args(rest);
        if args.len() >= 3 {
            let w: u32 = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as u32;
            let h: u32 = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as u32;
            let title = resolve_arg(&args[2], vars, oop);
            R3D_W.with(|c| c.set(w));
            R3D_H.with(|c| c.set(h));
            R3D_TITLE.with(|t| *t.borrow_mut() = title.clone());
            r3d_ensure_open(w, h, &title, vars, oop, server_cfg);
        }
        return true;
    }

    // r3d_clear "color"
    if let Some(rest) = line.strip_prefix("r3d_clear ") {
        let color_str = resolve_arg(rest.trim(), vars, oop);
        let backend = R3D_BACKEND.with(|c| c.get());
        if backend == 1 {
            let line = format!("gl_clear {}", color_str);
            execute(&line, vars, server_cfg, oop);
        } else if backend == 2 {
            let line = format!("gui_3d_clear {}", color_str);
            execute(&line, vars, server_cfg, oop);
        }
        return true;
    }

    // r3d_rotate ax ay az
    if let Some(rest) = line.strip_prefix("r3d_rotate ") {
        let backend = R3D_BACKEND.with(|c| c.get());
        let cmd = if backend == 1 { "gl_rotate " } else { "gui_3d_rotate " };
        let line = format!("{}{}", cmd, rest);
        execute(&line, vars, server_cfg, oop);
        return true;
    }

    // r3d_camera z
    if let Some(rest) = line.strip_prefix("r3d_camera ") {
        let backend = R3D_BACKEND.with(|c| c.get());
        let cmd = if backend == 1 { "gl_camera " } else { "gui_3d_camera " };
        let line = format!("{}{}", cmd, rest);
        execute(&line, vars, server_cfg, oop);
        return true;
    }

    // r3d_cube cx cy cz size "color"
    if let Some(rest) = line.strip_prefix("r3d_cube ") {
        let backend = R3D_BACKEND.with(|c| c.get());
        let cmd = if backend == 1 { "gl_cube " } else { "gui_3d_cube " };
        let line = format!("{}{}", cmd, rest);
        execute(&line, vars, server_cfg, oop);
        return true;
    }

    // r3d_swap — presents the frame.
    // CPU-priority policy: if the script manually opened GPU (via gl_init) and
    // it's too slow, fall back to CPU. If on CPU, just present — no auto-upgrade
    // to GPU, since the user asked for CPU priority.
    if line == "r3d_swap" {
        let backend = R3D_BACKEND.with(|c| c.get());
        if backend == 1 {
            execute("gl_swap", vars, server_cfg, oop);
            let slow: bool = GL_STATE.with(|s| {
                s.borrow().as_ref().map(|st| {
                    if st.recent_ms.len() < 15 { return false; }
                    let avg: f64 = st.recent_ms.iter().sum::<f64>() / st.recent_ms.len() as f64;
                    avg > 33.3
                }).unwrap_or(false)
            });
            if slow {
                r3d_switch_backend(2, vars, oop, server_cfg);
            }
        } else if backend == 2 {
            execute("gui_update", vars, server_cfg, oop);
        }
        return true;
    }

    // r3d_open varname
    if let Some(rest) = line.strip_prefix("r3d_open ") {
        let backend = R3D_BACKEND.with(|c| c.get());
        let cmd = if backend == 1 { "gl_open " } else { "gui_open " };
        let line = format!("{}{}", cmd, rest);
        execute(&line, vars, server_cfg, oop);
        return true;
    }

    // r3d_close — close whichever window is open
    if line == "r3d_close" {
        let backend = R3D_BACKEND.with(|c| c.get());
        if backend == 1 { execute("gl_close", vars, server_cfg, oop); }
        if backend == 2 { execute("gui_close", vars, server_cfg, oop); }
        R3D_BACKEND.with(|c| c.set(0));
        return true;
    }

    // r3d_mode -> var   ("gpu" or "cpu" — useful for HUD overlays)
    if let Some(rest) = line.strip_prefix("r3d_mode ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let backend = R3D_BACKEND.with(|c| c.get());
        let mode = match backend { 1 => "gpu", 2 => "cpu", _ => "none" };
        apply_return(vars, oop, var, Some(mode.to_string()));
        return true;
    }

    // ============================================================
    //  OPENGL HARDWARE-ACCELERATED 3D
    //  Lives alongside the CPU-based gui_3d_* commands. Use either.
    // ============================================================

    // gl_init width height "title"
    if let Some(rest) = line.strip_prefix("gl_init ") {
        let args = split_args(rest);
        if args.len() >= 3 {
            let w: u32 = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as u32;
            let h: u32 = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as u32;
            let title = resolve_arg(&args[2], vars, oop);
            match gl_init_state(w, h, &title) {
                Ok(state) => GL_STATE.with(|s| *s.borrow_mut() = Some(state)),
                Err(e) => println!("gl_init failed: {}", e),
            }
        }
        return true;
    }

    // gl_clear "color"
    if let Some(rest) = line.strip_prefix("gl_clear ") {
        use glow::HasContext as _;
        let color = color_to_u32(&resolve_arg(rest.trim(), vars, oop));
        let r = ((color >> 16) & 0xFF) as f32 / 255.0;
        let g = ((color >> 8) & 0xFF) as f32 / 255.0;
        let b = (color & 0xFF) as f32 / 255.0;
        GL_STATE.with(|s| {
            if let Some(st) = s.borrow_mut().as_mut() {
                unsafe {
                    st.gl.clear_color(r, g, b, 1.0);
                    st.gl.clear(glow::COLOR_BUFFER_BIT | glow::DEPTH_BUFFER_BIT);
                }
                st.verts.clear();
            }
        });
        return true;
    }

    // gl_rotate ax ay az
    if let Some(rest) = line.strip_prefix("gl_rotate ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let ax: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let ay: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let az: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            GL_STATE.with(|s| {
                if let Some(st) = s.borrow_mut().as_mut() {
                    st.ax = ax; st.ay = ay; st.az = az;
                }
            });
        }
        return true;
    }

    // gl_camera z
    if let Some(rest) = line.strip_prefix("gl_camera ") {
        let z: f32 = resolve_arg(rest.trim(), vars, oop).parse().unwrap_or(5.0);
        GL_STATE.with(|s| {
            if let Some(st) = s.borrow_mut().as_mut() {
                st.cam_z = z;
            }
        });
        return true;
    }

    // gl_triangle x1 y1 z1 x2 y2 z2 x3 y3 z3 "color"
    if let Some(rest) = line.strip_prefix("gl_triangle ") {
        let args = split_args(rest);
        if args.len() == 10 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let color = color_to_u32(&resolve_arg(&args[9], vars, oop));
            let r = ((color >> 16) & 0xFF) as f32 / 255.0;
            let gc = ((color >> 8) & 0xFF) as f32 / 255.0;
            let bc = (color & 0xFF) as f32 / 255.0;
            GL_STATE.with(|s| {
                if let Some(st) = s.borrow_mut().as_mut() {
                    for vi in 0..3 {
                        st.verts.push(g(vi*3));
                        st.verts.push(g(vi*3 + 1));
                        st.verts.push(g(vi*3 + 2));
                        st.verts.push(r); st.verts.push(gc); st.verts.push(bc);
                    }
                }
            });
        }
        return true;
    }

    // gl_cube cx cy cz size "color"  -- queues 12 triangles
    if let Some(rest) = line.strip_prefix("gl_cube ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let cx: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let cy: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let cz: f32 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let sz: f32 = resolve_arg(&args[3], vars, oop).parse::<f32>().unwrap_or(1.0) * 0.5;
            let color = color_to_u32(&resolve_arg(&args[4], vars, oop));
            let r = ((color >> 16) & 0xFF) as f32 / 255.0;
            let g = ((color >> 8) & 0xFF) as f32 / 255.0;
            let b = (color & 0xFF) as f32 / 255.0;
            let v = [
                (cx-sz, cy-sz, cz-sz), (cx+sz, cy-sz, cz-sz),
                (cx+sz, cy+sz, cz-sz), (cx-sz, cy+sz, cz-sz),
                (cx-sz, cy-sz, cz+sz), (cx+sz, cy-sz, cz+sz),
                (cx+sz, cy+sz, cz+sz), (cx-sz, cy+sz, cz+sz),
            ];
            // 6 faces * 2 triangles per face, with simple per-face brightness for "shading"
            let tris: [(usize, usize, usize, f32); 12] = [
                (0,2,1, 0.55), (0,3,2, 0.55),
                (4,5,6, 1.00), (4,6,7, 1.00),
                (0,1,5, 0.75), (0,5,4, 0.75),
                (3,7,6, 0.85), (3,6,2, 0.85),
                (0,4,7, 0.65), (0,7,3, 0.65),
                (1,2,6, 0.95), (1,6,5, 0.95),
            ];
            GL_STATE.with(|s| {
                if let Some(st) = s.borrow_mut().as_mut() {
                    for (a, bi, c, shade) in tris.iter() {
                        for idx in &[*a, *bi, *c] {
                            let (x, y, z) = v[*idx];
                            st.verts.push(x); st.verts.push(y); st.verts.push(z);
                            st.verts.push(r * shade);
                            st.verts.push(g * shade);
                            st.verts.push(b * shade);
                        }
                    }
                }
            });
        }
        return true;
    }

    // gl_swap  -- render queued verts + present
    if line == "gl_swap" {
        use glow::HasContext as _;
        use glutin::prelude::*;
        GL_STATE.with(|s| {
            if let Some(st) = s.borrow_mut().as_mut() {
                unsafe {
                    st.gl.bind_buffer(glow::ARRAY_BUFFER, Some(st.vbo));
                    let bytes: &[u8] = std::slice::from_raw_parts(
                        st.verts.as_ptr() as *const u8,
                        st.verts.len() * std::mem::size_of::<f32>(),
                    );
                    st.gl.buffer_data_u8_slice(glow::ARRAY_BUFFER, bytes, glow::STREAM_DRAW);
                    st.gl.use_program(Some(st.program));
                    let mvp = gl_mvp(st.ax, st.ay, st.az, st.cam_z, st.focal, st.aspect);
                    let loc = st.gl.get_uniform_location(st.program, "u_mvp");
                    if let Some(l) = loc {
                        st.gl.uniform_matrix_4_f32_slice(Some(&l), false, &mvp);
                    }
                    st.gl.bind_vertex_array(Some(st.vao));
                    let n_verts = (st.verts.len() / 6) as i32;
                    st.gl.draw_arrays(glow::TRIANGLES, 0, n_verts);
                }
                let _ = st.surface.swap_buffers(&st.context);
                st.verts.clear();
                // measure frame time
                let now = std::time::Instant::now();
                if let Some(prev) = st.last_swap {
                    let ms = (now - prev).as_secs_f64() * 1000.0;
                    st.last_frame_ms = ms;
                    if st.recent_ms.len() >= 30 { st.recent_ms.pop_front(); }
                    st.recent_ms.push_back(ms);
                }
                st.last_swap = Some(now);
            }
        });
        return true;
    }

    // gl_frame_time -> var   (ms of last frame, useful for adaptive logic)
    if let Some(rest) = line.strip_prefix("gl_frame_time ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let ms = GL_STATE.with(|s| s.borrow().as_ref().map(|st| st.last_frame_ms).unwrap_or(0.0));
        apply_return(vars, oop, var, Some(format!("{:.2}", ms)));
        return true;
    }

    // gl_fps_actual -> var   (averaged FPS over recent 30 frames)
    if let Some(rest) = line.strip_prefix("gl_fps_actual ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let fps = GL_STATE.with(|s| {
            s.borrow().as_ref().map(|st| {
                if st.recent_ms.is_empty() { 0.0 }
                else {
                    let avg: f64 = st.recent_ms.iter().sum::<f64>() / st.recent_ms.len() as f64;
                    if avg > 0.0 { 1000.0 / avg } else { 0.0 }
                }
            }).unwrap_or(0.0)
        });
        apply_return(vars, oop, var, Some(format!("{:.1}", fps)));
        return true;
    }

    // gl_should_fallback -> var
    // Returns 1 if recent 30 frames averaged below 30 fps (suggests overload),
    // so the script can fall back to CPU rendering or lower detail.
    if let Some(rest) = line.strip_prefix("gl_should_fallback ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let fb: i64 = GL_STATE.with(|s| {
            s.borrow().as_ref().map(|st| {
                if st.recent_ms.len() < 15 { return 0i64; }
                let avg: f64 = st.recent_ms.iter().sum::<f64>() / st.recent_ms.len() as f64;
                if avg > 33.3 { 1 } else { 0 }
            }).unwrap_or(0)
        });
        apply_return(vars, oop, var, Some(fb.to_string()));
        return true;
    }

    // sys_cpu -> var   (current CPU load 0-100; reads /proc/stat on Linux)
    if let Some(rest) = line.strip_prefix("sys_cpu ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let pct = read_cpu_load();
        apply_return(vars, oop, var, Some(format!("{:.1}", pct)));
        return true;
    }

    // sys_mem -> var   (memory used %; reads /proc/meminfo on Linux)
    if let Some(rest) = line.strip_prefix("sys_mem ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let pct = read_mem_load();
        apply_return(vars, oop, var, Some(format!("{:.1}", pct)));
        return true;
    }

    // gl_open varname  -- 1 if window still open, 0 otherwise
    if let Some(rest) = line.strip_prefix("gl_open ") {
        use winit::platform::pump_events::EventLoopExtPumpEvents;
        let var = rest.trim().to_string();
        let open = GL_STATE.with(|s| {
            let mut sb = s.borrow_mut();
            let st = match sb.as_mut() { Some(s) => s, None => return 0i64 };
            // pump events, look for close
            let mut still_open = st.open;
            let _ = st.event_loop.pump_events(
                Some(std::time::Duration::from_millis(0)),
                |event, _elwt| {
                    if let winit::event::Event::WindowEvent { event, .. } = event {
                        if matches!(event, winit::event::WindowEvent::CloseRequested) {
                            still_open = false;
                        }
                    }
                });
            st.open = still_open;
            if still_open { 1 } else { 0 }
        });
        vars.insert(var, open);
        return true;
    }

    // gl_close
    if line == "gl_close" {
        GL_STATE.with(|s| *s.borrow_mut() = None);
        return true;
    }

    // ===== NATIVE PARTICLE SYSTEM =====

    // gui_particle_spawn x y vx vy ax ay life color [size]
    if let Some(rest) = line.strip_prefix("gui_particle_spawn ") {
        let args = split_args(rest);
        if args.len() >= 8 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let life = parse_i64_loose(&resolve_arg(&args[6], vars, oop)) as i32;
            let color = color_to_u32(&resolve_arg(&args[7], vars, oop));
            let size = if args.len() >= 9 {
                parse_i64_loose(&resolve_arg(&args[8], vars, oop)).max(1) as i32
            } else { 2 };
            GUI_PARTICLES.with(|p| {
                p.borrow_mut().push(Particle {
                    x: g(0), y: g(1), vx: g(2), vy: g(3), ax: g(4), ay: g(5),
                    life, max_life: life, color, size,
                });
            });
        }
        return true;
    }

    // gui_particle_burst x y count color speed life — spawn N particles radially
    if let Some(rest) = line.strip_prefix("gui_particle_burst ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let x: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let y: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let count = parse_i64_loose(&resolve_arg(&args[2], vars, oop)).max(0) as i32;
            let color = color_to_u32(&resolve_arg(&args[3], vars, oop));
            let speed: f32 = resolve_arg(&args[4], vars, oop).parse().unwrap_or(3.0);
            let life = parse_i64_loose(&resolve_arg(&args[5], vars, oop)).max(1) as i32;
            GUI_PARTICLES.with(|p| {
                let mut ps = p.borrow_mut();
                for i in 0..count {
                    let a = (i as f32) * std::f32::consts::TAU / (count as f32);
                    ps.push(Particle {
                        x, y, vx: a.cos() * speed, vy: a.sin() * speed,
                        ax: 0.0, ay: 0.15, life, max_life: life, color, size: 2,
                    });
                }
            });
        }
        return true;
    }

    // gui_particle_update — apply physics for one frame (call once per frame)
    if line == "gui_particle_update" {
        GUI_PARTICLES.with(|p| {
            let mut ps = p.borrow_mut();
            for q in ps.iter_mut() {
                q.vx += q.ax;
                q.vy += q.ay;
                q.x += q.vx;
                q.y += q.vy;
                q.life -= 1;
            }
            ps.retain(|q| q.life > 0);
        });
        return true;
    }

    // gui_particle_draw — render all particles with alpha fade based on life
    if line == "gui_particle_draw" {
        let bw = GUI_W.with(|c| c.get());
        let bh = GUI_H.with(|c| c.get());
        GUI_PARTICLES.with(|p| {
            let ps = p.borrow();
            GUI_BUF.with(|b| {
                let mut buf = b.borrow_mut();
                for q in ps.iter() {
                    let alpha = (q.life as f32 / q.max_life as f32).clamp(0.0, 1.0);
                    let r = (((q.color >> 16) & 0xFF) as f32 * alpha) as u32;
                    let gr = (((q.color >> 8) & 0xFF) as f32 * alpha) as u32;
                    let b3 = ((q.color & 0xFF) as f32 * alpha) as u32;
                    let shaded = (r << 16) | (gr << 8) | b3;
                    let s = q.size;
                    for dy in -s..=s {
                        for dx in -s..=s {
                            if dx*dx + dy*dy <= s*s {
                                gui_put_pixel(&mut buf, bw, bh,
                                    q.x as i64 + dx as i64,
                                    q.y as i64 + dy as i64,
                                    shaded);
                            }
                        }
                    }
                }
            });
        });
        return true;
    }

    // gui_particle_count -> var  — count of live particles
    if let Some(rest) = line.strip_prefix("gui_particle_count ") {
        let var = rest.trim().to_string();
        let n = GUI_PARTICLES.with(|p| p.borrow().len() as i64);
        vars.insert(var, n);
        return true;
    }

    // gui_particle_clear — remove all particles
    if line == "gui_particle_clear" {
        GUI_PARTICLES.with(|p| p.borrow_mut().clear());
        return true;
    }

    // gui_3d_shade_triangle x1 y1 z1 c1  x2 y2 z2 c2  x3 y3 z3 c3
    // Per-vertex colored 3D triangle with Gouraud interpolation + z-buffer.
    if let Some(rest) = line.strip_prefix("gui_3d_shade_triangle ") {
        let args = split_args(rest);
        if args.len() == 12 {
            let g = |i: usize| -> f32 { resolve_arg(&args[i], vars, oop).parse().unwrap_or(0.0) };
            let (x1,y1,z1) = (g(0), g(1), g(2));
            let c1 = color_to_u32(&resolve_arg(&args[3], vars, oop));
            let (x2,y2,z2) = (g(4), g(5), g(6));
            let c2 = color_to_u32(&resolve_arg(&args[7], vars, oop));
            let (x3,y3,z3) = (g(8), g(9), g(10));
            let c3 = color_to_u32(&resolve_arg(&args[11], vars, oop));
            let v1 = rotate_xyz(x1,y1,z1);
            let v2 = rotate_xyz(x2,y2,z2);
            let v3 = rotate_xyz(x3,y3,z3);
            let p1 = project_3d(v1.0, v1.1, v1.2);
            let p2 = project_3d(v2.0, v2.1, v2.2);
            let p3 = project_3d(v3.0, v3.1, v3.2);
            let rgb = |c: u32| (((c >> 16) & 0xFF) as u8, ((c >> 8) & 0xFF) as u8, (c & 0xFF) as u8);
            if let (Some(p1), Some(p2), Some(p3)) = (p1, p2, p3) {
                raster_tri_z_gouraud(p1, rgb(c1), p2, rgb(c2), p3, rgb(c3));
            }
        }
        return true;
    }

    // ===== AUDIO =====
    // beep frequency_hz duration_ms — non-blocking on Linux via terminal bell;
    // proper tone via /dev/dsp / aplay if available
    if let Some(rest) = line.strip_prefix("beep_tone ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let freq: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(440.0);
            let dur_ms: u64 = parse_i64_loose(&resolve_arg(&args[1], vars, oop)).max(1) as u64;
            // generate WAV in-memory then send to aplay/paplay (Linux) or
            // print BEL on platforms without an audio cmd available.
            std::thread::spawn(move || {
                let _ = play_tone(freq, dur_ms);
            });
        }
        return true;
    }

    // ===== REAL AUDIO PLAYBACK (v2.0) =====
    //
    //   gui_audio_play "path/to/file.wav"
    //   gui_audio_play "music.mp3"
    //   gui_audio_stop_all
    //
    // Spawns the platform's default audio player as a background process.
    // Supports WAV / MP3 (and whatever else the player understands).
    //   Linux:   ffplay > paplay > aplay  (whichever is installed)
    //   macOS:   afplay
    //   Windows: PowerShell Media.SoundPlayer for WAV; ffplay for MP3
    if let Some(rest) = line.strip_prefix("gui_audio_play ") {
        use std::process::{Command, Stdio};
        let path = resolve_arg(rest.trim(), vars, oop);
        let stripped = strip_outer_quotes(&path).to_string();

        #[cfg(target_os = "linux")]
        {
            // Try players in preference order until one spawns.
            let attempts: &[(&str, &[&str])] = &[
                ("ffplay", &["-nodisp", "-autoexit", "-loglevel", "quiet"]),
                ("paplay", &[]),
                ("aplay",  &["-q"]),
                ("mpg123", &["-q"]),
            ];
            for (bin, flags) in attempts {
                let spawn = Command::new(bin)
                    .args(*flags)
                    .arg(&stripped)
                    .stdin(Stdio::null())
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .spawn();
                if spawn.is_ok() { break; }
            }
        }
        #[cfg(target_os = "macos")]
        {
            let _ = Command::new("afplay")
                .arg(&stripped)
                .stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null())
                .spawn();
        }
        #[cfg(target_os = "windows")]
        {
            let is_mp3 = stripped.to_lowercase().ends_with(".mp3");
            if is_mp3 {
                let _ = Command::new("ffplay")
                    .args(["-nodisp", "-autoexit", "-loglevel", "quiet"])
                    .arg(&stripped)
                    .stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null())
                    .spawn();
            } else {
                // WAV via PowerShell — synchronous but works out of the box.
                let ps = format!(
                    "(New-Object Media.SoundPlayer '{}').Play()",
                    stripped.replace('\'', "''")
                );
                let _ = Command::new("powershell")
                    .args(["-NoProfile", "-Command", &ps])
                    .stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null())
                    .spawn();
            }
        }
        return true;
    }

    // gui_audio_stop_all — kill every audio process this user is running.
    // Blunt but effective: pkill by name for the common players.
    if line == "gui_audio_stop_all" {
        use std::process::{Command, Stdio};
        #[cfg(any(target_os = "linux", target_os = "macos"))]
        {
            for bin in ["ffplay", "paplay", "aplay", "mpg123", "afplay"] {
                let _ = Command::new("pkill")
                    .args(["-f", bin])
                    .stdout(Stdio::null()).stderr(Stdio::null())
                    .spawn();
            }
        }
        #[cfg(target_os = "windows")]
        {
            for bin in ["ffplay.exe", "powershell.exe"] {
                let _ = Command::new("taskkill")
                    .args(["/F", "/IM", bin])
                    .stdout(Stdio::null()).stderr(Stdio::null())
                    .spawn();
            }
        }
        return true;
    }

    // ===== PERLIN NOISE =====
    // noise x y -> var   (returns value in [-1, 1])
    if let Some(rest) = line.strip_prefix("noise ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let x: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let y: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let n = perlin2(x, y);
            apply_return(vars, oop, result_var, Some(format!("{}", n)));
        }
        return true;
    }

    // ===== STATISTICS on lists =====

    // Helper: get list as Vec<f64>, parses each item, skips non-numeric
    fn list_as_f64(name: &str, oop: &OopState) -> Vec<f64> {
        oop.lists.get(name)
            .map(|l| l.iter().filter_map(|s| s.trim().parse::<f64>().ok()).collect())
            .unwrap_or_default()
    }

    // stats_median listname -> var
    if let Some(rest) = line.strip_prefix("stats_median ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let name = parts[0].trim();
        let mut nums = list_as_f64(name, oop);
        nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
        let med = if nums.is_empty() { 0.0 }
            else if nums.len() % 2 == 1 { nums[nums.len()/2] }
            else { (nums[nums.len()/2 - 1] + nums[nums.len()/2]) / 2.0 };
        apply_return(vars, oop, var, Some(format!("{}", med)));
        return true;
    }

    // stats_variance listname -> var  (population variance)
    if let Some(rest) = line.strip_prefix("stats_variance ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let nums = list_as_f64(parts[0].trim(), oop);
        let v = if nums.is_empty() { 0.0 } else {
            let mean = nums.iter().sum::<f64>() / nums.len() as f64;
            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64
        };
        apply_return(vars, oop, var, Some(format!("{}", v)));
        return true;
    }

    // stats_stddev listname -> var
    if let Some(rest) = line.strip_prefix("stats_stddev ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let nums = list_as_f64(parts[0].trim(), oop);
        let sd = if nums.is_empty() { 0.0 } else {
            let mean = nums.iter().sum::<f64>() / nums.len() as f64;
            (nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64).sqrt()
        };
        apply_return(vars, oop, var, Some(format!("{}", sd)));
        return true;
    }

    // stats_mode listname -> var  (most frequent value; first tied wins)
    if let Some(rest) = line.strip_prefix("stats_mode ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let name = parts[0].trim();
        let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
        if let Some(l) = oop.lists.get(name) {
            for s in l { *counts.entry(s.clone()).or_insert(0) += 1; }
        }
        let mode_val = counts.into_iter().max_by_key(|(_, c)| *c).map(|(s, _)| s).unwrap_or_default();
        apply_return(vars, oop, var, Some(mode_val));
        return true;
    }

    // stats_range listname -> var   (max - min)
    if let Some(rest) = line.strip_prefix("stats_range ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let nums = list_as_f64(parts[0].trim(), oop);
        let r = if nums.is_empty() { 0.0 } else {
            let mn = nums.iter().cloned().fold(f64::INFINITY, f64::min);
            let mx = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
            mx - mn
        };
        apply_return(vars, oop, var, Some(format!("{}", r)));
        return true;
    }

    // stats_percentile listname p -> var  (p in [0, 100])
    if let Some(rest) = line.strip_prefix("stats_percentile ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let mut nums = list_as_f64(args[0].trim(), oop);
            let p: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(50.0);
            nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
            let val = if nums.is_empty() { 0.0 } else {
                let idx = (p / 100.0 * (nums.len() - 1) as f64).round() as usize;
                nums[idx.min(nums.len() - 1)]
            };
            apply_return(vars, oop, var, Some(format!("{}", val)));
        }
        return true;
    }

    // ===== VECTOR MATH (vec3) =====
    // Vectors stored as comma-separated "x,y,z" strings.

    // vec3_add "ax,ay,az" "bx,by,bz" -> var
    if let Some(rest) = line.strip_prefix("vec3_add ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec3(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec3(&resolve_arg(&args[1], vars, oop));
            apply_return(vars, oop, var, Some(format!("{},{},{}", a.0+b.0, a.1+b.1, a.2+b.2)));
        }
        return true;
    }
    // vec3_sub
    if let Some(rest) = line.strip_prefix("vec3_sub ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec3(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec3(&resolve_arg(&args[1], vars, oop));
            apply_return(vars, oop, var, Some(format!("{},{},{}", a.0-b.0, a.1-b.1, a.2-b.2)));
        }
        return true;
    }
    // vec3_scale "x,y,z" s -> var
    if let Some(rest) = line.strip_prefix("vec3_scale ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec3(&resolve_arg(&args[0], vars, oop));
            let s: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1.0);
            apply_return(vars, oop, var, Some(format!("{},{},{}", a.0*s, a.1*s, a.2*s)));
        }
        return true;
    }
    // vec3_dot a b -> var
    if let Some(rest) = line.strip_prefix("vec3_dot ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec3(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec3(&resolve_arg(&args[1], vars, oop));
            apply_return(vars, oop, var, Some(format!("{}", a.0*b.0 + a.1*b.1 + a.2*b.2)));
        }
        return true;
    }
    // vec3_cross a b -> var
    if let Some(rest) = line.strip_prefix("vec3_cross ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec3(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec3(&resolve_arg(&args[1], vars, oop));
            let cx = a.1*b.2 - a.2*b.1;
            let cy = a.2*b.0 - a.0*b.2;
            let cz = a.0*b.1 - a.1*b.0;
            apply_return(vars, oop, var, Some(format!("{},{},{}", cx, cy, cz)));
        }
        return true;
    }
    // vec3_length a -> var
    if let Some(rest) = line.strip_prefix("vec3_length ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let a = parse_vec3(&resolve_arg(parts[0].trim(), vars, oop));
        let l = (a.0*a.0 + a.1*a.1 + a.2*a.2).sqrt();
        apply_return(vars, oop, var, Some(format!("{}", l)));
        return true;
    }
    // vec3_normalize a -> var
    if let Some(rest) = line.strip_prefix("vec3_normalize ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let a = parse_vec3(&resolve_arg(parts[0].trim(), vars, oop));
        let l = (a.0*a.0 + a.1*a.1 + a.2*a.2).sqrt().max(1e-12);
        apply_return(vars, oop, var, Some(format!("{},{},{}", a.0/l, a.1/l, a.2/l)));
        return true;
    }
    // vec3_distance a b -> var
    if let Some(rest) = line.strip_prefix("vec3_distance ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec3(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec3(&resolve_arg(&args[1], vars, oop));
            let dx = a.0-b.0; let dy = a.1-b.1; let dz = a.2-b.2;
            let d = (dx*dx + dy*dy + dz*dz).sqrt();
            apply_return(vars, oop, var, Some(format!("{}", d)));
        }
        return true;
    }
    // vec3_lerp a b t -> var
    if let Some(rest) = line.strip_prefix("vec3_lerp ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 3 {
            let a = parse_vec3(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec3(&resolve_arg(&args[1], vars, oop));
            let t: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            apply_return(vars, oop, var,
                Some(format!("{},{},{}", a.0+(b.0-a.0)*t, a.1+(b.1-a.1)*t, a.2+(b.2-a.2)*t)));
        }
        return true;
    }

    // ===== CSV =====
    // csv_read "path" target_list   — reads file, stores each row as comma-separated string
    if let Some(rest) = line.strip_prefix("csv_read ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let path = expand_path(&resolve_arg(&args[0], vars, oop));
            let target = args[1].trim().trim_matches('"').to_string();
            match fs::read_to_string(&path) {
                Ok(text) => {
                    let rows: Vec<String> = text.lines().map(|s| s.to_string()).collect();
                    oop.lists.insert(target, rows);
                }
                Err(e) => println!("csv_read failed: {}", e),
            }
        }
        return true;
    }

    // csv_write list "path"
    if let Some(rest) = line.strip_prefix("csv_write ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = args[0].trim().trim_matches('"');
            let path = expand_path(&resolve_arg(&args[1], vars, oop));
            if let Some(rows) = oop.lists.get(name) {
                let text = rows.join("\n");
                if let Err(e) = fs::write(&path, text) {
                    println!("csv_write failed: {}", e);
                }
            }
        }
        return true;
    }

    // ===== VEC2 (2D vectors as "x,y" strings) =====
    fn parse_vec2_s(s: &str) -> (f64, f64) {
        let nums: Vec<f64> = s.split(',').map(|t| t.trim().parse::<f64>().unwrap_or(0.0)).collect();
        (nums.first().copied().unwrap_or(0.0), nums.get(1).copied().unwrap_or(0.0))
    }

    if let Some(rest) = line.strip_prefix("vec2_add ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec2_s(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec2_s(&resolve_arg(&args[1], vars, oop));
            apply_return(vars, oop, var, Some(format!("{},{}", a.0+b.0, a.1+b.1)));
        }
        return true;
    }
    if let Some(rest) = line.strip_prefix("vec2_sub ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec2_s(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec2_s(&resolve_arg(&args[1], vars, oop));
            apply_return(vars, oop, var, Some(format!("{},{}", a.0-b.0, a.1-b.1)));
        }
        return true;
    }
    if let Some(rest) = line.strip_prefix("vec2_scale ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec2_s(&resolve_arg(&args[0], vars, oop));
            let s: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1.0);
            apply_return(vars, oop, var, Some(format!("{},{}", a.0*s, a.1*s)));
        }
        return true;
    }
    if let Some(rest) = line.strip_prefix("vec2_dot ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec2_s(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec2_s(&resolve_arg(&args[1], vars, oop));
            apply_return(vars, oop, var, Some(format!("{}", a.0*b.0 + a.1*b.1)));
        }
        return true;
    }
    if let Some(rest) = line.strip_prefix("vec2_length ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let a = parse_vec2_s(&resolve_arg(parts[0].trim(), vars, oop));
        apply_return(vars, oop, var, Some(format!("{}", (a.0*a.0 + a.1*a.1).sqrt())));
        return true;
    }
    if let Some(rest) = line.strip_prefix("vec2_normalize ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let a = parse_vec2_s(&resolve_arg(parts[0].trim(), vars, oop));
        let l = (a.0*a.0 + a.1*a.1).sqrt().max(1e-12);
        apply_return(vars, oop, var, Some(format!("{},{}", a.0/l, a.1/l)));
        return true;
    }
    if let Some(rest) = line.strip_prefix("vec2_distance ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let a = parse_vec2_s(&resolve_arg(&args[0], vars, oop));
            let b = parse_vec2_s(&resolve_arg(&args[1], vars, oop));
            let dx = a.0-b.0; let dy = a.1-b.1;
            apply_return(vars, oop, var, Some(format!("{}", (dx*dx+dy*dy).sqrt())));
        }
        return true;
    }
    if let Some(rest) = line.strip_prefix("vec2_angle ") {
        // angle in radians for "x,y"
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let a = parse_vec2_s(&resolve_arg(parts[0].trim(), vars, oop));
        apply_return(vars, oop, var, Some(format!("{}", a.1.atan2(a.0))));
        return true;
    }

    // ===== MATH HELPERS =====
    // smoothstep edge0 edge1 x -> var  (Hermite interpolation 0..1)
    if let Some(rest) = line.strip_prefix("smoothstep ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 3 {
            let e0: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let e1: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1.0);
            let x: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let t = ((x - e0) / (e1 - e0)).clamp(0.0, 1.0);
            apply_return(vars, oop, var, Some(format!("{}", t * t * (3.0 - 2.0 * t))));
        }
        return true;
    }

    // ===== COLOR UTILITIES =====
    // hsv_to_rgb h s v -> var  (h: 0-360, s/v: 0-1; output as #rrggbb)
    if let Some(rest) = line.strip_prefix("hsv_to_rgb ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 3 {
            let h: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let s: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let v: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let c = v * s;
            let h_prime = ((h % 360.0) / 60.0).abs();
            let x = c * (1.0 - ((h_prime % 2.0) - 1.0).abs());
            let (r1, g1, b1) = match h_prime as i32 {
                0 => (c, x, 0.0),
                1 => (x, c, 0.0),
                2 => (0.0, c, x),
                3 => (0.0, x, c),
                4 => (x, 0.0, c),
                _ => (c, 0.0, x),
            };
            let m = v - c;
            let r = ((r1 + m) * 255.0) as u32;
            let g = ((g1 + m) * 255.0) as u32;
            let b = ((b1 + m) * 255.0) as u32;
            apply_return(vars, oop, var, Some(format!("#{:02x}{:02x}{:02x}", r, g, b)));
        }
        return true;
    }

    // rgb_to_hsv "#rrggbb" -> var (output "h,s,v")
    if let Some(rest) = line.strip_prefix("rgb_to_hsv ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let hex = resolve_arg(parts[0].trim(), vars, oop);
        let packed = color_to_u32(&hex);
        let r = ((packed >> 16) & 0xFF) as f64 / 255.0;
        let g = ((packed >> 8) & 0xFF) as f64 / 255.0;
        let b = (packed & 0xFF) as f64 / 255.0;
        let max = r.max(g).max(b);
        let min = r.min(g).min(b);
        let d = max - min;
        let h = if d.abs() < 1e-9 { 0.0 }
            else if (max - r).abs() < 1e-9 { 60.0 * (((g - b) / d) % 6.0) }
            else if (max - g).abs() < 1e-9 { 60.0 * ((b - r) / d + 2.0) }
            else { 60.0 * ((r - g) / d + 4.0) };
        let h = if h < 0.0 { h + 360.0 } else { h };
        let s = if max < 1e-9 { 0.0 } else { d / max };
        apply_return(vars, oop, var, Some(format!("{},{},{}", h, s, max)));
        return true;
    }

    // color_lerp "#aabbcc" "#112233" t -> var
    if let Some(rest) = line.strip_prefix("color_lerp ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 3 {
            let a = color_to_u32(&resolve_arg(&args[0], vars, oop));
            let b = color_to_u32(&resolve_arg(&args[1], vars, oop));
            let t: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
            let lerp_ch = |c1: u32, c2: u32| -> u32 {
                (c1 as f64 + (c2 as f64 - c1 as f64) * t).clamp(0.0, 255.0) as u32
            };
            let r = lerp_ch((a >> 16) & 0xFF, (b >> 16) & 0xFF);
            let g = lerp_ch((a >> 8) & 0xFF, (b >> 8) & 0xFF);
            let bc = lerp_ch(a & 0xFF, b & 0xFF);
            apply_return(vars, oop, var, Some(format!("#{:02x}{:02x}{:02x}", r, g, bc)));
        }
        return true;
    }

    // ===== STRING UTILITIES =====
    // pad_right "txt" width "char" -> var
    if let Some(rest) = line.strip_prefix("pad_right ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() >= 2 {
            let s = resolve_arg(&args[0], vars, oop);
            let w: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let pad = if args.len() >= 3 {
                resolve_arg(&args[2], vars, oop).chars().next().unwrap_or(' ')
            } else { ' ' };
            let needed = w.saturating_sub(s.chars().count());
            let mut out = s.clone();
            for _ in 0..needed { out.push(pad); }
            apply_return(vars, oop, var, Some(out));
        }
        return true;
    }

    // center_str "txt" width "char" -> var
    if let Some(rest) = line.strip_prefix("center_str ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() >= 2 {
            let s = resolve_arg(&args[0], vars, oop);
            let w: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0);
            let pad = if args.len() >= 3 {
                resolve_arg(&args[2], vars, oop).chars().next().unwrap_or(' ')
            } else { ' ' };
            let len = s.chars().count();
            let total = w.saturating_sub(len);
            let left = total / 2;
            let right = total - left;
            let mut out = String::new();
            for _ in 0..left { out.push(pad); }
            out.push_str(&s);
            for _ in 0..right { out.push(pad); }
            apply_return(vars, oop, var, Some(out));
        }
        return true;
    }

    // ===== LIST UTILITIES =====
    // list_unique listname target  — copy unique values preserving order
    if let Some(rest) = line.strip_prefix("list_unique ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let src = args[0].trim();
            let dst = args[1].trim().to_string();
            let mut seen = std::collections::HashSet::new();
            let mut out = Vec::new();
            if let Some(l) = oop.lists.get(src) {
                for item in l {
                    if seen.insert(item.clone()) {
                        out.push(item.clone());
                    }
                }
            }
            oop.lists.insert(dst, out);
        }
        return true;
    }

    // list_zip a b target  — interleave items into "a_i,b_i" strings
    if let Some(rest) = line.strip_prefix("list_zip ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let a = args[0].trim();
            let b = args[1].trim();
            let dst = args[2].trim().to_string();
            let av: Vec<String> = oop.lists.get(a).cloned().unwrap_or_default();
            let bv: Vec<String> = oop.lists.get(b).cloned().unwrap_or_default();
            let n = av.len().min(bv.len());
            let mut out = Vec::with_capacity(n);
            for i in 0..n {
                out.push(format!("{},{}", av[i], bv[i]));
            }
            oop.lists.insert(dst, out);
        }
        return true;
    }

    // list_chunk listname size target  — split into N-sized chunks (comma-joined)
    if let Some(rest) = line.strip_prefix("list_chunk ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let src = args[0].trim();
            let size: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(1).max(1);
            let dst = args[2].trim().to_string();
            let mut out: Vec<String> = Vec::new();
            if let Some(l) = oop.lists.get(src) {
                for chunk in l.chunks(size) {
                    out.push(chunk.join("|"));
                }
            }
            oop.lists.insert(dst, out);
        }
        return true;
    }

    // ===== TERMINAL TUI =====
    // tui_box width height "title"  — draws a Unicode box with title
    if let Some(rest) = line.strip_prefix("tui_box ") {
        let args = split_args(rest);
        if args.len() >= 2 {
            let w: usize = resolve_arg(&args[0], vars, oop).parse().unwrap_or(40);
            let h: usize = resolve_arg(&args[1], vars, oop).parse().unwrap_or(5);
            let title = if args.len() >= 3 { resolve_arg(&args[2], vars, oop) } else { String::new() };
            if w >= 4 {
                let inner = w.saturating_sub(2);
                let title_show = if title.is_empty() { String::new() } else { format!(" {} ", title) };
                let tlen = title_show.chars().count();
                let left_pad = (inner.saturating_sub(tlen)) / 2;
                let right_pad = inner.saturating_sub(tlen).saturating_sub(left_pad);
                let mut top = String::from("┌");
                for _ in 0..left_pad { top.push('─'); }
                top.push_str(&title_show);
                for _ in 0..right_pad { top.push('─'); }
                top.push('┐');
                println!("{}", top);
                for _ in 0..h.saturating_sub(2) {
                    let mut row = String::from("│");
                    for _ in 0..inner { row.push(' '); }
                    row.push('│');
                    println!("{}", row);
                }
                let mut bot = String::from("└");
                for _ in 0..inner { bot.push('─'); }
                bot.push('┘');
                println!("{}", bot);
            }
        }
        return true;
    }

    // tui_progress current total width  — prints a progress bar
    if let Some(rest) = line.strip_prefix("tui_progress ") {
        let args = split_args(rest);
        if args.len() >= 2 {
            let cur: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let total: f64 = resolve_arg(&args[1], vars, oop).parse::<f64>().unwrap_or(1.0).max(0.0001_f64);
            let width: usize = if args.len() >= 3 {
                resolve_arg(&args[2], vars, oop).parse().unwrap_or(40)
            } else { 40 };
            let pct = (cur / total).clamp(0.0, 1.0);
            let filled = (pct * width as f64) as usize;
            let mut bar = String::from("[");
            for i in 0..width {
                bar.push(if i < filled { '█' } else { '░' });
            }
            bar.push_str(&format!("] {:>5.1}%", pct * 100.0));
            println!("{}", bar);
        }
        return true;
    }

    // ============================================================
    //  2D ENGINE — sprite loading, camera, tilemap, image drawing
    // ============================================================

    // gui_2d_load_image "name" "path.png|ppm"
    if let Some(rest) = line.strip_prefix("gui_2d_load_image ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = resolve_arg(&args[0], vars, oop);
            let path = expand_path(&resolve_arg(&args[1], vars, oop));
            match std::fs::read(&path) {
                Ok(data) => {
                    if let Some(img) = load_texture_bytes(&data) {
                        let (_, w, h) = (&img.0, img.1, img.2);
                        let (w, h) = (w, h);
                        println!("\x1b[36m[2d]\x1b[0m loaded {} ({}x{})", name, w, h);
                        GUI_2D_IMAGES.with(|m| m.borrow_mut().insert(name, img));
                    } else {
                        println!("gui_2d_load_image: unrecognized format");
                    }
                }
                Err(e) => println!("gui_2d_load_image: {}", e),
            }
        }
        return true;
    }

    // gui_2d_load_image_url "name" "https://..."
    if let Some(rest) = line.strip_prefix("gui_2d_load_image_url ") {
        let args = split_args(rest);
        if args.len() == 2 {
            let name = resolve_arg(&args[0], vars, oop);
            let url = resolve_arg(&args[1], vars, oop);
            match reqwest::blocking::get(&url).and_then(|r| r.bytes()) {
                Ok(bytes) => {
                    if let Some(img) = load_texture_bytes(&bytes) {
                        let (w, h) = (img.1, img.2);
                        println!("\x1b[36m[2d]\x1b[0m loaded {} from URL ({}x{})", name, w, h);
                        GUI_2D_IMAGES.with(|m| m.borrow_mut().insert(name, img));
                    } else { println!("gui_2d_load_image_url: format unrecognized"); }
                }
                Err(e) => println!("gui_2d_load_image_url failed: {}", e),
            }
        }
        return true;
    }

    // gui_2d_image_size "name" w_var h_var  -- query width/height
    if let Some(rest) = line.strip_prefix("gui_2d_image_size ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let name = resolve_arg(&args[0], vars, oop);
            let w_var = args[1].trim().to_string();
            let h_var = args[2].trim().to_string();
            let (w, h) = GUI_2D_IMAGES.with(|m| {
                m.borrow().get(&name).map(|(_, w, h)| (*w as i64, *h as i64)).unwrap_or((0, 0))
            });
            vars.insert(w_var, w);
            vars.insert(h_var, h);
        }
        return true;
    }

    // gui_2d_draw_image x y "name"   -- draw at top-left (x,y) at native size
    if let Some(rest) = line.strip_prefix("gui_2d_draw_image ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let x: i32 = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y: i32 = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let name = resolve_arg(&args[2], vars, oop);
            draw_image_internal(x, y, -1, -1, &name, None);
        }
        return true;
    }

    // gui_2d_draw_image_scaled x y w h "name"  -- stretched
    if let Some(rest) = line.strip_prefix("gui_2d_draw_image_scaled ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let w = parse_i64_loose(&resolve_arg(&args[2], vars, oop)) as i32;
            let h = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as i32;
            let name = resolve_arg(&args[4], vars, oop);
            draw_image_internal(x, y, w, h, &name, None);
        }
        return true;
    }

    // gui_2d_draw_image_region x y "name" sx sy sw sh  -- crop source region
    if let Some(rest) = line.strip_prefix("gui_2d_draw_image_region ") {
        let args = split_args(rest);
        if args.len() == 7 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let name = resolve_arg(&args[2], vars, oop);
            let sx = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as i32;
            let sy = parse_i64_loose(&resolve_arg(&args[4], vars, oop)) as i32;
            let sw = parse_i64_loose(&resolve_arg(&args[5], vars, oop)) as i32;
            let sh = parse_i64_loose(&resolve_arg(&args[6], vars, oop)) as i32;
            draw_image_internal(x, y, -1, -1, &name, Some((sx, sy, sw, sh)));
        }
        return true;
    }

    // gui_2d_smooth on|off  — toggle bilinear sampling for image draws
    if let Some(rest) = line.strip_prefix("gui_2d_smooth ") {
        let v = resolve_arg(rest.trim(), vars, oop).to_lowercase();
        let on = matches!(v.as_str(), "on" | "1" | "true" | "yes");
        GUI_2D_SMOOTH.with(|c| c.set(on));
        return true;
    }

    // gui_2d_draw_image_rotated x y w h "name" angle_rad
    if let Some(rest) = line.strip_prefix("gui_2d_draw_image_rotated ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let w = parse_i64_loose(&resolve_arg(&args[2], vars, oop)) as i32;
            let h = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as i32;
            let name = resolve_arg(&args[4], vars, oop);
            let angle: f32 = resolve_arg(&args[5], vars, oop).parse().unwrap_or(0.0);
            let mut f = DrawFlags::default();
            f.rotation = angle;
            draw_image_extended(x, y, w, h, &name, None, f);
        }
        return true;
    }

    // gui_2d_draw_image_flipped x y w h "name" flip_x flip_y
    if let Some(rest) = line.strip_prefix("gui_2d_draw_image_flipped ") {
        let args = split_args(rest);
        if args.len() == 7 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let w = parse_i64_loose(&resolve_arg(&args[2], vars, oop)) as i32;
            let h = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as i32;
            let name = resolve_arg(&args[4], vars, oop);
            let fx = parse_i64_loose(&resolve_arg(&args[5], vars, oop)) != 0;
            let fy = parse_i64_loose(&resolve_arg(&args[6], vars, oop)) != 0;
            let mut f = DrawFlags::default();
            f.flip_x = fx;
            f.flip_y = fy;
            draw_image_extended(x, y, w, h, &name, None, f);
        }
        return true;
    }

    // gui_2d_draw_image_tinted x y w h "name" "color"
    if let Some(rest) = line.strip_prefix("gui_2d_draw_image_tinted ") {
        let args = split_args(rest);
        if args.len() == 6 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let w = parse_i64_loose(&resolve_arg(&args[2], vars, oop)) as i32;
            let h = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as i32;
            let name = resolve_arg(&args[4], vars, oop);
            let tint = color_to_u32(&resolve_arg(&args[5], vars, oop));
            let mut f = DrawFlags::default();
            f.tint = Some(tint);
            draw_image_extended(x, y, w, h, &name, None, f);
        }
        return true;
    }

    // gui_2d_draw_image_ex x y w h "name" angle flip_x flip_y "tint"
    // Combo command — everything at once
    if let Some(rest) = line.strip_prefix("gui_2d_draw_image_ex ") {
        let args = split_args(rest);
        if args.len() == 9 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let w = parse_i64_loose(&resolve_arg(&args[2], vars, oop)) as i32;
            let h = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as i32;
            let name = resolve_arg(&args[4], vars, oop);
            let angle: f32 = resolve_arg(&args[5], vars, oop).parse().unwrap_or(0.0);
            let fx = parse_i64_loose(&resolve_arg(&args[6], vars, oop)) != 0;
            let fy = parse_i64_loose(&resolve_arg(&args[7], vars, oop)) != 0;
            let tint_s = resolve_arg(&args[8], vars, oop);
            let tint = if tint_s.is_empty() || tint_s == "0" { None }
                       else { Some(color_to_u32(&tint_s)) };
            let f = DrawFlags { flip_x: fx, flip_y: fy, rotation: angle, tint };
            draw_image_extended(x, y, w, h, &name, None, f);
        }
        return true;
    }

    // gui_2d_camera x y zoom
    if let Some(rest) = line.strip_prefix("gui_2d_camera ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let x: f32 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
            let y: f32 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
            let z: f32 = resolve_arg(&args[2], vars, oop).parse::<f32>().unwrap_or(1.0).max(0.01_f32);
            GUI_2D_CAM_X.with(|c| c.set(x));
            GUI_2D_CAM_Y.with(|c| c.set(y));
            GUI_2D_CAM_ZOOM.with(|c| c.set(z));
        }
        return true;
    }

    // gui_2d_camera_reset
    if line == "gui_2d_camera_reset" {
        GUI_2D_CAM_X.with(|c| c.set(0.0));
        GUI_2D_CAM_Y.with(|c| c.set(0.0));
        GUI_2D_CAM_ZOOM.with(|c| c.set(1.0));
        return true;
    }

    // gui_2d_color_key "color"  -- pixels of this color in images aren't drawn
    if let Some(rest) = line.strip_prefix("gui_2d_color_key ") {
        let s = resolve_arg(rest.trim(), vars, oop);
        if s.to_lowercase() == "off" {
            GUI_2D_COLOR_KEY_ENABLED.with(|c| c.set(false));
        } else {
            GUI_2D_COLOR_KEY.with(|c| c.set(color_to_u32(&s)));
            GUI_2D_COLOR_KEY_ENABLED.with(|c| c.set(true));
        }
        return true;
    }

    // gui_2d_load_tileset "name" "image_name" tile_w tile_h
    if let Some(rest) = line.strip_prefix("gui_2d_load_tileset ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let name = resolve_arg(&args[0], vars, oop);
            let img = resolve_arg(&args[1], vars, oop);
            let tw = parse_i64_loose(&resolve_arg(&args[2], vars, oop)) as usize;
            let th = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as usize;
            GUI_2D_TILESETS.with(|m| m.borrow_mut().insert(name, (img, tw, th)));
        }
        return true;
    }

    // gui_2d_draw_tile x y "tileset" index
    if let Some(rest) = line.strip_prefix("gui_2d_draw_tile ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop)) as i32;
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop)) as i32;
            let name = resolve_arg(&args[2], vars, oop);
            let idx = parse_i64_loose(&resolve_arg(&args[3], vars, oop)) as usize;
            let info = GUI_2D_TILESETS.with(|m| m.borrow().get(&name).cloned());
            if let Some((img_name, tw, th)) = info {
                // figure out tiles per row from image width
                let img_w = GUI_2D_IMAGES.with(|m| m.borrow().get(&img_name).map(|(_, w, _)| *w).unwrap_or(0));
                if img_w > 0 && tw > 0 {
                    let per_row = img_w / tw;
                    let tx = (idx % per_row) * tw;
                    let ty = (idx / per_row) * th;
                    draw_image_internal(x, y, tw as i32, th as i32, &img_name,
                        Some((tx as i32, ty as i32, tw as i32, th as i32)));
                }
            }
        }
        return true;
    }

    // gui_2d_text_outline x y "text" "color" "outline"
    if let Some(rest) = line.strip_prefix("gui_2d_text_outline ") {
        let args = split_args(rest);
        if args.len() == 5 {
            let x = parse_i64_loose(&resolve_arg(&args[0], vars, oop));
            let y = parse_i64_loose(&resolve_arg(&args[1], vars, oop));
            let text = resolve_arg(&args[2], vars, oop);
            let color = resolve_arg(&args[3], vars, oop);
            let outline = resolve_arg(&args[4], vars, oop);
            // outline by drawing text shifted in 8 directions
            for (dx, dy) in &[(-1,0),(1,0),(0,-1),(0,1),(-1,-1),(1,-1),(-1,1),(1,1)] {
                let cmd = format!("gui_text {} {} \"{}\" \"{}\"", x+dx, y+dy, text, outline);
                execute(&cmd, vars, server_cfg, oop);
            }
            let cmd = format!("gui_text {} {} \"{}\" \"{}\"", x, y, text, color);
            execute(&cmd, vars, server_cfg, oop);
        }
        return true;
    }

    // gui_window title -- shorthand: shows a centered title window in a browser
    if let Some(rest) = line.strip_prefix("gui_window ") {
        let title = resolve_arg(rest.trim(), vars, oop);
        let html = format!(
            "<!DOCTYPE html><html><head><title>{}</title><style>\
             body{{font-family:sans-serif;display:flex;align-items:center;justify-content:center;\
             height:100vh;margin:0;background:#1e1e1e;color:#eee}}\
             h1{{font-size:3em}}</style></head><body><h1>{}</h1></body></html>",
            html_escape_str(&title),
            html_escape_str(&title)
        );
        let tmp = env::temp_dir().join(format!("ayaan_win_{}.html", std::process::id()));
        if fs::write(&tmp, &html).is_ok() {
            let opener = if cfg!(target_os = "macos") {
                "open"
            } else if cfg!(target_os = "windows") {
                "cmd"
            } else {
                "xdg-open"
            };
            let _ = Command::new(opener).arg(&tmp).spawn();
        }
        return true;
    }

    // ===== LIST OF DICTS (composite key API) =====
    // ld_set listname idx field value — store a field on the idx'th element
    if let Some(rest) = line.strip_prefix("ld_set ") {
        let args = split_args(rest);
        if args.len() == 4 {
            let name = args[0].trim();
            let idx = resolve_arg(&args[1], vars, oop);
            let field = resolve_arg(&args[2], vars, oop);
            let value = resolve_arg(&args[3], vars, oop);
            let composite_key = format!("__ld_{}_{}_{}", name, idx, field);
            oop.string_vars.insert(composite_key, value);
            // Track size — push idx if not present
            if let Some(l) = oop.lists.get_mut(name) {
                if !l.iter().any(|v| v == &idx) {
                    l.push(idx);
                }
            } else {
                oop.lists.insert(name.to_string(), vec![idx]);
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ld_get ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 3 {
            let name = args[0].trim();
            let idx = resolve_arg(&args[1], vars, oop);
            let field = resolve_arg(&args[2], vars, oop);
            let composite_key = format!("__ld_{}_{}_{}", name, idx, field);
            let v = oop.string_vars.get(&composite_key).cloned().unwrap_or_default();
            apply_return(vars, oop, result_var, Some(v));
        }
        return true;
    }

    // ===== SELF-HOSTING DOCS =====
    if let Some(rest) = line.strip_prefix("docs ") {
        let name = rest.trim();
        let doc = builtin_doc(name);
        println!("\x1b[36m{}\x1b[0m", name);
        println!("{}", doc);
        return true;
    }

    // ===== TOSTRING (explicit) =====
    if let Some(rest) = line.strip_prefix("tostring ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let inst_name = parts[0].trim().to_string();
        let class_of_inst = oop.instances.get(&inst_name).map(|i| i.class_name.clone());
        if let Some(cn) = class_of_inst {
            if let Some((owner, method)) =
                find_method_in_chain(&oop.classes, &cn, "tostring", None)
            {
                let captured = capture_call_return(
                    vars,
                    server_cfg,
                    oop,
                    Some(inst_name.clone()),
                    &method,
                    &[],
                    Some(owner),
                );
                if !captured.0 {
                    return false;
                }
                apply_return(vars, oop, result_var, captured.1);
                return true;
            }
            // No tostring defined — fall back to <Class:name>
            apply_return(
                vars,
                oop,
                result_var,
                Some(format!("<{}:{}>", cn, inst_name)),
            );
        } else {
            apply_return(vars, oop, result_var, Some(format!("<undefined:{}>", inst_name)));
        }
        return true;
    }

    // ===== PACKAGE ASSET ACCESS =====
    // pkg_asset_path pkgname assetfile -> var  — get full path to an installed package asset
    if let Some(rest) = line.strip_prefix("pkg_asset_path ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let pkg = resolve_arg(&args[0], vars, oop);
            let asset = resolve_arg(&args[1], vars, oop);
            let p = package_dir().join(&pkg).join(&asset);
            apply_return(vars, oop, result_var, Some(p.to_string_lossy().to_string()));
        }
        return true;
    }

    // pkg_asset_read pkg asset var  — read file content from package
    if let Some(rest) = line.strip_prefix("pkg_asset_read ") {
        let parts: Vec<&str> = rest.splitn(2, "->").collect();
        let result_var = parts.get(1).map(|s| s.trim().to_string());
        let args = split_args(parts[0]);
        if args.len() == 2 {
            let pkg = resolve_arg(&args[0], vars, oop);
            let asset = resolve_arg(&args[1], vars, oop);
            let p = package_dir().join(&pkg).join(&asset);
            let content = fs::read_to_string(&p).unwrap_or_default();
            apply_return(vars, oop, result_var, Some(content));
        }
        return true;
    }

    // pkg_db_open pkg dbfile alias — open a sqlite db that's bundled with a package
    if let Some(rest) = line.strip_prefix("pkg_db_open ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let pkg = resolve_arg(&args[0], vars, oop);
            let dbfile = resolve_arg(&args[1], vars, oop);
            let alias = resolve_arg(&args[2], vars, oop);
            let p = package_dir().join(&pkg).join(&dbfile);
            match rusqlite::Connection::open(&p) {
                Ok(conn) => { oop.db_connections.insert(alias, conn); }
                Err(e) => println!("pkg_db_open failed: {}", e),
            }
        }
        return true;
    }

    // pkg_run_sql pkg sqlfile alias — execute a .sql file from a package against an open db
    if let Some(rest) = line.strip_prefix("pkg_run_sql ") {
        let args = split_args(rest);
        if args.len() == 3 {
            let pkg = resolve_arg(&args[0], vars, oop);
            let sqlfile = resolve_arg(&args[1], vars, oop);
            let alias = resolve_arg(&args[2], vars, oop);
            let p = package_dir().join(&pkg).join(&sqlfile);
            match fs::read_to_string(&p) {
                Ok(sql) => {
                    if let Some(conn) = oop.db_connections.get(&alias) {
                        for stmt in sql.split(';').map(|s| s.trim()).filter(|s| !s.is_empty()) {
                            let _ = conn.execute(stmt, []);
                        }
                    }
                }
                Err(e) => println!("pkg_run_sql failed: {}", e),
            }
        }
        return true;
    }

    // ====== ALIAS BLOCK ======
    aka!("echo_p", "psyska -/");
    aka!("writeln", "psyska -/");
    aka!("out_msg", "psyska -/");
    aka!("log_out_msg", "psyska -/");
    aka!("puts_v", "psyska -/");
    aka!("tellme", "psyska -/");
    aka!("blab", "psyska -/");
    aka!("shout_msg", "psyska -/");
    aka!("yell_msg", "psyska -/");
    aka!("p_emit", "psyska -/");
    aka!("say_it", "psyska -/");
    aka!("tell_it", "psyska -/");
    aka!("send_text", "psyska -/");
    aka!("display_text", "psyska -/");
    aka!("render_text", "psyska -/");
    aka!("show_text", "psyska -/");
    aka!("stdout_print", "psyska -/");
    aka!("draw_text", "psyska -/");
    aka!("assign_var", "set");
    aka!("store_var", "set");
    aka!("save_var", "set");
    aka!("let_v", "set");
    aka!("place_var", "set");
    aka!("put_v", "set");
    aka!("bind_var", "set");
    aka!("define_var", "set");
    aka!("declare_var", "set");
    aka!("stash_var", "set");
    aka!("remember_v", "set");
    aka!("set_var", "set");
    aka!("spawn_var", "set");
    aka!("init_var", "set");
    aka!("set_field_v", "set");
    aka!("v_set", "set");
    aka!("var_set", "set");
    aka!("plus_add", "add");
    aka!("sum_into", "add");
    aka!("accumulate", "add");
    aka!("incr_by", "add");
    aka!("add_to_v", "add");
    aka!("addn", "add");
    aka!("addint", "add");
    aka!("add_val", "add");
    aka!("increase", "add");
    aka!("tally_in", "add");
    aka!("totalize", "add");
    aka!("addvar", "add");
    aka!("bumpup", "incr");
    aka!("pp_inc", "incr");
    aka!("advance_var", "incr");
    aka!("step_var", "incr");
    aka!("tick_var", "incr");
    aka!("rise_var", "incr");
    aka!("nudge_up", "incr");
    aka!("raise_var", "incr");
    aka!("growvar", "incr");
    aka!("boost_var", "incr");
    aka!("bumpdown", "decr");
    aka!("mm_dec", "decr");
    aka!("lower_var", "decr");
    aka!("reduce_var", "decr");
    aka!("ebb_var", "decr");
    aka!("nudge_down", "decr");
    aka!("shrink_var", "decr");
    aka!("slip_var", "decr");
    aka!("cut_var", "decr");
    aka!("trim_var", "decr");
    aka!("pickrand", "rand");
    aka!("random_n", "rand");
    aka!("random_int", "rand");
    aka!("rng_n", "rand");
    aka!("roll_n", "rand");
    aka!("pick_n", "rand");
    aka!("rand_v", "rand");
    aka!("rand_n2", "rand");
    aka!("rndi", "rand");
    aka!("rand_in_range", "rand");
    aka!("zzz", "sleep");
    aka!("siesta_for", "sleep");
    aka!("rest_secs", "sleep");
    aka!("nap_for", "sleep");
    aka!("halt_for", "sleep");
    aka!("block_for", "sleep");
    aka!("snooze", "sleep");
    aka!("pause_secs", "sleep");
    aka!("delay_secs", "sleep");
    aka!("hold_for", "sleep");
    aka!("clrscr", "clear");
    aka!("wipescr", "clear");
    aka!("blank_term", "clear");
    aka!("fresh", "clear");
    aka!("tidy_screen", "clear");
    aka!("reset_screen", "clear");
    aka!("w_file", "writefile");
    aka!("save_file", "writefile");
    aka!("out_file", "writefile");
    aka!("store_file", "writefile");
    aka!("dump_file", "writefile");
    aka!("emit_file", "writefile");
    aka!("r_file", "readfile");
    aka!("cat_file", "readfile");
    aka!("slurp_file", "readfile");
    aka!("load_file", "readfile");
    aka!("fetch_file", "readfile");
    aka!("import_file", "readfile");
    aka!("mk_dir", "mkdir");
    aka!("ensure_folder", "mkdir");
    aka!("make_folder", "mkdir");
    aka!("new_dir", "mkdir");
    aka!("create_folder", "mkdir");
    aka!("new_folder", "mkdir");
    aka!("spawn_dir", "mkdir");
    aka!("delete_path", "rm");
    aka!("wipe_path", "rm");
    aka!("kill_file", "rm");
    aka!("trash", "rm");
    aka!("unlink_file", "rm");
    aka!("del_path", "rm");
    aka!("destroy_file", "rm");
    aka!("new_list", "list");
    aka!("alloc_list", "list");
    aka!("make_list", "list");
    aka!("init_list", "list");
    aka!("create_list", "list");
    aka!("fresh_list", "list");
    aka!("build_list", "list");
    aka!("lappend2", "push");
    aka!("list_add", "push");
    aka!("queue_add", "push");
    aka!("stack_push2", "push");
    aka!("back_add", "push");
    aka!("tail_add", "push");
    aka!("p_back", "push");
    aka!("enqueue", "push");
    aka!("shove_back", "push");
    aka!("unstack", "pop");
    aka!("back_remove", "pop");
    aka!("p_back_off", "pop");
    aka!("yank_back", "pop");
    aka!("shift_back", "pop");
    aka!("dequeue_back", "pop");
    aka!("list_at", "lget");
    aka!("elem_at", "lget");
    aka!("fetch_at", "lget");
    aka!("peek_at", "lget");
    aka!("read_at", "lget");
    aka!("el", "lget");
    aka!("lat2", "lget");
    aka!("indexof_list", "lget");
    aka!("list_put_at", "lset");
    aka!("el_set", "lset");
    aka!("set_at", "lset");
    aka!("write_at", "lset");
    aka!("place_at", "lset");
    aka!("count_list", "lsize");
    aka!("elements", "lsize");
    aka!("len_list", "lsize");
    aka!("n_elems", "lsize");
    aka!("card", "lsize");
    aka!("list_len2", "lsize");
    aka!("new_dict", "dict");
    aka!("alloc_dict", "dict");
    aka!("make_dict", "dict");
    aka!("init_dict", "dict");
    aka!("create_dict", "dict");
    aka!("fresh_dict", "dict");
    aka!("build_dict", "dict");
    aka!("map_set", "dset");
    aka!("kv_set", "dset");
    aka!("dict_put", "dset");
    aka!("table_set", "dset");
    aka!("hm_set", "dset");
    aka!("map_get", "dget");
    aka!("kv_get", "dget");
    aka!("dict_read", "dget");
    aka!("table_get", "dget");
    aka!("hm_get", "dget");
    aka!("lookup_key", "dget");
    aka!("count_dict", "dsize");
    aka!("n_keys", "dsize");
    aka!("kv_count", "dsize");
    aka!("card_dict", "dsize");
    aka!("set_color", "color");
    aka!("term_color", "color");
    aka!("ansi_color", "color");
    aka!("quit_now", "exit");
    aka!("stop_run", "exit");
    aka!("bail_out", "exit");
    aka!("halt_now", "exit");
    aka!("kill_run", "exit");
    aka!("die_now", "exit");
    aka!("leave_run", "exit");
    aka!("end_run", "exit");
    aka!("shutdown_now", "exit");
    aka!("sh_capture", "ffi");
    aka!("shell_capture", "ffi");
    aka!("ffi_run", "ffi");
    aka!("sh_grab", "ffi");
    aka!("shell_cmd", "ffi");
    aka!("sh_run", "exec");
    aka!("shell_run", "exec");
    aka!("execute_cmd", "exec");
    aka!("system_run", "exec");
    aka!("spawn_sh", "exec");
    aka!("fetch", "http_get");
    aka!("request", "http_get");
    aka!("wget_str", "http_get");
    aka!("curl_get", "http_get");
    aka!("url_fetch", "http_get");
    aka!("web_get", "http_get");
    aka!("http_pull", "http_get");
    aka!("post_url", "http_post");
    aka!("submit", "http_post");
    aka!("send_post", "http_post");
    aka!("post_request", "http_post");
    aka!("curl_post", "http_post");
    aka!("digest_md5", "md5");
    aka!("hash_5", "md5");
    aka!("checksum_md5", "md5");
    aka!("md5_text", "md5");
    aka!("digest_sha256", "sha256");
    aka!("hash_256", "sha256");
    aka!("checksum_sha256", "sha256");
    aka!("sha256_text", "sha256");
    aka!("b64_enc", "base64_encode");
    aka!("encode_base64", "base64_encode");
    aka!("to_b64", "base64_encode");
    aka!("b64ify", "base64_encode");
    aka!("b64_dec", "base64_decode");
    aka!("decode_base64", "base64_decode");
    aka!("from_b64", "base64_decode");
    aka!("un_b64", "base64_decode");
    aka!("pattern_match", "regex_match");
    aka!("rreplace", "regex_replace");
    aka!("re_replace", "regex_replace");
    aka!("sub_re", "regex_replace");
    aka!("swap_re", "regex_replace");
    aka!("info_msg", "log info");
    aka!("i_msg", "log info");
    aka!("log_i", "log info");
    aka!("warn_msg", "log warn");
    aka!("w_msg", "log warn");
    aka!("log_w", "log warn");
    aka!("err_msg", "log error");
    aka!("logerror", "log error");
    aka!("log_e", "log error");
    aka!("dbg_msg", "log debug");
    aka!("d_msg", "log debug");
    aka!("log_d", "log debug");
    aka!("unix_now", "now");
    aka!("epoch_now", "now");
    aka!("tstamp", "now");
    aka!("today_date", "date_today");
    aka!("todays_date", "date_today");
    aka!("day_of_today", "date_today");
    aka!("current_date", "date_today");
    aka!("fmt_date", "datefmt");
    aka!("format_date_str", "datefmt");
    aka!("dt_format", "datefmt");
    aka!("msleep", "sleep_ms");
    aka!("msec_sleep", "sleep_ms");
    aka!("wait_ms", "sleep_ms");
    aka!("millis_sleep", "sleep_ms");
    aka!("pause_ms", "sleep_ms");
    aka!("plus_days", "add_days");
    aka!("days_plus", "add_days");
    aka!("future_days", "add_days");
    aka!("days_diff_v", "diff_days");
    aka!("delta_days", "diff_days");
    aka!("days_apart", "diff_days");
    aka!("print_table", "table");
    aka!("show_table", "table");
    aka!("render_table", "table");
    aka!("mini_chart", "sparkline");
    aka!("tinybar", "sparkline");
    aka!("bars", "barchart");
    aka!("horiz_chart", "barchart");
    aka!("hist_bar", "barchart");
    aka!("loader", "spin");
    aka!("throbber", "spin");
    aka!("spinner_show", "spin");
    aka!("new_uuid", "uuid");
    aka!("gen_guid", "uuid");
    aka!("make_uuid", "uuid");
    aka!("rand_uuid_v", "uuid");
    aka!("host_name", "hostname");
    aka!("machine_name", "hostname");
    aka!("computer_name", "hostname");
    aka!("escape_html", "html_escape");
    aka!("pct_encode", "url_escape");
    aka!("urlenc", "url_escape");
    aka!("open_db", "db_open");
    aka!("sqlite_open", "db_open");
    aka!("close_db", "db_close");
    aka!("sqlite_close", "db_close");
    aka!("sql_exec", "db_exec");
    aka!("db_run", "db_exec");
    aka!("sql_query", "db_query");
    aka!("db_select", "db_query");
    aka!("net_ping", "ping");
    aka!("is_up_ping", "ping");
    aka!("wget_file", "download");
    aka!("curl_dl", "download");
    aka!("fetch_file_url", "download");
    aka!("bg_run", "spawn");
    aka!("fork_cmd", "spawn");
    aka!("async_run", "spawn");
    aka!("UPPER", "uppercase");
    aka!("to_upper_text", "uppercase");
    aka!("loud_text", "uppercase");
    aka!("TO_LOWER", "lower");
    aka!("to_lower_text", "lower");
    aka!("quiet_text", "lower");
    aka!("strip", "trim");
    aka!("trim_ws", "trim");
    aka!("trim_spaces", "trim");
    aka!("rev_str", "reverse");
    aka!("backwards", "reverse");
    aka!("flip_str", "reverse");
    aka!("explode", "split");
    aka!("splat", "split");
    aka!("to_parts", "split");
    aka!("join_str", "concat");
    aka!("merge_str", "concat");
    aka!("combine_str", "concat");
    aka!("swap_text", "replace");
    aka!("sub_text", "replace");
    aka!("exchange", "replace");
    aka!("str_in", "contains");
    aka!("has_substr", "contains");
    aka!("includes", "contains");
    aka!("begins_with", "startswith");
    aka!("leads_with", "startswith");
    aka!("head_is", "startswith");
    aka!("tails_with", "endswith");
    aka!("ends_in", "endswith");
    aka!("tail_is", "endswith");
    aka!("fmt_str", "format");
    aka!("render_fmt", "format");
    aka!("interp_fmt", "format");
    aka!("subst_fmt", "format");
    aka!("pad_text", "pad");
    aka!("rpad_text", "pad");
    aka!("right_pad_text", "pad");
    aka!("middle_pad", "center");
    aka!("center_pad", "center");
    aka!("center_text", "center");
    aka!("dup_text", "repeat_str");
    aka!("times_str", "repeat_str");
    aka!("n_copies", "repeat_str");
    aka!("seq_to", "range");
    aka!("gen_range", "range");
    aka!("make_range", "range");
    aka!("iota", "range");
    aka!("sort_list", "lsort");
    aka!("order_list", "lsort");
    aka!("asc_list", "lsort");
    aka!("flip_list", "lreverse");
    aka!("rev_list", "lreverse");
    aka!("back_list", "lreverse");
    aka!("dedupe_list", "lunique");
    aka!("uniq_list", "lunique");
    aka!("no_dups", "lunique");
    aka!("max_of_list", "lmax");
    aka!("largest_in", "lmax");
    aka!("top_list", "lmax");
    aka!("min_of_list", "lmin");
    aka!("least_in", "lmin");
    aka!("bot_list", "lmin");
    aka!("total_list", "lsum");
    aka!("add_all_list", "lsum");
    aka!("mean_list", "lavg");
    aka!("avg_list", "lavg");
    aka!("midval_list", "lavg");
    aka!("mix_list", "lshuffle");
    aka!("scramble_list", "lshuffle");
    aka!("randomize_list", "lshuffle");
    aka!("pick_one", "lchoice");
    aka!("rand_elem", "lchoice");
    aka!("draw_one", "lchoice");
    aka!("head_list", "first");
    aka!("fst_list", "first");
    aka!("front_list", "first");
    aka!("tail_list_end", "last");
    aka!("lst_list", "last");
    aka!("back_list2", "last");
    aka!("mag_of", "abs");
    aka!("absval", "abs");
    aka!("positive_of", "abs");
    aka!("signum", "sign");
    aka!("polarity", "sign");
    aka!("neg_or_pos", "sign");
    aka!("round_down", "floor");
    aka!("trunc_down", "floor");
    aka!("down_int", "floor");
    aka!("round_up", "ceil");
    aka!("trunc_up", "ceil");
    aka!("up_int", "ceil");
    aka!("nearest_int", "round");
    aka!("round_to_int", "round");
    aka!("to_int_round", "round");
    aka!("root2", "sqrt");
    aka!("square_root", "sqrt");
    aka!("sq_root", "sqrt");
    aka!("raise_to", "pow");
    aka!("power_of", "pow");
    aka!("exponent", "pow");
    aka!("bigger", "fmax");
    aka!("topper", "fmax");
    aka!("high_of", "fmax");
    aka!("smaller2", "fmin");
    aka!("bottomer", "fmin");
    aka!("low_of", "fmin");
    aka!("fact_n", "factorial");
    aka!("n_fact", "factorial");
    aka!("factorial_n", "factorial");
    aka!("prime_q", "is_prime");
    aka!("prime_check", "is_prime");
    aka!("test_prime", "is_prime");
    aka!("even_q", "is_even");
    aka!("even_check", "is_even");
    aka!("odd_q", "is_odd");
    aka!("odd_check", "is_odd");
    aka!("greatest_common", "gcd");
    aka!("common_div", "gcd");
    aka!("hcf", "gcd");
    aka!("least_common_mul", "lcm");
    aka!("common_mul2", "lcm");
    aka!("fib_n", "fibonacci");
    aka!("nth_fib", "fibonacci");
    aka!("primes_below", "primes_up_to");
    aka!("all_primes_to", "primes_up_to");
    aka!("prime_nth", "nth_prime");
    aka!("n_th_prime", "nth_prime");
    aka!("interpolate", "lerp");
    aka!("linear_interp", "lerp");
    aka!("mix_n", "lerp");
    aka!("dist_2d", "distance");
    aka!("euclid", "distance");
    aka!("taxicab", "manhattan");
    aka!("manhattan_dist", "manhattan");
    aka!("bound_n", "clamp");
    aka!("limit_n", "clamp");
    aka!("constrain_n", "clamp");
    aka!("iso_now", "now_iso");
    aka!("rfc3339_now", "now_iso");
    aka!("dow", "weekday");
    aka!("day_of_week", "weekday");
    aka!("today_check", "is_today");
    aka!("is_today_q", "is_today");
    aka!("leap_q", "is_leap_year");
    aka!("leap_check", "is_leap_year");
    aka!("weekend_q", "is_weekend");
    aka!("weekend_check", "is_weekend");
    aka!("new_uuid_v2", "uuid_v2");
    aka!("year_of", "year");
    aka!("yr_of", "year");
    aka!("mon_of", "month");
    aka!("month_of", "month");
    aka!("day_of_date", "day");
    aka!("date_to_epoch", "to_unix");
    aka!("epoch_to_date", "from_unix");
    aka!("ipv4_to_n", "ip_to_int");
    aka!("n_to_ipv4", "int_to_ip");
    aka!("valid_ipv4", "ip_v4_check");
    aka!("ipv4_q", "ip_v4_check");
    aka!("fake_ip", "random_ipv4");
    aka!("rand_ip", "random_ipv4");
    aka!("rand_p", "random_port");
    aka!("any_port", "random_port");
    aka!("rand_alpha", "rand_letter");
    aka!("rand_az", "rand_letter");
    aka!("rand_AZ", "rand_uppercase");
    aka!("rand_09", "rand_digit");
    aka!("rand_hex", "rand_hex_char");
    aka!("rand_real", "rand_float");
    aka!("rand_dec", "rand_float");
    aka!("real_rand", "rand_float");
    aka!("maybe", "rand_bool");
    aka!("tossbit", "rand_bool");
    aka!("heads_or_tails", "coin");
    aka!("coin_flip2", "coin");
    aka!("dice6", "d6");
    aka!("roll_d6", "d6");
    aka!("dice20", "d20");
    aka!("roll_d20", "d20");
    aka!("kind_of", "type_of");
    aka!("typ_of", "type_of");
    aka!("what_is", "type_of");
    aka!("var_exists", "has_var");
    aka!("is_set", "has_var");
    aka!("forget_v", "unset_var");
    aka!("drop_var", "unset_var");
    aka!("clear_var", "unset_var");
    aka!("dup_var", "copy_var");
    aka!("alias_var", "copy_var");
    aka!("xchg_vars", "swap_vars");
    aka!("trade_vars", "swap_vars");
    aka!("env_of", "getenv");
    aka!("env_var", "getenv");
    aka!("envget", "getenv");
    aka!("envput", "setenv");
    aka!("env_set_var", "setenv");
    aka!("load_dotenv", "loadenv");
    aka!("import_env", "loadenv");
    aka!("from_json", "json_parse");
    aka!("parse_json", "json_parse");
    aka!("to_json", "json_stringify");
    aka!("stringify_json", "json_stringify");
    aka!("pretty_json", "json_pretty");
    aka!("fmt_json", "json_pretty");
    aka!("host_of_url", "url_host");
    aka!("path_of_url", "url_path");
    aka!("query_of_url", "url_query");
    aka!("scheme_of_url", "url_scheme");
    aka!("bytes_of", "file_size");
    aka!("size_of_file", "file_size");
    aka!("dir_q", "is_dir");
    aka!("file_q", "is_file");
    aka!("leaf_of_path", "basename");
    aka!("filename_of", "basename");
    aka!("folder_of_path", "dirname");
    aka!("parent_of", "dirname");
    aka!("ext_of_file", "extname");
    aka!("filetype", "extname");
    aka!("path_join", "joinpath");
    aka!("combine_path", "joinpath");
    aka!("full_path", "abspath");
    aka!("canonical_path", "abspath");
    aka!("path_q", "exists");
    aka!("dir_contents", "listdir");
    aka!("ls_dir", "listdir");
    aka!("cp_file", "copy");
    aka!("mv_file", "move");
    aka!("rename_path", "move");
    aka!("file_append", "append_file");
    aka!("append_to_file", "append_file");
    aka!("lines_of", "read_lines");
    aka!("load_lines", "read_lines");
    aka!("save_lines", "write_lines");
    aka!("dump_lines", "write_lines");
    aka!("this_day", "today");
    aka!("next_day", "tomorrow");
    aka!("prev_day", "yesterday");
    aka!("os_kind", "platform");
    aka!("system_kind", "platform");
    aka!("my_pid", "pid");
    aka!("nice_one", "compliment");
    aka!("kudos", "compliment");
    aka!("tell_joke", "joke");
    aka!("wisdom_text", "fortune");
    aka!("big_text", "banner");
    aka!("ascii_banner", "banner");
    aka!("frame_text", "box");
    aka!("bar", "progress");
    // ====== ALIAS BLOCK 2 ======
    aka!("p_final", "psyska -/");
    aka!("say_final", "psyska -/");
    aka!("print_final", "psyska -/");
    aka!("write_final", "psyska -/");
    aka!("print", "psyska -/");
    aka!("println_v", "psyska -/");
    aka!("printout", "psyska -/");
    aka!("echo_now", "psyska -/");
    aka!("echo_var", "psyska -/");
    aka!("echo_text", "psyska -/");
    aka!("echo_str", "psyska -/");
    aka!("print_str", "psyska -/");
    aka!("print_text", "psyska -/");
    aka!("print_msg", "psyska -/");
    aka!("print_line", "psyska -/");
    aka!("print_ln", "psyska -/");
    aka!("print_out", "psyska -/");
    aka!("print_to_term", "psyska -/");
    aka!("print_to_screen", "psyska -/");
    aka!("p_text", "psyska -/");
    aka!("p_str", "psyska -/");
    aka!("p_msg", "psyska -/");
    aka!("p_out", "psyska -/");
    aka!("p_v", "psyska -/");
    aka!("p_val", "psyska -/");
    aka!("p_line", "psyska -/");
    aka!("p_ln", "psyska -/");
    aka!("send_to_term", "psyska -/");
    aka!("send_to_screen", "psyska -/");
    aka!("scr_print", "psyska -/");
    aka!("screen_print", "psyska -/");
    aka!("term_print", "psyska -/");
    aka!("stdout_v", "psyska -/");
    aka!("stdout_w", "psyska -/");
    aka!("writeln_v", "psyska -/");
    aka!("type_text", "psyska -/");
    aka!("type_str", "psyska -/");
    aka!("type_v", "psyska -/");
    aka!("type_msg", "psyska -/");
    aka!("shout_text", "psyska -/");
    aka!("whisper_text", "psyska -/");
    aka!("speak_v", "psyska -/");
    aka!("speak_text", "psyska -/");
    aka!("speak_str", "psyska -/");
    aka!("blast_text", "psyska -/");
    aka!("blast_msg", "psyska -/");
    aka!("post_to_term", "psyska -/");
    aka!("lay_down", "psyska -/");
    aka!("deposit_text", "psyska -/");
    aka!("assign", "set");
    aka!("assign_v", "set");
    aka!("letvar", "set");
    aka!("savevar", "set");
    aka!("place_v", "set");
    aka!("store_v", "set");
    aka!("set_int_var", "set");
    aka!("set_str_var", "set");
    aka!("remember_var", "set");
    aka!("stash_v", "set");
    aka!("preserve_v", "set");
    aka!("init_v", "set");
    aka!("begin_v", "set");
    aka!("bestow_v", "set");
    aka!("construct_v", "set");
    aka!("form_v", "set");
    aka!("spawn_v", "set");
    aka!("make_v", "set");
    aka!("alloc_var", "set");
    aka!("alloc_v", "set");
    aka!("imbue_v", "set");
    aka!("instil_v", "set");
    aka!("set2", "set");
    aka!("plus_v", "add");
    aka!("sum_v", "add");
    aka!("incby", "add");
    aka!("addby", "add");
    aka!("add_n", "add");
    aka!("addto", "add");
    aka!("tally_v", "add");
    aka!("increase_v", "add");
    aka!("boost_by", "add");
    aka!("augment", "add");
    aka!("extend_v", "add");
    aka!("increment", "incr");
    aka!("inc_v", "incr");
    aka!("tick", "incr");
    aka!("tick_v", "incr");
    aka!("step_up", "incr");
    aka!("bump", "incr");
    aka!("advance", "incr");
    aka!("uppervalue", "incr");
    aka!("decrement", "decr");
    aka!("dec_v", "decr");
    aka!("untick", "decr");
    aka!("step_down", "decr");
    aka!("bump_down", "decr");
    aka!("retreat", "decr");
    aka!("lowervalue", "decr");
    aka!("random_v", "rand");
    aka!("rrand", "rand");
    aka!("rng", "rand");
    aka!("random_int_v", "rand");
    aka!("random_in", "rand");
    aka!("any_int", "rand");
    aka!("any_n", "rand");
    aka!("pause_v", "sleep");
    aka!("halt_v", "sleep");
    aka!("block_v", "sleep");
    aka!("snooze_v", "sleep");
    aka!("nap_v", "sleep");
    aka!("save_file_v", "writefile");
    aka!("dump_text", "writefile");
    aka!("write_to_file", "writefile");
    aka!("save_to_file", "writefile");
    aka!("load_file_v", "readfile");
    aka!("slurp_text", "readfile");
    aka!("cat_v", "readfile");
    aka!("read_to_string", "readfile");
    aka!("mkdir_v", "mkdir");
    aka!("make_dir_v", "mkdir");
    aka!("create_dir", "mkdir");
    aka!("build_dir", "mkdir");
    aka!("delete_v", "rm");
    aka!("unlink_v", "rm");
    aka!("kill_path", "rm");
    aka!("list_v", "list");
    aka!("init_list_v", "list");
    aka!("build_list_v", "list");
    aka!("fresh_list_v", "list");
    aka!("push_v", "push");
    aka!("lpush", "push");
    aka!("list_push2", "push");
    aka!("append_v", "push");
    aka!("back_v", "push");
    aka!("pop_v", "pop");
    aka!("lpop", "pop");
    aka!("list_pop2", "pop");
    aka!("remove_back", "pop");
    aka!("lget_v", "lget");
    aka!("list_index", "lget");
    aka!("at_index", "lget");
    aka!("lset_v", "lset");
    aka!("list_set2", "lset");
    aka!("place_index", "lset");
    aka!("lsize_v", "lsize");
    aka!("list_count2", "lsize");
    aka!("len_l", "lsize");
    aka!("dict_v", "dict");
    aka!("init_dict_v", "dict");
    aka!("build_dict_v", "dict");
    aka!("fresh_dict_v", "dict");
    aka!("table_v", "dict");
    aka!("dset_v", "dset");
    aka!("dict_put2", "dset");
    aka!("map_put", "dset");
    aka!("dget_v", "dget");
    aka!("dict_lookup", "dget");
    aka!("map_lookup", "dget");
    aka!("dsize_v", "dsize");
    aka!("dict_count2", "dsize");
    aka!("n_keys2", "dsize");
    aka!("color_v", "color");
    aka!("set_term_color", "color");
    aka!("tint", "color");
    aka!("quit", "exit");
    aka!("stop", "exit");
    aka!("abort", "exit");
    aka!("leave", "exit");
    aka!("die", "exit");
    aka!("halt", "exit");
    aka!("shutdown", "exit");
    aka!("kill_v", "exit");
    aka!("end_v", "exit");
    aka!("http_get_v", "http_get");
    aka!("http_fetch2", "http_get");
    aka!("url_get", "http_get");
    aka!("http_post_v", "http_post");
    aka!("url_post", "http_post");
    aka!("md5_v", "md5");
    aka!("md5sum", "md5");
    aka!("sha256_v", "sha256");
    aka!("sha256sum", "sha256");
    aka!("b64encode_v", "base64_encode");
    aka!("b64decode_v", "base64_decode");
    aka!("regex_test", "regex_match");
    aka!("re_test", "regex_match");
    aka!("regex_swap", "regex_replace");
    aka!("re_swap", "regex_replace");
    aka!("now_v", "now");
    aka!("now_epoch", "now");
    aka!("epoch_v", "now");
    aka!("datefmt_v", "datefmt");
    aka!("format_date_v", "datefmt");
    aka!("sleep_ms_v", "sleep_ms");
    aka!("wait_millis", "sleep_ms");
    aka!("msec_pause", "sleep_ms");
    aka!("render_grid", "table");
    aka!("spin_v", "spin");
    aka!("spinner_v", "spin");
    aka!("uuid_v_alt", "uuid");
    aka!("guid_v", "uuid");
    aka!("hostname_v", "hostname");
    aka!("bg_v", "spawn");
    aka!("fork_v", "spawn");
    aka!("upper_v", "uppercase");
    aka!("to_upper_v", "uppercase");
    aka!("lower_v", "lower");
    aka!("to_lower_v", "lower");
    aka!("trim_v", "trim");
    aka!("strip_v", "trim");
    aka!("rev_v", "reverse");
    aka!("flip_v", "reverse");
    aka!("split_v", "split");
    aka!("tokenize", "split");
    aka!("concat_v", "concat");
    aka!("stitch", "concat");
    aka!("replace_v", "replace");
    aka!("swap_v", "replace");
    aka!("contains_v", "contains");
    aka!("has_v_str", "contains");
    aka!("startswith_v", "startswith");
    aka!("endswith_v", "endswith");
    aka!("format_v", "format");
    aka!("sprintf_like", "format");
    aka!("pad_v", "pad");
    aka!("center_v", "center");
    aka!("repeat_v", "repeat_str");
    aka!("range_v", "range");
    aka!("lsort_v", "lsort");
    aka!("lreverse_v", "lreverse");
    aka!("lunique_v", "lunique");
    aka!("lmax_v", "lmax");
    aka!("lmin_v", "lmin");
    aka!("lsum_v", "lsum");
    aka!("lavg_v", "lavg");
    aka!("lshuffle_v", "lshuffle");
    aka!("lchoice_v", "lchoice");
    aka!("first_v", "first");
    aka!("last_v", "last");
    aka!("abs_v", "abs");
    aka!("sign_v", "sign");
    aka!("floor_v", "floor");
    aka!("ceil_v", "ceil");
    aka!("round_v", "round");
    aka!("sqrt_v", "sqrt");
    aka!("pow_v", "pow");
    aka!("factorial_v", "factorial");
    aka!("fibonacci_v", "fibonacci");
    aka!("ip_to_int_v", "ip_to_int");
    aka!("int_to_ip_v", "int_to_ip");
    aka!("ip_v4_check_v", "ip_v4_check");
    aka!("random_ipv4_v", "random_ipv4");
    aka!("random_port_v", "random_port");
    aka!("rand_letter_v", "rand_letter");
    aka!("rand_uppercase_v", "rand_uppercase");
    aka!("rand_digit_v", "rand_digit");
    aka!("rand_hex_char_v", "rand_hex_char");
    aka!("type_of_v", "type_of");
    aka!("has_var_v", "has_var");
    aka!("unset_var_v", "unset_var");
    aka!("copy_var_v", "copy_var");
    aka!("swap_vars_v", "swap_vars");
    aka!("getenv_v", "getenv");
    aka!("setenv_v", "setenv");
    aka!("json_parse_v", "json_parse");
    aka!("json_stringify_v", "json_stringify");
    aka!("url_host_v", "url_host");
    aka!("url_path_v", "url_path");
    aka!("url_query_v", "url_query");
    aka!("url_scheme_v", "url_scheme");
    aka!("file_size_v", "file_size");
    aka!("is_dir_v", "is_dir");
    aka!("is_file_v", "is_file");
    aka!("basename_v", "basename");
    aka!("dirname_v", "dirname");
    aka!("extname_v", "extname");
    aka!("joinpath_v", "joinpath");
    aka!("exists_v", "exists");
    aka!("listdir_v", "listdir");
    aka!("copy_v_p", "copy");
    aka!("move_v", "move");
    aka!("today_v", "today");
    aka!("tomorrow_v", "tomorrow");
    aka!("yesterday_v", "yesterday");
    aka!("platform_v", "platform");
    aka!("compliment_v", "compliment");
    aka!("joke_v", "joke");
    aka!("fortune_v", "fortune");
    aka!("banner_v", "banner");
    aka!("box_v", "box");
    aka!("progress_v", "progress");
    aka!("say_n_1", "psyska -/");
    aka!("tell_n_1", "psyska -/");
    aka!("print_n_1", "psyska -/");
    aka!("out_n_1", "psyska -/");
    aka!("echo_n_1", "psyska -/");
    aka!("write_n_1", "psyska -/");
    aka!("show_n_1", "psyska -/");
    aka!("display_n_1", "psyska -/");
    aka!("emit_n_1", "psyska -/");
    aka!("set_n_1", "set");
    aka!("store_n_1", "set");
    aka!("save_n_1", "set");
    aka!("add_n_v_1", "add");
    aka!("plus_n_1", "add");
    aka!("sum_n_1", "add");
    aka!("inc_n_1", "incr");
    aka!("tick_n_1", "incr");
    aka!("bump_n_1", "incr");
    aka!("dec_n_1", "decr");
    aka!("untick_n_1", "decr");
    aka!("rand_n_v_1", "rand");
    aka!("pick_n_v_1", "rand");
    aka!("rng_n_v_1", "rand");
    aka!("sleep_n_1", "sleep");
    aka!("nap_n_1", "sleep");
    aka!("rest_n_1", "sleep");
    aka!("wfile_n_1", "writefile");
    aka!("rfile_n_1", "readfile");
    aka!("mkd_n_1", "mkdir");
    aka!("rm_n_v_1", "rm");
    aka!("list_n_1", "list");
    aka!("push_n_v_1", "push");
    aka!("pop_n_v_1", "pop");
    aka!("lget_n_1", "lget");
    aka!("lset_n_1", "lset");
    aka!("lsize_n_1", "lsize");
    aka!("dict_n_1", "dict");
    aka!("dset_n_1", "dset");
    aka!("dget_n_1", "dget");
    aka!("dsize_n_1", "dsize");
    aka!("color_n_1", "color");
    aka!("exit_n_v_1", "exit");
    aka!("hg_n_1", "http_get");
    aka!("hp_n_1", "http_post");
    aka!("md5_n_1", "md5");
    aka!("sha256_n_1", "sha256");
    aka!("b64e_n_1", "base64_encode");
    aka!("b64d_n_1", "base64_decode");
    aka!("re_n_1", "regex_match");
    aka!("res_n_1", "regex_replace");
    aka!("now_n_v_1", "now");
    aka!("today_n_v_1", "today");
    aka!("up_n_1", "uppercase");
    aka!("lo_n_1", "lower");
    aka!("trim_n_1", "trim");
    aka!("rev_n_1", "reverse");
    aka!("split_n_1", "split");
    aka!("concat_n_1", "concat");
    aka!("uuid_n_1", "uuid");
    aka!("hostname_n_1", "hostname");
    aka!("table_n_1", "table");
    aka!("spin_n_1", "spin");
    aka!("banner_n_1", "banner");
    aka!("box_n_1", "box");
    aka!("progress_n_v_1", "progress");
    aka!("ffi_n_v_1", "ffi");
    aka!("exec_n_v_1", "exec");
    aka!("getenv_n_1", "getenv");
    aka!("setenv_n_1", "setenv");
    aka!("range_n_1", "range");
    aka!("first_n_1", "first");
    aka!("last_n_v_1", "last");
    aka!("lsort_n_1", "lsort");
    aka!("lreverse_n_1", "lreverse");
    aka!("lmax_n_1", "lmax");
    aka!("lmin_n_1", "lmin");
    aka!("lsum_n_1", "lsum");
    aka!("lavg_n_1", "lavg");
    aka!("lshuffle_n_1", "lshuffle");
    aka!("lchoice_n_1", "lchoice");
    aka!("abs_n_v_1", "abs");
    aka!("sign_n_1", "sign");
    aka!("floor_n_1", "floor");
    aka!("ceil_n_1", "ceil");
    aka!("round_n_1", "round");
    aka!("sqrt_n_1", "sqrt");
    aka!("fact_n_v_1", "factorial");
    aka!("fib_n_v_1", "fibonacci");
    aka!("tof_n_1", "type_of");
    aka!("hv_n_1", "has_var");
    aka!("fsz_n_1", "file_size");
    aka!("isd_n_1", "is_dir");
    aka!("isf_n_1", "is_file");
    aka!("bn_n_1", "basename");
    aka!("dn_n_1", "dirname");
    aka!("xn_n_1", "extname");
    aka!("ex_n_1", "exists");
    aka!("ll_n_1", "listdir");
    aka!("jp_n_1", "json_parse");
    aka!("js_n_1", "json_stringify");
    aka!("he_n_1", "html_escape");
    aka!("ue_n_1", "url_escape");
    aka!("ip2i_n_1", "ip_to_int");
    aka!("i2ip_n_1", "int_to_ip");
    aka!("say_n_2", "psyska -/");
    aka!("tell_n_2", "psyska -/");
    aka!("print_n_2", "psyska -/");
    aka!("out_n_2", "psyska -/");
    aka!("echo_n_2", "psyska -/");
    aka!("write_n_2", "psyska -/");
    aka!("show_n_2", "psyska -/");
    aka!("display_n_2", "psyska -/");
    aka!("emit_n_2", "psyska -/");
    aka!("set_n_2", "set");
    aka!("store_n_2", "set");
    aka!("save_n_2", "set");
    aka!("add_n_v_2", "add");
    aka!("plus_n_2", "add");
    aka!("sum_n_2", "add");
    aka!("inc_n_2", "incr");
    aka!("tick_n_2", "incr");
    aka!("bump_n_2", "incr");
    aka!("dec_n_2", "decr");
    aka!("untick_n_2", "decr");
    aka!("rand_n_v_2", "rand");
    aka!("pick_n_v_2", "rand");
    aka!("rng_n_v_2", "rand");
    aka!("sleep_n_2", "sleep");
    aka!("nap_n_2", "sleep");
    aka!("rest_n_2", "sleep");
    aka!("wfile_n_2", "writefile");
    aka!("rfile_n_2", "readfile");
    aka!("mkd_n_2", "mkdir");
    aka!("rm_n_v_2", "rm");
    aka!("list_n_2", "list");
    aka!("push_n_v_2", "push");
    aka!("pop_n_v_2", "pop");
    aka!("lget_n_2", "lget");
    aka!("lset_n_2", "lset");
    aka!("lsize_n_2", "lsize");
    aka!("dict_n_2", "dict");
    aka!("dset_n_2", "dset");
    aka!("dget_n_2", "dget");
    aka!("dsize_n_2", "dsize");
    aka!("color_n_2", "color");
    aka!("exit_n_v_2", "exit");
    aka!("hg_n_2", "http_get");
    aka!("hp_n_2", "http_post");
    aka!("md5_n_2", "md5");
    aka!("sha256_n_2", "sha256");
    aka!("b64e_n_2", "base64_encode");
    aka!("b64d_n_2", "base64_decode");
    aka!("re_n_2", "regex_match");
    aka!("res_n_2", "regex_replace");
    aka!("now_n_v_2", "now");
    aka!("today_n_v_2", "today");
    aka!("up_n_2", "uppercase");
    aka!("lo_n_2", "lower");
    aka!("trim_n_2", "trim");
    aka!("rev_n_2", "reverse");
    aka!("split_n_2", "split");
    aka!("concat_n_2", "concat");
    aka!("uuid_n_2", "uuid");
    aka!("hostname_n_2", "hostname");
    aka!("table_n_2", "table");
    aka!("spin_n_2", "spin");
    aka!("banner_n_2", "banner");
    aka!("box_n_2", "box");
    aka!("progress_n_v_2", "progress");
    aka!("ffi_n_v_2", "ffi");
    aka!("exec_n_v_2", "exec");
    aka!("getenv_n_2", "getenv");
    aka!("setenv_n_2", "setenv");
    aka!("range_n_2", "range");
    aka!("first_n_2", "first");
    aka!("last_n_v_2", "last");
    aka!("lsort_n_2", "lsort");
    aka!("lreverse_n_2", "lreverse");
    aka!("lmax_n_2", "lmax");
    aka!("lmin_n_2", "lmin");
    aka!("lsum_n_2", "lsum");
    aka!("lavg_n_2", "lavg");
    aka!("lshuffle_n_2", "lshuffle");
    aka!("lchoice_n_2", "lchoice");
    aka!("abs_n_v_2", "abs");
    aka!("sign_n_2", "sign");
    aka!("floor_n_2", "floor");
    aka!("ceil_n_2", "ceil");
    aka!("round_n_2", "round");
    aka!("sqrt_n_2", "sqrt");
    aka!("fact_n_v_2", "factorial");
    aka!("fib_n_v_2", "fibonacci");
    aka!("tof_n_2", "type_of");
    aka!("hv_n_2", "has_var");
    aka!("fsz_n_2", "file_size");
    aka!("isd_n_2", "is_dir");
    aka!("isf_n_2", "is_file");
    aka!("bn_n_2", "basename");
    aka!("dn_n_2", "dirname");
    aka!("xn_n_2", "extname");
    aka!("ex_n_2", "exists");
    aka!("ll_n_2", "listdir");
    aka!("jp_n_2", "json_parse");
    aka!("js_n_2", "json_stringify");
    aka!("he_n_2", "html_escape");
    aka!("ue_n_2", "url_escape");
    aka!("ip2i_n_2", "ip_to_int");
    aka!("i2ip_n_2", "int_to_ip");
    aka!("say_n_3", "psyska -/");
    aka!("tell_n_3", "psyska -/");
    aka!("print_n_3", "psyska -/");
    aka!("out_n_3", "psyska -/");
    aka!("echo_n_3", "psyska -/");
    aka!("write_n_3", "psyska -/");
    aka!("show_n_3", "psyska -/");
    aka!("display_n_3", "psyska -/");
    aka!("emit_n_3", "psyska -/");
    aka!("set_n_3", "set");
    aka!("store_n_3", "set");
    aka!("save_n_3", "set");
    aka!("add_n_v_3", "add");
    aka!("plus_n_3", "add");
    aka!("sum_n_3", "add");
    aka!("inc_n_3", "incr");
    aka!("tick_n_3", "incr");
    aka!("bump_n_3", "incr");
    aka!("dec_n_3", "decr");
    aka!("untick_n_3", "decr");
    aka!("rand_n_v_3", "rand");
    aka!("pick_n_v_3", "rand");
    aka!("rng_n_v_3", "rand");
    aka!("sleep_n_3", "sleep");
    aka!("nap_n_3", "sleep");
    aka!("rest_n_3", "sleep");
    aka!("wfile_n_3", "writefile");
    aka!("rfile_n_3", "readfile");
    aka!("mkd_n_3", "mkdir");
    aka!("rm_n_v_3", "rm");
    aka!("list_n_3", "list");
    aka!("push_n_v_3", "push");
    aka!("pop_n_v_3", "pop");
    aka!("lget_n_3", "lget");
    aka!("lset_n_3", "lset");
    aka!("lsize_n_3", "lsize");
    aka!("dict_n_3", "dict");
    aka!("dset_n_3", "dset");
    aka!("dget_n_3", "dget");
    aka!("dsize_n_3", "dsize");
    aka!("color_n_3", "color");
    aka!("exit_n_v_3", "exit");
    aka!("hg_n_3", "http_get");
    aka!("hp_n_3", "http_post");
    aka!("md5_n_3", "md5");
    aka!("sha256_n_3", "sha256");
    aka!("b64e_n_3", "base64_encode");
    aka!("b64d_n_3", "base64_decode");
    aka!("re_n_3", "regex_match");
    aka!("res_n_3", "regex_replace");
    aka!("now_n_v_3", "now");
    aka!("today_n_v_3", "today");
    aka!("up_n_3", "uppercase");
    aka!("lo_n_3", "lower");
    aka!("trim_n_3", "trim");
    aka!("rev_n_3", "reverse");
    aka!("split_n_3", "split");
    aka!("concat_n_3", "concat");
    aka!("uuid_n_3", "uuid");
    aka!("hostname_n_3", "hostname");
    aka!("table_n_3", "table");
    aka!("spin_n_3", "spin");
    aka!("banner_n_3", "banner");
    aka!("box_n_3", "box");
    aka!("progress_n_v_3", "progress");
    aka!("ffi_n_v_3", "ffi");
    aka!("exec_n_v_3", "exec");
    aka!("getenv_n_3", "getenv");
    aka!("setenv_n_3", "setenv");
    aka!("range_n_3", "range");
    aka!("first_n_3", "first");
    aka!("last_n_v_3", "last");
    aka!("lsort_n_3", "lsort");
    aka!("lreverse_n_3", "lreverse");
    aka!("lmax_n_3", "lmax");
    aka!("lmin_n_3", "lmin");
    aka!("lsum_n_3", "lsum");
    aka!("lavg_n_3", "lavg");
    aka!("lshuffle_n_3", "lshuffle");
    aka!("lchoice_n_3", "lchoice");
    aka!("abs_n_v_3", "abs");
    aka!("sign_n_3", "sign");
    aka!("floor_n_3", "floor");
    aka!("ceil_n_3", "ceil");
    aka!("round_n_3", "round");
    aka!("sqrt_n_3", "sqrt");
    aka!("fact_n_v_3", "factorial");
    aka!("fib_n_v_3", "fibonacci");
    aka!("tof_n_3", "type_of");
    aka!("hv_n_3", "has_var");
    aka!("fsz_n_3", "file_size");
    aka!("isd_n_3", "is_dir");
    aka!("isf_n_3", "is_file");
    aka!("bn_n_3", "basename");
    aka!("dn_n_3", "dirname");
    aka!("xn_n_3", "extname");
    aka!("ex_n_3", "exists");
    aka!("ll_n_3", "listdir");
    aka!("jp_n_3", "json_parse");
    aka!("js_n_3", "json_stringify");
    aka!("he_n_3", "html_escape");
    aka!("ue_n_3", "url_escape");
    aka!("ip2i_n_3", "ip_to_int");
    aka!("i2ip_n_3", "int_to_ip");
    aka!("say_n_4", "psyska -/");
    aka!("tell_n_4", "psyska -/");
    aka!("print_n_4", "psyska -/");
    aka!("out_n_4", "psyska -/");
    aka!("echo_n_4", "psyska -/");
    aka!("write_n_4", "psyska -/");
    aka!("show_n_4", "psyska -/");
    aka!("display_n_4", "psyska -/");
    aka!("emit_n_4", "psyska -/");
    aka!("set_n_4", "set");
    aka!("store_n_4", "set");
    aka!("save_n_4", "set");
    aka!("add_n_v_4", "add");
    aka!("plus_n_4", "add");
    aka!("sum_n_4", "add");
    aka!("inc_n_4", "incr");
    aka!("tick_n_4", "incr");
    aka!("bump_n_4", "incr");
    aka!("dec_n_4", "decr");
    aka!("untick_n_4", "decr");
    aka!("rand_n_v_4", "rand");
    aka!("pick_n_v_4", "rand");
    aka!("rng_n_v_4", "rand");
    aka!("sleep_n_4", "sleep");
    aka!("nap_n_4", "sleep");
    aka!("rest_n_4", "sleep");
    aka!("wfile_n_4", "writefile");
    aka!("rfile_n_4", "readfile");
    aka!("mkd_n_4", "mkdir");
    aka!("rm_n_v_4", "rm");
    aka!("list_n_4", "list");
    aka!("push_n_v_4", "push");
    aka!("pop_n_v_4", "pop");
    aka!("lget_n_4", "lget");
    aka!("lset_n_4", "lset");
    aka!("lsize_n_4", "lsize");
    aka!("dict_n_4", "dict");
    aka!("dset_n_4", "dset");
    aka!("dget_n_4", "dget");
    aka!("dsize_n_4", "dsize");
    aka!("color_n_4", "color");
    aka!("exit_n_v_4", "exit");
    aka!("hg_n_4", "http_get");
    aka!("hp_n_4", "http_post");
    aka!("md5_n_4", "md5");
    aka!("sha256_n_4", "sha256");
    aka!("b64e_n_4", "base64_encode");
    aka!("b64d_n_4", "base64_decode");
    aka!("re_n_4", "regex_match");
    aka!("res_n_4", "regex_replace");
    aka!("now_n_v_4", "now");
    aka!("today_n_v_4", "today");
    aka!("up_n_4", "uppercase");
    aka!("lo_n_4", "lower");
    aka!("trim_n_4", "trim");
    aka!("rev_n_4", "reverse");
    aka!("split_n_4", "split");
    aka!("concat_n_4", "concat");
    aka!("uuid_n_4", "uuid");
    aka!("hostname_n_4", "hostname");
    aka!("table_n_4", "table");
    aka!("spin_n_4", "spin");
    aka!("banner_n_4", "banner");
    aka!("box_n_4", "box");
    aka!("progress_n_v_4", "progress");
    aka!("ffi_n_v_4", "ffi");
    aka!("exec_n_v_4", "exec");
    aka!("getenv_n_4", "getenv");
    aka!("setenv_n_4", "setenv");
    aka!("range_n_4", "range");
    aka!("first_n_4", "first");
    aka!("last_n_v_4", "last");
    aka!("lsort_n_4", "lsort");
    aka!("lreverse_n_4", "lreverse");
    aka!("lmax_n_4", "lmax");
    aka!("lmin_n_4", "lmin");
    aka!("lsum_n_4", "lsum");
    aka!("lavg_n_4", "lavg");
    aka!("lshuffle_n_4", "lshuffle");
    aka!("lchoice_n_4", "lchoice");
    aka!("abs_n_v_4", "abs");
    aka!("sign_n_4", "sign");
    aka!("floor_n_4", "floor");
    aka!("ceil_n_4", "ceil");
    aka!("round_n_4", "round");
    aka!("sqrt_n_4", "sqrt");
    aka!("fact_n_v_4", "factorial");
    aka!("fib_n_v_4", "fibonacci");
    aka!("tof_n_4", "type_of");
    aka!("hv_n_4", "has_var");
    aka!("fsz_n_4", "file_size");
    aka!("isd_n_4", "is_dir");
    aka!("isf_n_4", "is_file");
    aka!("bn_n_4", "basename");
    aka!("dn_n_4", "dirname");
    aka!("xn_n_4", "extname");
    aka!("ex_n_4", "exists");
    aka!("ll_n_4", "listdir");
    aka!("jp_n_4", "json_parse");
    aka!("js_n_4", "json_stringify");
    aka!("he_n_4", "html_escape");
    aka!("ue_n_4", "url_escape");
    aka!("ip2i_n_4", "ip_to_int");
    aka!("i2ip_n_4", "int_to_ip");
    aka!("say_n_5", "psyska -/");
    aka!("tell_n_5", "psyska -/");
    aka!("print_n_5", "psyska -/");
    aka!("out_n_5", "psyska -/");
    aka!("echo_n_5", "psyska -/");
    aka!("write_n_5", "psyska -/");
    aka!("show_n_5", "psyska -/");
    aka!("display_n_5", "psyska -/");
    aka!("emit_n_5", "psyska -/");
    aka!("set_n_5", "set");
    aka!("store_n_5", "set");
    aka!("save_n_5", "set");
    aka!("add_n_v_5", "add");
    aka!("plus_n_5", "add");
    aka!("sum_n_5", "add");
    aka!("inc_n_5", "incr");
    aka!("tick_n_5", "incr");
    aka!("bump_n_5", "incr");
    aka!("dec_n_5", "decr");
    aka!("untick_n_5", "decr");
    aka!("rand_n_v_5", "rand");
    aka!("pick_n_v_5", "rand");
    aka!("rng_n_v_5", "rand");
    aka!("sleep_n_5", "sleep");
    aka!("nap_n_5", "sleep");
    aka!("rest_n_5", "sleep");
    aka!("wfile_n_5", "writefile");
    aka!("rfile_n_5", "readfile");
    aka!("mkd_n_5", "mkdir");
    aka!("rm_n_v_5", "rm");
    aka!("list_n_5", "list");
    aka!("push_n_v_5", "push");
    aka!("pop_n_v_5", "pop");
    aka!("lget_n_5", "lget");
    aka!("lset_n_5", "lset");
    aka!("lsize_n_5", "lsize");
    aka!("dict_n_5", "dict");
    aka!("dset_n_5", "dset");
    aka!("dget_n_5", "dget");
    aka!("dsize_n_5", "dsize");
    aka!("color_n_5", "color");
    aka!("exit_n_v_5", "exit");
    aka!("hg_n_5", "http_get");
    aka!("hp_n_5", "http_post");
    aka!("md5_n_5", "md5");
    aka!("sha256_n_5", "sha256");
    aka!("b64e_n_5", "base64_encode");
    aka!("b64d_n_5", "base64_decode");
    aka!("re_n_5", "regex_match");
    aka!("res_n_5", "regex_replace");
    aka!("now_n_v_5", "now");
    aka!("today_n_v_5", "today");
    aka!("up_n_5", "uppercase");
    aka!("lo_n_5", "lower");
    aka!("trim_n_5", "trim");
    aka!("rev_n_5", "reverse");
    aka!("split_n_5", "split");
    aka!("concat_n_5", "concat");
    aka!("uuid_n_5", "uuid");
    aka!("hostname_n_5", "hostname");
    aka!("table_n_5", "table");
    aka!("spin_n_5", "spin");
    aka!("banner_n_5", "banner");
    aka!("box_n_5", "box");
    aka!("progress_n_v_5", "progress");
    aka!("ffi_n_v_5", "ffi");
    aka!("exec_n_v_5", "exec");
    aka!("getenv_n_5", "getenv");
    aka!("setenv_n_5", "setenv");
    aka!("range_n_5", "range");
    aka!("first_n_5", "first");
    aka!("last_n_v_5", "last");
    aka!("lsort_n_5", "lsort");
    aka!("lreverse_n_5", "lreverse");
    aka!("lmax_n_5", "lmax");
    aka!("lmin_n_5", "lmin");
    aka!("lsum_n_5", "lsum");
    aka!("lavg_n_5", "lavg");
    aka!("lshuffle_n_5", "lshuffle");
    aka!("lchoice_n_5", "lchoice");
    aka!("abs_n_v_5", "abs");
    aka!("sign_n_5", "sign");
    aka!("floor_n_5", "floor");
    aka!("ceil_n_5", "ceil");
    aka!("round_n_5", "round");
    aka!("sqrt_n_5", "sqrt");
    aka!("fact_n_v_5", "factorial");
    aka!("fib_n_v_5", "fibonacci");
    aka!("tof_n_5", "type_of");
    aka!("hv_n_5", "has_var");
    aka!("fsz_n_5", "file_size");
    aka!("isd_n_5", "is_dir");
    aka!("isf_n_5", "is_file");
    aka!("bn_n_5", "basename");
    aka!("dn_n_5", "dirname");
    aka!("xn_n_5", "extname");
    aka!("ex_n_5", "exists");
    aka!("ll_n_5", "listdir");
    aka!("jp_n_5", "json_parse");
    aka!("js_n_5", "json_stringify");
    aka!("he_n_5", "html_escape");
    aka!("ue_n_5", "url_escape");
    aka!("ip2i_n_5", "ip_to_int");
    aka!("i2ip_n_5", "int_to_ip");
    aka!("say_n_6", "psyska -/");
    aka!("tell_n_6", "psyska -/");
    aka!("print_n_6", "psyska -/");
    aka!("out_n_6", "psyska -/");
    aka!("echo_n_6", "psyska -/");
    aka!("write_n_6", "psyska -/");
    aka!("show_n_6", "psyska -/");
    aka!("display_n_6", "psyska -/");
    aka!("emit_n_6", "psyska -/");
    aka!("set_n_6", "set");
    aka!("store_n_6", "set");
    aka!("save_n_6", "set");
    aka!("add_n_v_6", "add");
    aka!("plus_n_6", "add");
    aka!("sum_n_6", "add");
    aka!("inc_n_6", "incr");
    aka!("tick_n_6", "incr");
    aka!("bump_n_6", "incr");
    aka!("dec_n_6", "decr");
    aka!("untick_n_6", "decr");
    aka!("rand_n_v_6", "rand");
    aka!("pick_n_v_6", "rand");
    aka!("rng_n_v_6", "rand");
    aka!("sleep_n_6", "sleep");
    aka!("nap_n_6", "sleep");
    aka!("rest_n_6", "sleep");
    aka!("wfile_n_6", "writefile");
    aka!("rfile_n_6", "readfile");
    aka!("mkd_n_6", "mkdir");
    aka!("rm_n_v_6", "rm");
    aka!("list_n_6", "list");
    aka!("push_n_v_6", "push");
    aka!("pop_n_v_6", "pop");
    aka!("lget_n_6", "lget");
    aka!("lset_n_6", "lset");
    aka!("lsize_n_6", "lsize");
    aka!("dict_n_6", "dict");
    aka!("dset_n_6", "dset");
    aka!("dget_n_6", "dget");
    aka!("dsize_n_6", "dsize");
    aka!("color_n_6", "color");
    aka!("exit_n_v_6", "exit");
    aka!("hg_n_6", "http_get");
    aka!("hp_n_6", "http_post");
    aka!("md5_n_6", "md5");
    aka!("sha256_n_6", "sha256");
    aka!("b64e_n_6", "base64_encode");
    aka!("b64d_n_6", "base64_decode");
    aka!("re_n_6", "regex_match");
    aka!("res_n_6", "regex_replace");
    aka!("now_n_v_6", "now");
    aka!("today_n_v_6", "today");
    aka!("up_n_6", "uppercase");
    aka!("lo_n_6", "lower");
    aka!("trim_n_6", "trim");
    aka!("rev_n_6", "reverse");
    aka!("split_n_6", "split");
    aka!("concat_n_6", "concat");
    aka!("uuid_n_6", "uuid");
    aka!("hostname_n_6", "hostname");
    aka!("table_n_6", "table");
    aka!("spin_n_6", "spin");
    aka!("banner_n_6", "banner");
    aka!("box_n_6", "box");
    aka!("progress_n_v_6", "progress");
    aka!("ffi_n_v_6", "ffi");
    aka!("exec_n_v_6", "exec");
    aka!("getenv_n_6", "getenv");
    aka!("setenv_n_6", "setenv");
    aka!("range_n_6", "range");
    aka!("first_n_6", "first");
    aka!("last_n_v_6", "last");
    aka!("lsort_n_6", "lsort");
    aka!("lreverse_n_6", "lreverse");
    aka!("lmax_n_6", "lmax");
    aka!("lmin_n_6", "lmin");
    aka!("lsum_n_6", "lsum");
    aka!("lavg_n_6", "lavg");
    aka!("lshuffle_n_6", "lshuffle");
    aka!("lchoice_n_6", "lchoice");
    aka!("abs_n_v_6", "abs");
    aka!("sign_n_6", "sign");
    aka!("floor_n_6", "floor");
    aka!("ceil_n_6", "ceil");
    aka!("round_n_6", "round");
    aka!("sqrt_n_6", "sqrt");
    aka!("fact_n_v_6", "factorial");
    aka!("fib_n_v_6", "fibonacci");
    aka!("tof_n_6", "type_of");
    aka!("hv_n_6", "has_var");
    aka!("fsz_n_6", "file_size");
    aka!("isd_n_6", "is_dir");
    aka!("isf_n_6", "is_file");
    aka!("bn_n_6", "basename");
    aka!("dn_n_6", "dirname");
    aka!("xn_n_6", "extname");
    aka!("ex_n_6", "exists");
    aka!("ll_n_6", "listdir");
    aka!("jp_n_6", "json_parse");
    aka!("js_n_6", "json_stringify");
    aka!("he_n_6", "html_escape");
    aka!("ue_n_6", "url_escape");
    aka!("ip2i_n_6", "ip_to_int");
    aka!("i2ip_n_6", "int_to_ip");
    aka!("say_n_7", "psyska -/");
    aka!("tell_n_7", "psyska -/");
    aka!("print_n_7", "psyska -/");
    aka!("out_n_7", "psyska -/");
    aka!("echo_n_7", "psyska -/");
    aka!("write_n_7", "psyska -/");
    aka!("show_n_7", "psyska -/");
    aka!("display_n_7", "psyska -/");
    aka!("emit_n_7", "psyska -/");
    aka!("set_n_7", "set");
    aka!("store_n_7", "set");
    aka!("save_n_7", "set");
    aka!("add_n_v_7", "add");
    aka!("plus_n_7", "add");
    aka!("sum_n_7", "add");
    aka!("inc_n_7", "incr");
    aka!("tick_n_7", "incr");
    aka!("bump_n_7", "incr");
    aka!("dec_n_7", "decr");
    aka!("untick_n_7", "decr");
    aka!("rand_n_v_7", "rand");
    aka!("pick_n_v_7", "rand");
    aka!("rng_n_v_7", "rand");
    aka!("sleep_n_7", "sleep");
    aka!("nap_n_7", "sleep");
    aka!("rest_n_7", "sleep");
    aka!("wfile_n_7", "writefile");
    aka!("rfile_n_7", "readfile");
    aka!("mkd_n_7", "mkdir");
    aka!("rm_n_v_7", "rm");
    aka!("list_n_7", "list");
    aka!("push_n_v_7", "push");
    aka!("pop_n_v_7", "pop");
    aka!("lget_n_7", "lget");
    aka!("lset_n_7", "lset");
    aka!("lsize_n_7", "lsize");
    aka!("dict_n_7", "dict");
    aka!("dset_n_7", "dset");
    aka!("dget_n_7", "dget");
    aka!("dsize_n_7", "dsize");
    aka!("color_n_7", "color");
    aka!("exit_n_v_7", "exit");
    aka!("hg_n_7", "http_get");
    aka!("hp_n_7", "http_post");
    aka!("md5_n_7", "md5");
    aka!("sha256_n_7", "sha256");
    aka!("b64e_n_7", "base64_encode");
    aka!("b64d_n_7", "base64_decode");
    aka!("re_n_7", "regex_match");
    aka!("res_n_7", "regex_replace");
    aka!("now_n_v_7", "now");
    aka!("today_n_v_7", "today");
    aka!("up_n_7", "uppercase");
    aka!("lo_n_7", "lower");
    aka!("trim_n_7", "trim");
    aka!("rev_n_7", "reverse");
    aka!("split_n_7", "split");
    aka!("concat_n_7", "concat");
    aka!("uuid_n_7", "uuid");
    aka!("hostname_n_7", "hostname");
    aka!("table_n_7", "table");
    aka!("spin_n_7", "spin");
    aka!("banner_n_7", "banner");
    aka!("box_n_7", "box");
    aka!("progress_n_v_7", "progress");
    aka!("ffi_n_v_7", "ffi");
    aka!("exec_n_v_7", "exec");
    aka!("getenv_n_7", "getenv");
    aka!("setenv_n_7", "setenv");
    aka!("range_n_7", "range");
    aka!("first_n_7", "first");
    aka!("last_n_v_7", "last");
    aka!("lsort_n_7", "lsort");
    aka!("lreverse_n_7", "lreverse");
    aka!("lmax_n_7", "lmax");
    aka!("lmin_n_7", "lmin");
    aka!("lsum_n_7", "lsum");
    aka!("lavg_n_7", "lavg");
    aka!("lshuffle_n_7", "lshuffle");
    aka!("lchoice_n_7", "lchoice");
    aka!("abs_n_v_7", "abs");
    aka!("sign_n_7", "sign");
    aka!("floor_n_7", "floor");
    aka!("ceil_n_7", "ceil");
    aka!("round_n_7", "round");
    aka!("sqrt_n_7", "sqrt");
    aka!("fact_n_v_7", "factorial");
    aka!("fib_n_v_7", "fibonacci");
    aka!("tof_n_7", "type_of");
    aka!("hv_n_7", "has_var");
    aka!("fsz_n_7", "file_size");
    aka!("isd_n_7", "is_dir");
    aka!("isf_n_7", "is_file");
    aka!("bn_n_7", "basename");
    aka!("dn_n_7", "dirname");
    aka!("xn_n_7", "extname");
    aka!("ex_n_7", "exists");
    aka!("ll_n_7", "listdir");
    aka!("jp_n_7", "json_parse");
    aka!("js_n_7", "json_stringify");
    aka!("he_n_7", "html_escape");
    aka!("ue_n_7", "url_escape");
    aka!("ip2i_n_7", "ip_to_int");
    aka!("i2ip_n_7", "int_to_ip");
    aka!("say_n_8", "psyska -/");
    aka!("tell_n_8", "psyska -/");
    aka!("print_n_8", "psyska -/");
    aka!("out_n_8", "psyska -/");
    aka!("echo_n_8", "psyska -/");
    aka!("write_n_8", "psyska -/");
    aka!("show_n_8", "psyska -/");
    aka!("display_n_8", "psyska -/");
    aka!("emit_n_8", "psyska -/");
    aka!("set_n_8", "set");
    aka!("store_n_8", "set");
    aka!("save_n_8", "set");
    aka!("add_n_v_8", "add");
    aka!("plus_n_8", "add");
    aka!("sum_n_8", "add");
    aka!("inc_n_8", "incr");
    aka!("tick_n_8", "incr");
    aka!("bump_n_8", "incr");
    aka!("dec_n_8", "decr");
    aka!("untick_n_8", "decr");
    aka!("rand_n_v_8", "rand");
    aka!("pick_n_v_8", "rand");
    aka!("rng_n_v_8", "rand");
    aka!("sleep_n_8", "sleep");
    aka!("nap_n_8", "sleep");
    aka!("rest_n_8", "sleep");
    aka!("wfile_n_8", "writefile");
    aka!("rfile_n_8", "readfile");
    aka!("mkd_n_8", "mkdir");
    aka!("rm_n_v_8", "rm");
    aka!("list_n_8", "list");
    aka!("push_n_v_8", "push");
    aka!("pop_n_v_8", "pop");
    aka!("lget_n_8", "lget");
    aka!("lset_n_8", "lset");
    aka!("lsize_n_8", "lsize");
    aka!("dict_n_8", "dict");
    aka!("dset_n_8", "dset");
    aka!("dget_n_8", "dget");
    aka!("dsize_n_8", "dsize");
    aka!("color_n_8", "color");
    aka!("exit_n_v_8", "exit");
    aka!("hg_n_8", "http_get");
    aka!("hp_n_8", "http_post");
    aka!("md5_n_8", "md5");
    aka!("sha256_n_8", "sha256");
    aka!("b64e_n_8", "base64_encode");
    aka!("b64d_n_8", "base64_decode");
    aka!("re_n_8", "regex_match");
    aka!("res_n_8", "regex_replace");
    aka!("now_n_v_8", "now");
    aka!("today_n_v_8", "today");
    aka!("up_n_8", "uppercase");
    aka!("lo_n_8", "lower");
    aka!("trim_n_8", "trim");
    aka!("rev_n_8", "reverse");
    aka!("split_n_8", "split");
    aka!("concat_n_8", "concat");
    aka!("uuid_n_8", "uuid");
    aka!("hostname_n_8", "hostname");
    aka!("table_n_8", "table");
    aka!("spin_n_8", "spin");
    aka!("banner_n_8", "banner");
    aka!("box_n_8", "box");
    aka!("progress_n_v_8", "progress");
    aka!("ffi_n_v_8", "ffi");
    aka!("exec_n_v_8", "exec");
    aka!("getenv_n_8", "getenv");
    aka!("setenv_n_8", "setenv");
    aka!("range_n_8", "range");
    aka!("first_n_8", "first");
    aka!("last_n_v_8", "last");
    aka!("lsort_n_8", "lsort");
    aka!("lreverse_n_8", "lreverse");
    aka!("lmax_n_8", "lmax");
    aka!("lmin_n_8", "lmin");
    aka!("lsum_n_8", "lsum");
    aka!("lavg_n_8", "lavg");
    aka!("lshuffle_n_8", "lshuffle");
    aka!("lchoice_n_8", "lchoice");
    aka!("abs_n_v_8", "abs");
    aka!("sign_n_8", "sign");
    aka!("floor_n_8", "floor");
    aka!("ceil_n_8", "ceil");
    aka!("round_n_8", "round");
    aka!("sqrt_n_8", "sqrt");
    aka!("fact_n_v_8", "factorial");
    aka!("fib_n_v_8", "fibonacci");
    aka!("tof_n_8", "type_of");
    aka!("hv_n_8", "has_var");
    aka!("fsz_n_8", "file_size");
    aka!("isd_n_8", "is_dir");
    aka!("isf_n_8", "is_file");
    aka!("bn_n_8", "basename");
    aka!("dn_n_8", "dirname");
    aka!("xn_n_8", "extname");
    aka!("ex_n_8", "exists");
    aka!("ll_n_8", "listdir");
    aka!("jp_n_8", "json_parse");
    aka!("js_n_8", "json_stringify");
    aka!("he_n_8", "html_escape");
    aka!("ue_n_8", "url_escape");
    aka!("ip2i_n_8", "ip_to_int");
    aka!("i2ip_n_8", "int_to_ip");
    aka!("say_n_9", "psyska -/");
    aka!("tell_n_9", "psyska -/");
    aka!("print_n_9", "psyska -/");
    aka!("out_n_9", "psyska -/");
    aka!("echo_n_9", "psyska -/");
    aka!("write_n_9", "psyska -/");
    aka!("show_n_9", "psyska -/");
    aka!("display_n_9", "psyska -/");
    aka!("emit_n_9", "psyska -/");
    aka!("set_n_9", "set");
    aka!("store_n_9", "set");
    aka!("save_n_9", "set");
    aka!("add_n_v_9", "add");
    aka!("plus_n_9", "add");
    aka!("sum_n_9", "add");
    aka!("inc_n_9", "incr");
    aka!("tick_n_9", "incr");
    aka!("bump_n_9", "incr");
    aka!("dec_n_9", "decr");
    aka!("untick_n_9", "decr");
    aka!("rand_n_v_9", "rand");
    aka!("pick_n_v_9", "rand");
    aka!("rng_n_v_9", "rand");
    aka!("sleep_n_9", "sleep");
    aka!("nap_n_9", "sleep");
    aka!("rest_n_9", "sleep");
    aka!("wfile_n_9", "writefile");
    aka!("rfile_n_9", "readfile");
    aka!("mkd_n_9", "mkdir");
    aka!("rm_n_v_9", "rm");
    aka!("list_n_9", "list");
    aka!("push_n_v_9", "push");
    aka!("pop_n_v_9", "pop");
    aka!("lget_n_9", "lget");
    aka!("lset_n_9", "lset");
    aka!("lsize_n_9", "lsize");
    aka!("dict_n_9", "dict");
    aka!("dset_n_9", "dset");
    aka!("dget_n_9", "dget");
    aka!("dsize_n_9", "dsize");
    aka!("color_n_9", "color");
    aka!("exit_n_v_9", "exit");
    aka!("hg_n_9", "http_get");
    aka!("hp_n_9", "http_post");
    aka!("md5_n_9", "md5");
    aka!("sha256_n_9", "sha256");
    aka!("b64e_n_9", "base64_encode");
    aka!("b64d_n_9", "base64_decode");
    aka!("re_n_9", "regex_match");
    aka!("res_n_9", "regex_replace");
    aka!("now_n_v_9", "now");
    aka!("today_n_v_9", "today");
    aka!("up_n_9", "uppercase");
    aka!("lo_n_9", "lower");
    aka!("trim_n_9", "trim");
    aka!("rev_n_9", "reverse");
    aka!("split_n_9", "split");
    aka!("concat_n_9", "concat");
    aka!("uuid_n_9", "uuid");
    aka!("hostname_n_9", "hostname");
    aka!("table_n_9", "table");
    aka!("spin_n_9", "spin");
    aka!("banner_n_9", "banner");
    aka!("box_n_9", "box");
    aka!("progress_n_v_9", "progress");
    aka!("ffi_n_v_9", "ffi");
    aka!("exec_n_v_9", "exec");
    aka!("getenv_n_9", "getenv");
    aka!("setenv_n_9", "setenv");
    aka!("range_n_9", "range");
    aka!("first_n_9", "first");
    aka!("last_n_v_9", "last");
    aka!("lsort_n_9", "lsort");
    aka!("lreverse_n_9", "lreverse");
    aka!("lmax_n_9", "lmax");
    aka!("lmin_n_9", "lmin");
    aka!("lsum_n_9", "lsum");
    aka!("lavg_n_9", "lavg");
    aka!("lshuffle_n_9", "lshuffle");
    aka!("lchoice_n_9", "lchoice");
    aka!("abs_n_v_9", "abs");
    aka!("sign_n_9", "sign");
    aka!("floor_n_9", "floor");
    aka!("ceil_n_9", "ceil");
    aka!("round_n_9", "round");
    aka!("sqrt_n_9", "sqrt");
    aka!("fact_n_v_9", "factorial");
    aka!("fib_n_v_9", "fibonacci");
    aka!("tof_n_9", "type_of");
    aka!("hv_n_9", "has_var");
    aka!("fsz_n_9", "file_size");
    aka!("isd_n_9", "is_dir");
    aka!("isf_n_9", "is_file");
    aka!("bn_n_9", "basename");
    aka!("dn_n_9", "dirname");
    aka!("xn_n_9", "extname");
    aka!("ex_n_9", "exists");
    aka!("ll_n_9", "listdir");
    aka!("jp_n_9", "json_parse");
    aka!("js_n_9", "json_stringify");
    aka!("he_n_9", "html_escape");
    aka!("ue_n_9", "url_escape");
    aka!("ip2i_n_9", "ip_to_int");
    aka!("i2ip_n_9", "int_to_ip");
    aka!("say_n_10", "psyska -/");
    aka!("tell_n_10", "psyska -/");
    aka!("print_n_10", "psyska -/");
    aka!("out_n_10", "psyska -/");
    aka!("echo_n_10", "psyska -/");
    aka!("write_n_10", "psyska -/");
    aka!("show_n_10", "psyska -/");
    aka!("display_n_10", "psyska -/");
    aka!("emit_n_10", "psyska -/");
    aka!("set_n_10", "set");
    aka!("store_n_10", "set");
    aka!("save_n_10", "set");
    aka!("add_n_v_10", "add");
    aka!("plus_n_10", "add");
    aka!("sum_n_10", "add");
    aka!("inc_n_10", "incr");
    aka!("tick_n_10", "incr");
    aka!("bump_n_10", "incr");
    aka!("dec_n_10", "decr");
    aka!("untick_n_10", "decr");
    aka!("rand_n_v_10", "rand");
    aka!("pick_n_v_10", "rand");
    aka!("rng_n_v_10", "rand");
    aka!("sleep_n_10", "sleep");
    aka!("nap_n_10", "sleep");
    aka!("rest_n_10", "sleep");
    aka!("wfile_n_10", "writefile");
    aka!("rfile_n_10", "readfile");
    aka!("mkd_n_10", "mkdir");
    aka!("rm_n_v_10", "rm");
    aka!("list_n_10", "list");
    aka!("push_n_v_10", "push");
    aka!("pop_n_v_10", "pop");
    aka!("lget_n_10", "lget");
    aka!("lset_n_10", "lset");
    aka!("lsize_n_10", "lsize");
    aka!("dict_n_10", "dict");
    aka!("dset_n_10", "dset");
    aka!("dget_n_10", "dget");
    aka!("dsize_n_10", "dsize");
    aka!("color_n_10", "color");
    aka!("exit_n_v_10", "exit");
    aka!("hg_n_10", "http_get");
    aka!("hp_n_10", "http_post");
    aka!("md5_n_10", "md5");
    aka!("sha256_n_10", "sha256");
    aka!("b64e_n_10", "base64_encode");
    aka!("b64d_n_10", "base64_decode");
    aka!("re_n_10", "regex_match");
    aka!("res_n_10", "regex_replace");
    aka!("now_n_v_10", "now");
    aka!("today_n_v_10", "today");
    aka!("up_n_10", "uppercase");
    aka!("lo_n_10", "lower");
    aka!("trim_n_10", "trim");
    aka!("rev_n_10", "reverse");
    aka!("split_n_10", "split");
    aka!("concat_n_10", "concat");
    aka!("uuid_n_10", "uuid");
    aka!("hostname_n_10", "hostname");
    aka!("table_n_10", "table");
    aka!("spin_n_10", "spin");
    aka!("banner_n_10", "banner");
    aka!("box_n_10", "box");
    aka!("progress_n_v_10", "progress");
    aka!("ffi_n_v_10", "ffi");
    aka!("exec_n_v_10", "exec");
    aka!("getenv_n_10", "getenv");
    aka!("setenv_n_10", "setenv");
    aka!("range_n_10", "range");
    aka!("first_n_10", "first");
    aka!("last_n_v_10", "last");
    aka!("lsort_n_10", "lsort");
    aka!("lreverse_n_10", "lreverse");
    aka!("lmax_n_10", "lmax");
    aka!("lmin_n_10", "lmin");
    aka!("lsum_n_10", "lsum");
    aka!("lavg_n_10", "lavg");
    aka!("lshuffle_n_10", "lshuffle");
    aka!("lchoice_n_10", "lchoice");
    aka!("abs_n_v_10", "abs");
    aka!("sign_n_10", "sign");
    aka!("floor_n_10", "floor");
    aka!("ceil_n_10", "ceil");
    aka!("round_n_10", "round");
    aka!("sqrt_n_10", "sqrt");
    aka!("fact_n_v_10", "factorial");
    aka!("fib_n_v_10", "fibonacci");
    aka!("tof_n_10", "type_of");
    aka!("hv_n_10", "has_var");
    aka!("fsz_n_10", "file_size");
    aka!("isd_n_10", "is_dir");
    aka!("isf_n_10", "is_file");
    aka!("bn_n_10", "basename");
    aka!("dn_n_10", "dirname");
    aka!("xn_n_10", "extname");
    aka!("ex_n_10", "exists");
    aka!("ll_n_10", "listdir");
    aka!("jp_n_10", "json_parse");
    aka!("js_n_10", "json_stringify");
    aka!("he_n_10", "html_escape");
    aka!("ue_n_10", "url_escape");
    aka!("ip2i_n_10", "ip_to_int");
    aka!("i2ip_n_10", "int_to_ip");
    aka!("say_n_11", "psyska -/");
    aka!("tell_n_11", "psyska -/");
    aka!("print_n_11", "psyska -/");
    aka!("out_n_11", "psyska -/");
    aka!("echo_n_11", "psyska -/");
    aka!("write_n_11", "psyska -/");
    aka!("show_n_11", "psyska -/");
    aka!("display_n_11", "psyska -/");
    aka!("emit_n_11", "psyska -/");
    aka!("set_n_11", "set");
    aka!("store_n_11", "set");
    aka!("save_n_11", "set");
    aka!("add_n_v_11", "add");
    aka!("plus_n_11", "add");
    aka!("sum_n_11", "add");
    aka!("inc_n_11", "incr");
    aka!("tick_n_11", "incr");
    aka!("bump_n_11", "incr");
    aka!("dec_n_11", "decr");
    aka!("untick_n_11", "decr");
    aka!("rand_n_v_11", "rand");
    aka!("pick_n_v_11", "rand");
    aka!("rng_n_v_11", "rand");
    aka!("sleep_n_11", "sleep");
    aka!("nap_n_11", "sleep");
    aka!("rest_n_11", "sleep");
    aka!("wfile_n_11", "writefile");
    aka!("rfile_n_11", "readfile");
    aka!("mkd_n_11", "mkdir");
    aka!("rm_n_v_11", "rm");
    aka!("list_n_11", "list");
    aka!("push_n_v_11", "push");
    aka!("pop_n_v_11", "pop");
    aka!("lget_n_11", "lget");
    aka!("lset_n_11", "lset");
    aka!("lsize_n_11", "lsize");
    aka!("dict_n_11", "dict");
    aka!("dset_n_11", "dset");
    aka!("dget_n_11", "dget");
    aka!("dsize_n_11", "dsize");
    aka!("color_n_11", "color");
    aka!("exit_n_v_11", "exit");
    aka!("hg_n_11", "http_get");
    aka!("hp_n_11", "http_post");
    aka!("md5_n_11", "md5");
    aka!("sha256_n_11", "sha256");
    aka!("b64e_n_11", "base64_encode");
    aka!("b64d_n_11", "base64_decode");
    aka!("re_n_11", "regex_match");
    aka!("res_n_11", "regex_replace");
    aka!("now_n_v_11", "now");
    aka!("today_n_v_11", "today");
    aka!("up_n_11", "uppercase");
    aka!("lo_n_11", "lower");
    aka!("trim_n_11", "trim");
    aka!("rev_n_11", "reverse");
    aka!("split_n_11", "split");
    aka!("concat_n_11", "concat");
    aka!("uuid_n_11", "uuid");
    aka!("hostname_n_11", "hostname");
    aka!("table_n_11", "table");
    aka!("spin_n_11", "spin");
    aka!("banner_n_11", "banner");
    aka!("box_n_11", "box");
    aka!("progress_n_v_11", "progress");
    aka!("ffi_n_v_11", "ffi");
    aka!("exec_n_v_11", "exec");
    aka!("getenv_n_11", "getenv");
    aka!("setenv_n_11", "setenv");
    aka!("range_n_11", "range");
    aka!("first_n_11", "first");
    aka!("last_n_v_11", "last");
    aka!("lsort_n_11", "lsort");
    aka!("lreverse_n_11", "lreverse");
    aka!("lmax_n_11", "lmax");
    aka!("lmin_n_11", "lmin");
    aka!("lsum_n_11", "lsum");
    aka!("lavg_n_11", "lavg");
    aka!("lshuffle_n_11", "lshuffle");
    aka!("lchoice_n_11", "lchoice");
    aka!("abs_n_v_11", "abs");
    aka!("sign_n_11", "sign");
    aka!("floor_n_11", "floor");
    aka!("ceil_n_11", "ceil");
    aka!("round_n_11", "round");
    aka!("sqrt_n_11", "sqrt");
    aka!("fact_n_v_11", "factorial");
    aka!("fib_n_v_11", "fibonacci");
    aka!("tof_n_11", "type_of");
    aka!("hv_n_11", "has_var");
    aka!("fsz_n_11", "file_size");
    aka!("isd_n_11", "is_dir");
    aka!("isf_n_11", "is_file");
    aka!("bn_n_11", "basename");
    aka!("dn_n_11", "dirname");
    aka!("xn_n_11", "extname");
    aka!("ex_n_11", "exists");
    aka!("ll_n_11", "listdir");
    aka!("jp_n_11", "json_parse");
    aka!("js_n_11", "json_stringify");
    aka!("he_n_11", "html_escape");
    aka!("ue_n_11", "url_escape");
    aka!("ip2i_n_11", "ip_to_int");
    aka!("i2ip_n_11", "int_to_ip");
    aka!("say_n_12", "psyska -/");
    aka!("tell_n_12", "psyska -/");
    aka!("print_n_12", "psyska -/");
    aka!("out_n_12", "psyska -/");
    aka!("echo_n_12", "psyska -/");
    aka!("write_n_12", "psyska -/");
    aka!("show_n_12", "psyska -/");
    aka!("display_n_12", "psyska -/");
    aka!("emit_n_12", "psyska -/");
    aka!("set_n_12", "set");
    aka!("store_n_12", "set");
    aka!("save_n_12", "set");
    aka!("add_n_v_12", "add");
    aka!("plus_n_12", "add");
    aka!("sum_n_12", "add");
    aka!("inc_n_12", "incr");
    aka!("tick_n_12", "incr");
    aka!("bump_n_12", "incr");
    aka!("dec_n_12", "decr");
    aka!("untick_n_12", "decr");
    aka!("rand_n_v_12", "rand");
    aka!("pick_n_v_12", "rand");
    aka!("rng_n_v_12", "rand");
    aka!("sleep_n_12", "sleep");
    aka!("nap_n_12", "sleep");
    aka!("rest_n_12", "sleep");
    aka!("wfile_n_12", "writefile");
    aka!("rfile_n_12", "readfile");
    aka!("mkd_n_12", "mkdir");
    aka!("rm_n_v_12", "rm");
    aka!("list_n_12", "list");
    aka!("push_n_v_12", "push");
    aka!("pop_n_v_12", "pop");
    aka!("lget_n_12", "lget");
    aka!("lset_n_12", "lset");
    aka!("lsize_n_12", "lsize");
    aka!("dict_n_12", "dict");
    aka!("dset_n_12", "dset");
    aka!("dget_n_12", "dget");
    aka!("dsize_n_12", "dsize");
    aka!("color_n_12", "color");
    aka!("exit_n_v_12", "exit");
    aka!("hg_n_12", "http_get");
    aka!("hp_n_12", "http_post");
    aka!("md5_n_12", "md5");
    aka!("sha256_n_12", "sha256");
    aka!("b64e_n_12", "base64_encode");
    aka!("b64d_n_12", "base64_decode");
    aka!("re_n_12", "regex_match");
    aka!("res_n_12", "regex_replace");
    aka!("now_n_v_12", "now");
    aka!("today_n_v_12", "today");
    aka!("up_n_12", "uppercase");
    aka!("lo_n_12", "lower");
    aka!("trim_n_12", "trim");
    aka!("rev_n_12", "reverse");
    aka!("split_n_12", "split");
    aka!("concat_n_12", "concat");
    aka!("uuid_n_12", "uuid");
    aka!("hostname_n_12", "hostname");
    aka!("table_n_12", "table");
    aka!("spin_n_12", "spin");
    aka!("banner_n_12", "banner");
    aka!("box_n_12", "box");
    aka!("progress_n_v_12", "progress");
    aka!("ffi_n_v_12", "ffi");
    aka!("exec_n_v_12", "exec");
    aka!("getenv_n_12", "getenv");
    aka!("setenv_n_12", "setenv");
    aka!("range_n_12", "range");
    aka!("first_n_12", "first");
    aka!("last_n_v_12", "last");
    aka!("lsort_n_12", "lsort");
    aka!("lreverse_n_12", "lreverse");
    aka!("lmax_n_12", "lmax");
    aka!("lmin_n_12", "lmin");
    aka!("lsum_n_12", "lsum");
    aka!("lavg_n_12", "lavg");
    aka!("lshuffle_n_12", "lshuffle");
    aka!("lchoice_n_12", "lchoice");
    aka!("abs_n_v_12", "abs");
    aka!("sign_n_12", "sign");
    aka!("floor_n_12", "floor");
    aka!("ceil_n_12", "ceil");
    aka!("round_n_12", "round");
    aka!("sqrt_n_12", "sqrt");
    aka!("fact_n_v_12", "factorial");
    aka!("fib_n_v_12", "fibonacci");
    aka!("tof_n_12", "type_of");
    aka!("hv_n_12", "has_var");
    aka!("fsz_n_12", "file_size");
    aka!("isd_n_12", "is_dir");
    aka!("isf_n_12", "is_file");
    aka!("bn_n_12", "basename");
    aka!("dn_n_12", "dirname");
    aka!("xn_n_12", "extname");
    aka!("ex_n_12", "exists");
    aka!("ll_n_12", "listdir");
    aka!("jp_n_12", "json_parse");
    aka!("js_n_12", "json_stringify");
    aka!("he_n_12", "html_escape");
    aka!("ue_n_12", "url_escape");
    aka!("ip2i_n_12", "ip_to_int");
    aka!("i2ip_n_12", "int_to_ip");
    aka!("say_n_13", "psyska -/");
    aka!("tell_n_13", "psyska -/");
    aka!("print_n_13", "psyska -/");
    aka!("out_n_13", "psyska -/");
    aka!("echo_n_13", "psyska -/");
    aka!("write_n_13", "psyska -/");
    aka!("show_n_13", "psyska -/");
    aka!("display_n_13", "psyska -/");
    aka!("emit_n_13", "psyska -/");
    aka!("set_n_13", "set");
    aka!("store_n_13", "set");
    aka!("save_n_13", "set");
    aka!("add_n_v_13", "add");
    aka!("plus_n_13", "add");
    aka!("sum_n_13", "add");
    aka!("inc_n_13", "incr");
    aka!("tick_n_13", "incr");
    aka!("bump_n_13", "incr");
    aka!("dec_n_13", "decr");
    aka!("untick_n_13", "decr");
    aka!("rand_n_v_13", "rand");
    aka!("pick_n_v_13", "rand");
    aka!("rng_n_v_13", "rand");
    aka!("sleep_n_13", "sleep");
    aka!("nap_n_13", "sleep");
    aka!("rest_n_13", "sleep");
    aka!("wfile_n_13", "writefile");
    aka!("rfile_n_13", "readfile");
    aka!("mkd_n_13", "mkdir");
    aka!("rm_n_v_13", "rm");
    aka!("list_n_13", "list");
    aka!("push_n_v_13", "push");
    aka!("pop_n_v_13", "pop");
    aka!("lget_n_13", "lget");
    aka!("lset_n_13", "lset");
    aka!("lsize_n_13", "lsize");
    aka!("dict_n_13", "dict");
    aka!("dset_n_13", "dset");
    aka!("dget_n_13", "dget");
    aka!("dsize_n_13", "dsize");
    aka!("color_n_13", "color");
    aka!("exit_n_v_13", "exit");
    aka!("hg_n_13", "http_get");
    aka!("hp_n_13", "http_post");
    aka!("md5_n_13", "md5");
    aka!("sha256_n_13", "sha256");
    aka!("b64e_n_13", "base64_encode");
    aka!("b64d_n_13", "base64_decode");
    aka!("re_n_13", "regex_match");
    aka!("res_n_13", "regex_replace");
    aka!("now_n_v_13", "now");
    aka!("today_n_v_13", "today");
    aka!("up_n_13", "uppercase");
    aka!("lo_n_13", "lower");
    aka!("trim_n_13", "trim");
    aka!("rev_n_13", "reverse");
    aka!("split_n_13", "split");
    aka!("concat_n_13", "concat");
    aka!("uuid_n_13", "uuid");
    aka!("hostname_n_13", "hostname");
    aka!("table_n_13", "table");
    aka!("spin_n_13", "spin");
    aka!("banner_n_13", "banner");
    aka!("box_n_13", "box");
    aka!("progress_n_v_13", "progress");
    aka!("ffi_n_v_13", "ffi");
    aka!("exec_n_v_13", "exec");
    aka!("getenv_n_13", "getenv");
    aka!("setenv_n_13", "setenv");
    aka!("range_n_13", "range");
    aka!("first_n_13", "first");
    aka!("last_n_v_13", "last");
    aka!("lsort_n_13", "lsort");
    aka!("lreverse_n_13", "lreverse");
    aka!("lmax_n_13", "lmax");
    aka!("lmin_n_13", "lmin");
    aka!("lsum_n_13", "lsum");
    aka!("lavg_n_13", "lavg");
    aka!("lshuffle_n_13", "lshuffle");
    aka!("lchoice_n_13", "lchoice");
    aka!("abs_n_v_13", "abs");
    aka!("sign_n_13", "sign");
    aka!("floor_n_13", "floor");
    aka!("ceil_n_13", "ceil");
    aka!("round_n_13", "round");
    aka!("sqrt_n_13", "sqrt");
    aka!("fact_n_v_13", "factorial");
    aka!("fib_n_v_13", "fibonacci");
    aka!("tof_n_13", "type_of");
    aka!("hv_n_13", "has_var");
    aka!("fsz_n_13", "file_size");
    aka!("isd_n_13", "is_dir");
    aka!("isf_n_13", "is_file");
    aka!("bn_n_13", "basename");
    aka!("dn_n_13", "dirname");
    aka!("xn_n_13", "extname");
    aka!("ex_n_13", "exists");
    aka!("ll_n_13", "listdir");
    aka!("jp_n_13", "json_parse");
    aka!("js_n_13", "json_stringify");
    aka!("he_n_13", "html_escape");
    aka!("ue_n_13", "url_escape");
    aka!("ip2i_n_13", "ip_to_int");
    aka!("i2ip_n_13", "int_to_ip");
    aka!("say_n_14", "psyska -/");
    aka!("tell_n_14", "psyska -/");
    aka!("print_n_14", "psyska -/");
    aka!("out_n_14", "psyska -/");
    aka!("echo_n_14", "psyska -/");
    aka!("write_n_14", "psyska -/");
    aka!("show_n_14", "psyska -/");
    aka!("display_n_14", "psyska -/");
    aka!("emit_n_14", "psyska -/");
    aka!("set_n_14", "set");
    aka!("store_n_14", "set");
    aka!("save_n_14", "set");
    aka!("add_n_v_14", "add");
    aka!("plus_n_14", "add");
    aka!("sum_n_14", "add");
    aka!("inc_n_14", "incr");
    aka!("tick_n_14", "incr");
    aka!("bump_n_14", "incr");
    aka!("dec_n_14", "decr");
    aka!("untick_n_14", "decr");
    aka!("rand_n_v_14", "rand");
    aka!("pick_n_v_14", "rand");
    aka!("rng_n_v_14", "rand");
    aka!("sleep_n_14", "sleep");
    aka!("nap_n_14", "sleep");
    aka!("rest_n_14", "sleep");
    aka!("wfile_n_14", "writefile");
    aka!("rfile_n_14", "readfile");
    aka!("mkd_n_14", "mkdir");
    aka!("rm_n_v_14", "rm");
    aka!("list_n_14", "list");
    aka!("push_n_v_14", "push");
    aka!("pop_n_v_14", "pop");
    aka!("lget_n_14", "lget");
    aka!("lset_n_14", "lset");
    aka!("lsize_n_14", "lsize");
    aka!("dict_n_14", "dict");
    aka!("dset_n_14", "dset");
    aka!("dget_n_14", "dget");
    aka!("dsize_n_14", "dsize");
    aka!("color_n_14", "color");
    aka!("exit_n_v_14", "exit");
    aka!("hg_n_14", "http_get");
    aka!("hp_n_14", "http_post");
    aka!("md5_n_14", "md5");
    aka!("sha256_n_14", "sha256");
    aka!("b64e_n_14", "base64_encode");
    aka!("b64d_n_14", "base64_decode");
    aka!("re_n_14", "regex_match");
    aka!("res_n_14", "regex_replace");
    aka!("now_n_v_14", "now");
    aka!("today_n_v_14", "today");
    aka!("up_n_14", "uppercase");
    aka!("lo_n_14", "lower");
    aka!("trim_n_14", "trim");
    aka!("rev_n_14", "reverse");
    aka!("split_n_14", "split");
    aka!("concat_n_14", "concat");
    aka!("uuid_n_14", "uuid");
    aka!("hostname_n_14", "hostname");
    aka!("table_n_14", "table");
    aka!("spin_n_14", "spin");
    aka!("banner_n_14", "banner");
    aka!("box_n_14", "box");
    aka!("progress_n_v_14", "progress");
    aka!("ffi_n_v_14", "ffi");
    aka!("exec_n_v_14", "exec");
    aka!("getenv_n_14", "getenv");
    aka!("setenv_n_14", "setenv");
    aka!("range_n_14", "range");
    aka!("first_n_14", "first");
    aka!("last_n_v_14", "last");
    aka!("lsort_n_14", "lsort");
    aka!("lreverse_n_14", "lreverse");
    aka!("lmax_n_14", "lmax");
    aka!("lmin_n_14", "lmin");
    aka!("lsum_n_14", "lsum");
    aka!("lavg_n_14", "lavg");
    aka!("lshuffle_n_14", "lshuffle");
    aka!("lchoice_n_14", "lchoice");
    aka!("abs_n_v_14", "abs");
    aka!("sign_n_14", "sign");
    aka!("floor_n_14", "floor");
    aka!("ceil_n_14", "ceil");
    aka!("round_n_14", "round");
    aka!("sqrt_n_14", "sqrt");
    aka!("fact_n_v_14", "factorial");
    aka!("fib_n_v_14", "fibonacci");
    aka!("tof_n_14", "type_of");
    aka!("hv_n_14", "has_var");
    aka!("fsz_n_14", "file_size");
    aka!("isd_n_14", "is_dir");
    aka!("isf_n_14", "is_file");
    aka!("bn_n_14", "basename");
    aka!("dn_n_14", "dirname");
    aka!("xn_n_14", "extname");
    aka!("ex_n_14", "exists");
    aka!("ll_n_14", "listdir");
    aka!("jp_n_14", "json_parse");
    aka!("js_n_14", "json_stringify");
    aka!("he_n_14", "html_escape");
    aka!("ue_n_14", "url_escape");
    aka!("ip2i_n_14", "ip_to_int");
    aka!("i2ip_n_14", "int_to_ip");
    aka!("say_n_15", "psyska -/");
    aka!("tell_n_15", "psyska -/");
    aka!("print_n_15", "psyska -/");
    aka!("out_n_15", "psyska -/");
    aka!("echo_n_15", "psyska -/");
    aka!("write_n_15", "psyska -/");
    aka!("show_n_15", "psyska -/");
    aka!("display_n_15", "psyska -/");
    aka!("emit_n_15", "psyska -/");
    aka!("set_n_15", "set");
    aka!("store_n_15", "set");
    aka!("save_n_15", "set");
    aka!("add_n_v_15", "add");
    aka!("plus_n_15", "add");
    aka!("sum_n_15", "add");
    aka!("inc_n_15", "incr");
    aka!("tick_n_15", "incr");
    aka!("bump_n_15", "incr");
    aka!("dec_n_15", "decr");
    aka!("untick_n_15", "decr");
    aka!("rand_n_v_15", "rand");
    aka!("pick_n_v_15", "rand");
    aka!("rng_n_v_15", "rand");
    aka!("sleep_n_15", "sleep");
    aka!("nap_n_15", "sleep");
    aka!("rest_n_15", "sleep");
    aka!("wfile_n_15", "writefile");
    aka!("rfile_n_15", "readfile");
    aka!("mkd_n_15", "mkdir");
    aka!("rm_n_v_15", "rm");
    aka!("list_n_15", "list");
    aka!("push_n_v_15", "push");
    aka!("pop_n_v_15", "pop");
    aka!("lget_n_15", "lget");
    aka!("lset_n_15", "lset");
    aka!("lsize_n_15", "lsize");
    aka!("dict_n_15", "dict");
    aka!("dset_n_15", "dset");
    aka!("dget_n_15", "dget");
    aka!("dsize_n_15", "dsize");
    aka!("color_n_15", "color");
    aka!("exit_n_v_15", "exit");
    aka!("hg_n_15", "http_get");
    aka!("hp_n_15", "http_post");
    aka!("md5_n_15", "md5");
    aka!("sha256_n_15", "sha256");
    aka!("b64e_n_15", "base64_encode");
    aka!("b64d_n_15", "base64_decode");
    aka!("re_n_15", "regex_match");
    aka!("res_n_15", "regex_replace");
    aka!("now_n_v_15", "now");
    aka!("today_n_v_15", "today");
    aka!("up_n_15", "uppercase");
    aka!("lo_n_15", "lower");
    aka!("trim_n_15", "trim");
    aka!("rev_n_15", "reverse");
    aka!("split_n_15", "split");
    aka!("concat_n_15", "concat");
    aka!("uuid_n_15", "uuid");
    aka!("hostname_n_15", "hostname");
    aka!("table_n_15", "table");
    aka!("spin_n_15", "spin");
    aka!("banner_n_15", "banner");
    aka!("box_n_15", "box");
    aka!("progress_n_v_15", "progress");
    aka!("ffi_n_v_15", "ffi");
    aka!("exec_n_v_15", "exec");
    aka!("getenv_n_15", "getenv");
    aka!("setenv_n_15", "setenv");
    aka!("range_n_15", "range");
    aka!("first_n_15", "first");
    aka!("last_n_v_15", "last");
    aka!("lsort_n_15", "lsort");
    aka!("lreverse_n_15", "lreverse");
    aka!("lmax_n_15", "lmax");
    aka!("lmin_n_15", "lmin");
    aka!("lsum_n_15", "lsum");
    aka!("lavg_n_15", "lavg");
    aka!("lshuffle_n_15", "lshuffle");
    aka!("lchoice_n_15", "lchoice");
    aka!("abs_n_v_15", "abs");
    aka!("sign_n_15", "sign");
    aka!("floor_n_15", "floor");
    aka!("ceil_n_15", "ceil");
    aka!("round_n_15", "round");
    aka!("sqrt_n_15", "sqrt");

    aka!("echo", "psyska -/");
    aka!("println", "psyska -/");
    aka!("print_l", "psyska -/");
    aka!("write_line", "psyska -/");
    aka!("p_one", "psyska -/");
    aka!("outln", "psyska -/");
    aka!("out_line", "psyska -/");
    aka!("out_str", "psyska -/");
    aka!("outmsg", "psyska -/");
    aka!("p_log", "psyska -/");
    aka!("log_line", "psyska -/");
    aka!("log_p", "psyska -/");
    aka!("log_pr", "psyska -/");
    aka!("tell", "psyska -/");
    aka!("say_line", "psyska -/");
    aka!("say2", "psyska -/");
    aka!("narrate2", "psyska -/");
    aka!("render_msg", "psyska -/");
    aka!("broadcast", "psyska -/");
    aka!("announce", "psyska -/");
    aka!("report", "psyska -/");
    aka!("msg_p", "psyska -/");
    aka!("msg2", "psyska -/");
    aka!("msg_out", "psyska -/");
    aka!("msg_out2", "psyska -/");
    aka!("alert", "psyska -/");
    aka!("alert2", "psyska -/");
    aka!("show_line", "psyska -/");
    aka!("show_str", "psyska -/");
    aka!("show3", "psyska -/");
    aka!("show_msg", "psyska -/");
    aka!("display", "psyska -/");
    aka!("display2", "psyska -/");
    aka!("display_line", "psyska -/");
    aka!("disp_line", "psyska -/");
    aka!("disp_msg", "psyska -/");
    aka!("dispmsg", "psyska -/");
    aka!("txt_print", "psyska -/");
    aka!("txt2", "psyska -/");
    aka!("txt_p", "psyska -/");
    aka!("txt_w", "psyska -/");
    aka!("txt_msg", "psyska -/");
    aka!("p1", "psyska -/");
    aka!("p2", "psyska -/");
    aka!("p3", "psyska -/");
    aka!("p4", "psyska -/");
    aka!("p5", "psyska -/");
    aka!("p_msg2", "psyska -/");
    aka!("psay", "psyska -/");
    aka!("p_say", "psyska -/");
    aka!("to_upper2", "upper");
    aka!("ucase", "upper");
    aka!("uc_str", "upper");
    aka!("uppercase_str", "upper");
    aka!("upcase", "upper");
    aka!("shout", "upper");
    aka!("capitalize_all", "upper");
    aka!("all_upper", "upper");
    aka!("all_caps", "upper");
    aka!("to_lower2", "lower");
    aka!("lcase", "lower");
    aka!("lc_str", "lower");
    aka!("string_length", "strlen");
    aka!("char_count", "strlen");
    aka!("char_length", "strlen");
    aka!("str_len2", "strlen");
    aka!("len2", "strlen");
    aka!("size_of_str", "strlen");
    aka!("txt_len", "strlen");
    aka!("list_length", "lsize");
    aka!("list_size2", "lsize");
    aka!("list_count_all", "lsize");
    aka!("num_items", "lsize");
    aka!("item_count2", "lsize");
    aka!("len_of_list", "lsize");
    aka!("dict_length", "dsize");
    aka!("dict_size2", "dsize");
    aka!("dict_count_all", "dsize");
    aka!("num_keys", "dsize");
    aka!("key_count", "dsize");
    aka!("hash_size", "dsize");
    aka!("to_int2", "intval");
    aka!("parse_int", "intval");
    aka!("atoi", "intval");
    aka!("as_int", "intval");
    aka!("integer_of", "intval");
    aka!("int_from_str", "intval");
    aka!("i_of", "intval");
    aka!("to_float2", "floatval");
    aka!("parse_float", "floatval");
    aka!("atof", "floatval");
    aka!("as_float", "floatval");
    aka!("float_of", "floatval");
    aka!("f_of", "floatval");
    aka!("real_of", "floatval");
    aka!("to_str", "tostring");
    aka!("str_of", "tostring");
    aka!("string_of", "tostring");
    aka!("as_str", "tostring");
    aka!("stringify", "tostring");
    aka!("repr2", "tostring");
    aka!("inspect2", "tostring");
    aka!("rev2", "reverse");
    aka!("string_reverse", "reverse");
    aka!("strip_ws", "trim");
    aka!("strip2", "trim");
    aka!("trim_str", "trim");
    aka!("chomp", "trim");
    aka!("trim_all", "trim");
    aka!("string_concat", "concat");
    aka!("str_append", "concat");
    aka!("stitch_str", "concat");
    aka!("str_split", "split");
    aka!("string_split", "split");
    aka!("tokens_of", "split");
    aka!("tokenize2", "split");
    aka!("string_replace", "replace");
    aka!("swap_str", "replace");
    aka!("substitute", "replace");
    aka!("subst2", "replace");
    aka!("str_swap", "replace");
    aka!("loop_n", "repeat");
    aka!("n_times", "repeat");
    aka!("do_n", "repeat");
    aka!("iter_n", "repeat");
    aka!("times_n", "repeat");
    aka!("rand_int_v", "rand");
    aka!("randomi", "rand");
    aka!("rnd_int", "rand");
    aka!("wait", "sleep");
    aka!("pause2", "sleep");
    aka!("delay", "sleep");
    aka!("hold2", "sleep");
    aka!("sleep_v", "sleep");
    aka!("now_ms_v", "now");
    aka!("current_ms", "now");
    aka!("millis_now", "now");
    aka!("ts_ms", "now");
    aka!("epoch_ms_v", "now");
    aka!("sin_v", "sin");
    aka!("sine", "sin");
    aka!("sin_of", "sin");
    aka!("cos_v", "cos");
    aka!("cosine", "cos");
    aka!("cos_of", "cos");
    aka!("tan_v", "tan");
    aka!("tangent", "tan");
    aka!("tan_of", "tan");
    aka!("abs2", "abs");
    aka!("magnitude", "abs");
    aka!("abs_of", "abs");
    aka!("modulus_n", "abs");
    aka!("sqrt2", "sqrt");
    aka!("sqrt_of", "sqrt");
    aka!("floor2", "floor");
    aka!("floor_of", "floor");
    aka!("ceil2", "ceil");
    aka!("ceil_of", "ceil");
    aka!("round2", "round");
    aka!("round_off", "round");
    aka!("round_of", "round");
    aka!("color_rgb", "rgb");
    aka!("from_rgb", "rgb");
    aka!("rgb_color", "rgb");
    aka!("rgb_make", "rgb");
    aka!("mklist", "list");
    aka!("list_append", "push");
    aka!("list_push", "push");
    aka!("append_to", "push");
    aka!("add_to_list", "push");
    aka!("list_pop", "pop");
    aka!("remove_last", "pop");
    aka!("tail_remove", "pop");
    aka!("list_set", "lset");
    aka!("set_index", "lset");
    aka!("assign_at", "lset");
    aka!("put_at", "lset");
    aka!("list_get", "lget");
    aka!("get_at", "lget");
    aka!("get_index", "lget");
    aka!("list_clear", "lclear");
    aka!("empty_list", "lclear");
    aka!("clear_list", "lclear");
    aka!("wipe_list", "lclear");
    aka!("reset_list", "lclear");
    aka!("abs_alt", "abs");
    aka!("abspath_alt", "abspath");
    aka!("add_days_alt", "add_days");
    aka!("append_file_alt", "append_file");
    aka!("arch_name_alt", "arch_name");
    aka!("arrow_down_alt", "arrow_down");
    aka!("arrow_left_alt", "arrow_left");
    aka!("arrow_right_alt", "arrow_right");
    aka!("arrow_up_alt", "arrow_up");
    aka!("askstring_alt", "askstring");
    aka!("askyesno_alt", "askyesno");
    aka!("assert_alt", "assert");
    aka!("assert_eq_alt", "assert_eq");
    aka!("assert_gt_alt", "assert_gt");
    aka!("assert_lt_alt", "assert_lt");
    aka!("assert_ne_alt", "assert_ne");
    aka!("async_alt", "async");
    aka!("atan2_alt", "atan2");
    aka!("atbash_alt", "atbash");
    aka!("avg_alt", "avg");
    aka!("await_alt", "await");
    aka!("backup_file_alt", "backup_file");
    aka!("band_alt", "band");
    aka!("banner_alt", "banner");
    aka!("barchart_alt", "barchart");
    aka!("base64_decode_alt", "base64_decode");
    aka!("base64_encode_alt", "base64_encode");
    aka!("basename_alt", "basename");
    aka!("benchmark_alt", "benchmark");
    aka!("bgrgb_alt", "bgrgb");
    aka!("bnot_alt", "bnot");
    aka!("bor_alt", "bor");
    aka!("box_alt", "box");
    aka!("bxor_alt", "bxor");
    aka!("caesar_decode_alt", "caesar_decode");
    aka!("caesar_encode_alt", "caesar_encode");
    aka!("calc_alt", "calc");
    aka!("call_alt", "call");
    aka!("capitalize_alt", "capitalize");
    aka!("catch_alt", "catch");
    aka!("ceil_alt", "ceil");
    aka!("center_alt", "center");
    aka!("chars_alt", "chars");
    aka!("choose_alt", "choose");
    aka!("chr_alt", "chr");
    aka!("clamp_alt", "clamp");
    aka!("clamp_int_alt", "clamp_int");
    aka!("class_alt", "class");
    aka!("coin_alt", "coin");
    aka!("color_alt", "color");
    aka!("concat_alt", "concat");
    aka!("const_alt", "const");
    aka!("contains_alt", "contains");
    aka!("contains_all_alt", "contains_all");
    aka!("contains_any_alt", "contains_any");
    aka!("copy_alt", "copy");
    aka!("copy_var_alt", "copy_var");
    aka!("countdown_alt", "countdown");
    aka!("count_lines_matching_alt", "count_lines_matching");
    aka!("count_substr_alt", "count_substr");
    aka!("countup_alt", "countup");
    aka!("count_words_alt", "count_words");
    aka!("crc32_alt", "crc32");
    aka!("ctype_alt", "ctype");
    aka!("d20_alt", "d20");
    aka!("d6_alt", "d6");
    aka!("datefmt_alt", "datefmt");
    aka!("date_today_alt", "date_today");
    aka!("date_tomorrow_alt", "date_tomorrow");
    aka!("date_yesterday_alt", "date_yesterday");
    aka!("day_alt", "day");
    aka!("dayname_alt", "dayname");
    aka!("dayofyear_alt", "dayofyear");
    aka!("days_in_month_alt", "days_in_month");
    aka!("days_in_year_alt", "days_in_year");
    aka!("db_begin_alt", "db_begin");
    aka!("db_close_alt", "db_close");
    aka!("db_commit_alt", "db_commit");
    aka!("db_count_alt", "db_count");
    aka!("db_exec_alt", "db_exec");
    aka!("db_exists_alt", "db_exists");
    aka!("db_insert_alt", "db_insert");
    aka!("db_open_alt", "db_open");
    aka!("db_query_alt", "db_query");
    aka!("db_rollback_alt", "db_rollback");
    aka!("db_tables_alt", "db_tables");
    aka!("dclear_alt", "dclear");
    aka!("dcount_value_alt", "dcount_value");
    aka!("ddel_alt", "ddel");
    aka!("decr_alt", "decr");
    aka!("deg_to_rad_alt", "deg_to_rad");
    aka!("delete_alt", "delete");
    aka!("dget_alt", "dget");
    aka!("dhas_alt", "dhas");
    aka!("dict_alt", "dict");
    aka!("diff_days_alt", "diff_days");
    aka!("dincr_alt", "dincr");
    aka!("dinvert_alt", "dinvert");
    aka!("dir_exists_alt", "dir_exists");
    aka!("dirname_alt", "dirname");
    aka!("distance_alt", "distance");
    aka!("divider_alt", "divider");
    aka!("dkeys_alt", "dkeys");
    aka!("dmerge_alt", "dmerge");
    aka!("docs_alt", "docs");
    aka!("domit_alt", "domit");
    aka!("download_alt", "download");
    aka!("dpairs_alt", "dpairs");
    aka!("dpick_alt", "dpick");
    aka!("dpop_alt", "dpop");
    aka!("dprint_alt", "dprint");
    aka!("dset_alt", "dset");
    aka!("dsize_alt", "dsize");
    aka!("dvalues_alt", "dvalues");
    aka!("e_alt", "e");
    aka!("echo_alt", "echo");
    aka!("endswith_alt", "endswith");
    aka!("ensure_dir_alt", "ensure_dir");
    aka!("enum_alt", "enum");
    aka!("env_dict_alt", "env_dict");
    aka!("env_list_alt", "env_list");
    aka!("env_size_alt", "env_size");
    aka!("exec_alt", "exec");
    aka!("exists_alt", "exists");
    aka!("extname_alt", "extname");
    aka!("factorial_alt", "factorial");
    aka!("ffi_alt", "ffi");
    aka!("fficall_alt", "fficall");
    aka!("ffiload_alt", "ffiload");
    aka!("fibonacci_alt", "fibonacci");
    aka!("field_alt", "field");
    aka!("file_age_alt", "file_age");
    aka!("file_count_in_dir_alt", "file_count_in_dir");
    aka!("file_empty_alt", "file_empty");
    aka!("file_ext_alt", "file_ext");
    aka!("file_grep_alt", "file_grep");
    aka!("file_hash_alt", "file_hash");
    aka!("file_head_alt", "file_head");
    aka!("file_lines_count_alt", "file_lines_count");
    aka!("file_mtime_alt", "file_mtime");
    aka!("file_replace_alt", "file_replace");
    aka!("file_size_alt", "file_size");
    aka!("file_size_human_alt", "file_size_human");
    aka!("file_stem_alt", "file_stem");
    aka!("file_tail_alt", "file_tail");
    aka!("file_words_count_alt", "file_words_count");
    aka!("file_writable_alt", "file_writable");
    aka!("find_files_alt", "find_files");
    aka!("find_index_alt", "find_index");
    aka!("first_alt", "first");
    aka!("first_word_alt", "first_word");
    aka!("floor_alt", "floor");
    aka!("fmax_alt", "fmax");
    aka!("fmin_alt", "fmin");
    aka!("foreach_alt", "foreach");
    aka!("format_alt", "format");
    aka!("format_bytes_alt", "format_bytes");
    aka!("format_duration_alt", "format_duration");
    aka!("format_number_alt", "format_number");
    aka!("form_encode_alt", "form_encode");
    aka!("from_bin_alt", "from_bin");
    aka!("from_hex_alt", "from_hex");
    aka!("from_unix_alt", "from_unix");
    aka!("func_alt", "func");
    aka!("gcd_alt", "gcd");
    aka!("gcd3_alt", "gcd3");
    aka!("get_alt", "get");
    aka!("getenv_alt", "getenv");
    aka!("getf_alt", "getf");
    aka!("gethome_alt", "gethome");
    aka!("getuser_alt", "getuser");
    aka!("gotoxy_alt", "gotoxy");
    aka!("gui_alpha_pixel_alt", "gui_alpha_pixel");
    aka!("gui_blit_ppm_alt", "gui_blit_ppm");
    aka!("gui_circle_alt", "gui_circle");
    aka!("gui_clear_alt", "gui_clear");
    aka!("gui_clear_rect_alt", "gui_clear_rect");
    aka!("gui_ellipse_alt", "gui_ellipse");
    aka!("gui_fill_circle_alt", "gui_fill_circle");
    aka!("gui_fill_rect_alt", "gui_fill_rect");
    aka!("gui_fill_triangle_alt", "gui_fill_triangle");
    aka!("gui_fps_alt", "gui_fps");
    aka!("gui_get_pixel_alt", "gui_get_pixel");
    aka!("gui_gradient_rect_alt", "gui_gradient_rect");
    aka!("gui_is_focused_alt", "gui_is_focused");
    aka!("gui_key_down_alt", "gui_key_down");
    aka!("gui_line_alt", "gui_line");
    aka!("gui_mouse_down_alt", "gui_mouse_down");
    aka!("gui_mouse_wheel_alt", "gui_mouse_wheel");
    aka!("gui_mouse_x_alt", "gui_mouse_x");
    aka!("gui_mouse_y_alt", "gui_mouse_y");
    aka!("gui_native_alt", "gui_native");
    aka!("gui_open_alt", "gui_open");
    aka!("gui_pixel_alt", "gui_pixel");
    aka!("gui_polygon_alt", "gui_polygon");
    aka!("gui_rect_alt", "gui_rect");
    aka!("gui_screenshot_alt", "gui_screenshot");
    aka!("gui_set_title_alt", "gui_set_title");
    aka!("gui_show_alt", "gui_show");
    aka!("gui_text_alt", "gui_text");
    aka!("gui_text_big_alt", "gui_text_big");
    aka!("gui_text_width_alt", "gui_text_width");
    aka!("gui_thick_line_alt", "gui_thick_line");
    aka!("gui_window_alt", "gui_window");
    aka!("gui_window_h_alt", "gui_window_h");
    aka!("gui_window_w_alt", "gui_window_w");
    aka!("hamming_distance_alt", "hamming_distance");
    aka!("has_var_alt", "has_var");
    aka!("hex_decode_alt", "hex_decode");
    aka!("hex_encode_alt", "hex_encode");
    aka!("hmac_sha256_alt", "hmac_sha256");
    aka!("hostname_alt", "hostname");
    aka!("hour_now_alt", "hour_now");
    aka!("hr_alt", "hr");
    aka!("html_escape_alt", "html_escape");
    aka!("http_delete_alt", "http_delete");
    aka!("http_get_alt", "http_get");
    aka!("http_post_alt", "http_post");
    aka!("http_put_alt", "http_put");
    aka!("hypot_alt", "hypot");
    aka!("if_alt", "if");
    aka!("implements_alt", "implements");
    aka!("importayaan_alt", "importayaan");
    aka!("importpkg_alt", "importpkg");
    aka!("incr_alt", "incr");
    aka!("inspect_alt", "inspect");
    aka!("instanceof_alt", "instanceof");
    aka!("interface_alt", "interface");
    aka!("int_to_ip_alt", "int_to_ip");
    aka!("ip_to_int_alt", "ip_to_int");
    aka!("ip_v4_check_alt", "ip_v4_check");
    aka!("iqr_alt", "iqr");
    aka!("is_alnum_alt", "is_alnum");
    aka!("is_alpha_alt", "is_alpha");
    aka!("is_anagram_alt", "is_anagram");
    aka!("is_ascii_alt", "is_ascii");
    aka!("is_digit_alt", "is_digit");
    aka!("is_dir_alt", "is_dir");
    aka!("is_even_alt", "is_even");
    aka!("is_file_alt", "is_file");
    aka!("is_leap_year_alt", "is_leap_year");
    aka!("is_lower_alt", "is_lower");
    aka!("is_odd_alt", "is_odd");
    aka!("is_palindrome_alt", "is_palindrome");
    aka!("is_prime_alt", "is_prime");
    aka!("is_root_alt", "is_root");
    aka!("is_today_alt", "is_today");
    aka!("is_upper_alt", "is_upper");
    aka!("is_weekend_alt", "is_weekend");
    aka!("is_whitespace_alt", "is_whitespace");
    aka!("jaccard_alt", "jaccard");
    aka!("joinpath_alt", "joinpath");
    aka!("jscall_alt", "jscall");
    aka!("json_alt", "json");
    aka!("json_escape_str_alt", "json_escape_str");
    aka!("json_get_path_alt", "json_get_path");
    aka!("json_parse_alt", "json_parse");
    aka!("json_pretty_alt", "json_pretty");
    aka!("json_stringify_alt", "json_stringify");
    aka!("lall_neg_alt", "lall_neg");
    aka!("lall_pos_alt", "lall_pos");
    aka!("lall_zero_alt", "lall_zero");
    aka!("lambda_alt", "lambda");
    aka!("lang_env_alt", "lang_env");
    aka!("lany_pos_alt", "lany_pos");
    aka!("lany_zero_alt", "lany_zero");
    aka!("last_alt", "last");
    aka!("last_word_alt", "last_word");
    aka!("lavg_alt", "lavg");
    aka!("lchoice_alt", "lchoice");
    aka!("lclear_alt", "lclear");
    aka!("lcm_alt", "lcm");
    aka!("lcompact_alt", "lcompact");
    aka!("lconcat_alt", "lconcat");
    aka!("lcontains_alt", "lcontains");
    aka!("lcopy_alt", "lcopy");
    aka!("lcount_eq_alt", "lcount_eq");
    aka!("lcount_neg_alt", "lcount_neg");
    aka!("lcount_pos_alt", "lcount_pos");
    aka!("lcount_zero_alt", "lcount_zero");
    aka!("lcumprod_alt", "lcumprod");
    aka!("lcumsum_alt", "lcumsum");
    aka!("ld_get_alt", "ld_get");
    aka!("ldiff_lists_alt", "ldiff_lists");
    aka!("ldrop_alt", "ldrop");
    aka!("ld_set_alt", "ld_set");
    aka!("left_alt", "left");
    aka!("lerp_alt", "lerp");
    aka!("letter_freq_alt", "letter_freq");
    aka!("levenshtein_alt", "levenshtein");
    aka!("lextend_alt", "lextend");
    aka!("lfill_alt", "lfill");
    aka!("lget_alt", "lget");
    aka!("lindex_alt", "lindex");
    aka!("linit_alt", "linit");
    aka!("linsert_alt", "linsert");
    aka!("lis_sorted_alt", "lis_sorted");
    aka!("list_alt", "list");
    aka!("listdir_alt", "listdir");
    aka!("lis_unique_alt", "lis_unique");
    aka!("ljoin_alt", "ljoin");
    aka!("lmax_alt", "lmax");
    aka!("lmedian_alt", "lmedian");
    aka!("lmin_alt", "lmin");
    aka!("loadenv_alt", "loadenv");
    aka!("local_ip_alt", "local_ip");
    aka!("log_alt", "log");
    aka!("log_base_alt", "log_base");
    aka!("logfile_alt", "logfile");
    aka!("lones_alt", "lones");
    aka!("longest_common_alt", "longest_common");
    aka!("lower_alt", "lower");
    aka!("lpartition_alt", "lpartition");
    aka!("lpop_front_alt", "lpop_front");
    aka!("lprepend_alt", "lprepend");
    aka!("lprint_alt", "lprint");
    aka!("lproduct_alt", "lproduct");
    aka!("lremove_alt", "lremove");
    aka!("lremove_at_alt", "lremove_at");
    aka!("lreplace_all_alt", "lreplace_all");
    aka!("lreverse_alt", "lreverse");
    aka!("lreverse_copy_alt", "lreverse_copy");
    aka!("lscan_alt", "lscan");
    aka!("lset_alt", "lset");
    aka!("lshuffle_alt", "lshuffle");
    aka!("lsize_alt", "lsize");
    aka!("lsort_alt", "lsort");
    aka!("lstddev_alt", "lstddev");
    aka!("lsum_alt", "lsum");
    aka!("lswap_alt", "lswap");
    aka!("ltail_alt", "ltail");
    aka!("ltake_alt", "ltake");
    aka!("lunique_alt", "lunique");
    aka!("lvariance_alt", "lvariance");
    aka!("lwindow_alt", "lwindow");
    aka!("lzeros_alt", "lzeros");
    aka!("lzip_alt", "lzip");
    aka!("mac_format_alt", "mac_format");
    aka!("manhattan_alt", "manhattan");
    aka!("map_range_alt", "map_range");
    aka!("matchv_alt", "matchv");
    aka!("max_alt", "max");
    aka!("max_var_alt", "max_var");
    aka!("md5_alt", "md5");
    aka!("method_alt", "method");
    aka!("midnight_today_alt", "midnight_today");
    aka!("min_alt", "min");
    aka!("minute_now_alt", "minute_now");
    aka!("min_var_alt", "min_var");
    aka!("mkdir_alt", "mkdir");
    aka!("mod_pow_alt", "mod_pow");
    aka!("module_alt", "module");
    aka!("month_alt", "month");
    aka!("monthname_alt", "monthname");
    aka!("months_between_alt", "months_between");
    aka!("move_alt", "move");
    aka!("new_alt", "new");
    aka!("noop_alt", "noop");
    aka!("normalize_alt", "normalize");
    aka!("normalize_path_alt", "normalize_path");
    aka!("note_alt", "note");
    aka!("now_alt", "now");
    aka!("now_iso_alt", "now_iso");
    aka!("now_minus_days_alt", "now_minus_days");
    aka!("now_plus_days_alt", "now_plus_days");
    aka!("nproc_alt", "nproc");
    aka!("nth_prime_alt", "nth_prime");
    aka!("nth_root_alt", "nth_root");
    aka!("nth_word_alt", "nth_word");
    aka!("ord_alt", "ord");
    aka!("os_family_alt", "os_family");
    aka!("os_name_alt", "os_name");
    aka!("pad_alt", "pad");
    aka!("pad_left_alt", "pad_left");
    aka!("panic_alt", "panic");
    aka!("parse_query_alt", "parse_query");
    aka!("percentile_alt", "percentile");
    aka!("percentile_25_alt", "percentile_25");
    aka!("percentile_75_alt", "percentile_75");
    aka!("perms_alt", "perms");
    aka!("phi_alt", "phi");
    aka!("pi_alt", "pi");
    aka!("pid_alt", "pid");
    aka!("ping_alt", "ping");
    aka!("pkg_asset_path_alt", "pkg_asset_path");
    aka!("pkg_asset_read_alt", "pkg_asset_read");
    aka!("pkg_db_open_alt", "pkg_db_open");
    aka!("pkg_run_sql_alt", "pkg_run_sql");
    aka!("platform_alt", "platform");
    aka!("play_alt", "play");
    aka!("pop_alt", "pop");
    aka!("post_alt", "post");
    aka!("pow_alt", "pow");
    aka!("prime_factors_alt", "prime_factors");
    aka!("primes_up_to_alt", "primes_up_to");
    aka!("printf_alt", "printf");
    aka!("progress_alt", "progress");
    aka!("public_ip_alt", "public_ip");
    aka!("push_alt", "push");
    aka!("put_alt", "put");
    aka!("pwd_alt", "pwd");
    aka!("pycall_alt", "pycall");
    aka!("quarter_of_alt", "quarter_of");
    aka!("rad_to_deg_alt", "rad_to_deg");
    aka!("raise_alt", "raise");
    aka!("rand_bool_alt", "rand_bool");
    aka!("rand_digit_alt", "rand_digit");
    aka!("rand_float_alt", "rand_float");
    aka!("rand_hex_char_alt", "rand_hex_char");
    aka!("rand_letter_alt", "rand_letter");
    aka!("random_bytes_alt", "random_bytes");
    aka!("random_ipv4_alt", "random_ipv4");
    aka!("random_mac_alt", "random_mac");
    aka!("random_password_alt", "random_password");
    aka!("random_port_alt", "random_port");
    aka!("rand_uppercase_alt", "rand_uppercase");
    aka!("range_alt", "range");
    aka!("range_stat_alt", "range_stat");
    aka!("readfile_alt", "readfile");
    aka!("read_first_line_alt", "read_first_line");
    aka!("read_last_line_alt", "read_last_line");
    aka!("read_lines_alt", "read_lines");
    aka!("redirect_alt", "redirect");
    aka!("regex_all_matches_alt", "regex_all_matches");
    aka!("regex_capture_alt", "regex_capture");
    aka!("regex_match_alt", "regex_match");
    aka!("regex_replace_alt", "regex_replace");
    aka!("repeat_alt", "repeat");
    aka!("repeat_call_alt", "repeat_call");
    aka!("repeat_print_alt", "repeat_print");
    aka!("repeat_str_alt", "repeat_str");
    aka!("replace_alt", "replace");
    aka!("retry_alt", "retry");
    aka!("return_alt", "return");
    aka!("reverse_alt", "reverse");
    aka!("rgb_alt", "rgb");
    aka!("right_alt", "right");
    aka!("rm_alt", "rm");
    aka!("rmdir_alt", "rmdir");
    aka!("rot13_alt", "rot13");
    aka!("round_alt", "round");
    aka!("round_to_alt", "round_to");
    aka!("route_alt", "route");
    aka!("second_now_alt", "second_now");
    aka!("selfget_alt", "selfget");
    aka!("selfset_alt", "selfset");
    aka!("send_alt", "send");
    aka!("serve_alt", "serve");
    aka!("servefile_alt", "servefile");
    aka!("set_diff_alt", "set_diff");
    aka!("setenv_alt", "setenv");
    aka!("set_eq_alt", "set_eq");
    aka!("setf_alt", "setf");
    aka!("set_int_alt", "set_int");
    aka!("set_intersect_alt", "set_intersect");
    aka!("set_string_alt", "set_string");
    aka!("set_union_alt", "set_union");
    aka!("sha1_alt", "sha1");
    aka!("sha256_alt", "sha256");
    aka!("sha512_alt", "sha512");
    aka!("shell_escape_alt", "shell_escape");
    aka!("shell_name_alt", "shell_name");
    aka!("shl_alt", "shl");
    aka!("shr_alt", "shr");
    aka!("sign_alt", "sign");
    aka!("sleep_ms_alt", "sleep_ms");
    aka!("sparkline_alt", "sparkline");
    aka!("spawn_alt", "spawn");
    aka!("spin_alt", "spin");
    aka!("split_alt", "split");
    aka!("sqrt_alt", "sqrt");
    aka!("sqrt2_alt", "sqrt2");
    aka!("startswith_alt", "startswith");
    aka!("static_alt", "static");
    aka!("status_alt", "status");
    aka!("str_chunk_alt", "str_chunk");
    aka!("str_eq_ci_alt", "str_eq_ci");
    aka!("strip_left_alt", "strip_left");
    aka!("strip_right_alt", "strip_right");
    aka!("str_is_float_alt", "str_is_float");
    aka!("str_is_int_alt", "str_is_int");
    aka!("str_is_numeric_alt", "str_is_numeric");
    aka!("strlen_alt", "strlen");
    aka!("str_lines_alt", "str_lines");
    aka!("str_pad_zero_alt", "str_pad_zero");
    aka!("substr_alt", "substr");
    aka!("sum_alt", "sum");
    aka!("swap_vars_alt", "swap_vars");
    aka!("switch_alt", "switch");
    aka!("table_alt", "table");
    aka!("tau_alt", "tau");
    aka!("term_name_var_alt", "term_name_var");
    aka!("term_size_alt", "term_size");
    aka!("test_fail_alt", "test_fail");
    aka!("test_pass_alt", "test_pass");
    aka!("test_skip_alt", "test_skip");
    aka!("time_end_alt", "time_end");
    aka!("times_alt", "times");
    aka!("timestamp_ms_alt", "timestamp_ms");
    aka!("time_start_alt", "time_start");
    aka!("title_alt", "title");
    aka!("titlebar_alt", "titlebar");
    aka!("to_bin_alt", "to_bin");
    aka!("to_constant_alt", "to_constant");
    aka!("todo_alt", "todo");
    aka!("toggle_alt", "toggle");
    aka!("to_hex_alt", "to_hex");
    aka!("to_int_alt", "to_int");
    aka!("tomorrow_iso_alt", "tomorrow_iso");
    aka!("to_oct_alt", "to_oct");
    aka!("to_pascal_alt", "to_pascal");
    aka!("to_str_alt", "to_str");
    aka!("tostring_alt", "tostring");
    aka!("touch_alt", "touch");
    aka!("to_unix_alt", "to_unix");
    aka!("triangular_alt", "triangular");
    aka!("trim_alt", "trim");
    aka!("trunc_alt", "trunc");
    aka!("truncate_alt", "truncate");
    aka!("type_of_alt", "type_of");
    aka!("typeof_alt", "typeof");
    aka!("unset_var_alt", "unset_var");
    aka!("upper_alt", "upper");
    aka!("uppercase_alt", "uppercase");
    aka!("uptime_alt", "uptime");
    aka!("url_escape_alt", "url_escape");
    aka!("url_host_alt", "url_host");
    aka!("url_path_alt", "url_path");
    aka!("url_query_alt", "url_query");
    aka!("url_scheme_alt", "url_scheme");
    aka!("uuid_alt", "uuid");
    aka!("vprint_alt", "vprint");
    aka!("warn_alt", "warn");
    aka!("watchfile_alt", "watchfile");
    aka!("weekday_alt", "weekday");
    aka!("week_of_year_alt", "week_of_year");
    aka!("which_alt", "which");
    aka!("while_alt", "while");
    aka!("word_freq_alt", "word_freq");
    aka!("words_alt", "words");
    aka!("writefile_alt", "writefile");
    aka!("write_lines_alt", "write_lines");
    aka!("ws_broadcast_alt", "ws_broadcast");
    aka!("ws_clients_alt", "ws_clients");
    aka!("ws_last_alt", "ws_last");
    aka!("ws_recv_alt", "ws_recv");
    aka!("ws_send_alt", "ws_send");
    aka!("ws_serve_alt", "ws_serve");
    aka!("year_alt", "year");
    aka!("years_between_alt", "years_between");
    aka!("yesterday_iso_alt", "yesterday_iso");
    aka!("zero_var_alt", "zero_var");
    aka!("abs_alt2", "abs");
    aka!("abspath_alt2", "abspath");
    aka!("add_days_alt2", "add_days");
    aka!("append_file_alt2", "append_file");
    aka!("arch_name_alt2", "arch_name");
    aka!("arrow_down_alt2", "arrow_down");
    aka!("arrow_left_alt2", "arrow_left");
    aka!("arrow_right_alt2", "arrow_right");
    aka!("arrow_up_alt2", "arrow_up");
    aka!("askstring_alt2", "askstring");
    aka!("askyesno_alt2", "askyesno");
    aka!("assert_alt2", "assert");
    aka!("assert_eq_alt2", "assert_eq");
    aka!("assert_gt_alt2", "assert_gt");
    aka!("assert_lt_alt2", "assert_lt");
    aka!("assert_ne_alt2", "assert_ne");
    aka!("async_alt2", "async");
    aka!("atan2_alt2", "atan2");
    aka!("atbash_alt2", "atbash");
    aka!("avg_alt2", "avg");
    aka!("await_alt2", "await");
    aka!("backup_file_alt2", "backup_file");
    aka!("band_alt2", "band");
    aka!("banner_alt2", "banner");
    aka!("barchart_alt2", "barchart");
    aka!("base64_decode_alt2", "base64_decode");
    aka!("base64_encode_alt2", "base64_encode");
    aka!("basename_alt2", "basename");
    aka!("benchmark_alt2", "benchmark");
    aka!("bgrgb_alt2", "bgrgb");
    aka!("bnot_alt2", "bnot");
    aka!("bor_alt2", "bor");
    aka!("box_alt2", "box");
    aka!("bxor_alt2", "bxor");
    aka!("caesar_decode_alt2", "caesar_decode");
    aka!("caesar_encode_alt2", "caesar_encode");
    aka!("calc_alt2", "calc");
    aka!("call_alt2", "call");
    aka!("capitalize_alt2", "capitalize");
    aka!("catch_alt2", "catch");
    aka!("ceil_alt2", "ceil");
    aka!("center_alt2", "center");
    aka!("chars_alt2", "chars");
    aka!("choose_alt2", "choose");
    aka!("chr_alt2", "chr");
    aka!("clamp_alt2", "clamp");
    aka!("clamp_int_alt2", "clamp_int");
    aka!("class_alt2", "class");
    aka!("coin_alt2", "coin");
    aka!("color_alt2", "color");
    aka!("concat_alt2", "concat");
    aka!("const_alt2", "const");
    aka!("contains_alt2", "contains");
    aka!("contains_all_alt2", "contains_all");
    aka!("contains_any_alt2", "contains_any");
    aka!("copy_alt2", "copy");
    aka!("copy_var_alt2", "copy_var");
    aka!("countdown_alt2", "countdown");
    aka!("count_lines_matching_alt2", "count_lines_matching");
    aka!("count_substr_alt2", "count_substr");
    aka!("countup_alt2", "countup");
    aka!("count_words_alt2", "count_words");
    aka!("crc32_alt2", "crc32");
    aka!("ctype_alt2", "ctype");
    aka!("d20_alt2", "d20");
    aka!("d6_alt2", "d6");
    aka!("datefmt_alt2", "datefmt");
    aka!("date_today_alt2", "date_today");
    aka!("date_tomorrow_alt2", "date_tomorrow");
    aka!("date_yesterday_alt2", "date_yesterday");
    aka!("day_alt2", "day");
    aka!("dayname_alt2", "dayname");
    aka!("dayofyear_alt2", "dayofyear");
    aka!("days_in_month_alt2", "days_in_month");
    aka!("days_in_year_alt2", "days_in_year");
    aka!("db_begin_alt2", "db_begin");
    aka!("db_close_alt2", "db_close");
    aka!("db_commit_alt2", "db_commit");
    aka!("db_count_alt2", "db_count");
    aka!("db_exec_alt2", "db_exec");
    aka!("db_exists_alt2", "db_exists");
    aka!("db_insert_alt2", "db_insert");
    aka!("db_open_alt2", "db_open");
    aka!("db_query_alt2", "db_query");
    aka!("db_rollback_alt2", "db_rollback");
    aka!("db_tables_alt2", "db_tables");
    aka!("dclear_alt2", "dclear");
    aka!("dcount_value_alt2", "dcount_value");
    aka!("ddel_alt2", "ddel");
    aka!("decr_alt2", "decr");
    aka!("deg_to_rad_alt2", "deg_to_rad");
    aka!("delete_alt2", "delete");
    aka!("dget_alt2", "dget");
    aka!("dhas_alt2", "dhas");
    aka!("dict_alt2", "dict");
    aka!("diff_days_alt2", "diff_days");
    aka!("dincr_alt2", "dincr");
    aka!("dinvert_alt2", "dinvert");
    aka!("dir_exists_alt2", "dir_exists");
    aka!("dirname_alt2", "dirname");
    aka!("distance_alt2", "distance");
    aka!("divider_alt2", "divider");
    aka!("dkeys_alt2", "dkeys");
    aka!("dmerge_alt2", "dmerge");
    aka!("docs_alt2", "docs");
    aka!("domit_alt2", "domit");
    aka!("download_alt2", "download");
    aka!("dpairs_alt2", "dpairs");
    aka!("dpick_alt2", "dpick");
    aka!("dpop_alt2", "dpop");
    aka!("dprint_alt2", "dprint");
    aka!("dset_alt2", "dset");
    aka!("dsize_alt2", "dsize");
    aka!("dvalues_alt2", "dvalues");
    aka!("e_alt2", "e");
    aka!("echo_alt2", "echo");
    aka!("endswith_alt2", "endswith");
    aka!("ensure_dir_alt2", "ensure_dir");
    aka!("enum_alt2", "enum");
    aka!("env_dict_alt2", "env_dict");
    aka!("env_list_alt2", "env_list");
    aka!("env_size_alt2", "env_size");
    aka!("exec_alt2", "exec");
    aka!("exists_alt2", "exists");
    aka!("extname_alt2", "extname");
    aka!("factorial_alt2", "factorial");
    aka!("ffi_alt2", "ffi");
    aka!("fficall_alt2", "fficall");
    aka!("ffiload_alt2", "ffiload");
    aka!("fibonacci_alt2", "fibonacci");
    aka!("field_alt2", "field");
    aka!("file_age_alt2", "file_age");
    aka!("file_count_in_dir_alt2", "file_count_in_dir");
    aka!("file_empty_alt2", "file_empty");
    aka!("file_ext_alt2", "file_ext");
    aka!("file_grep_alt2", "file_grep");
    aka!("file_hash_alt2", "file_hash");
    aka!("file_head_alt2", "file_head");
    aka!("file_lines_count_alt2", "file_lines_count");
    aka!("file_mtime_alt2", "file_mtime");
    aka!("file_replace_alt2", "file_replace");
    aka!("file_size_alt2", "file_size");
    aka!("file_size_human_alt2", "file_size_human");
    aka!("file_stem_alt2", "file_stem");
    aka!("file_tail_alt2", "file_tail");
    aka!("file_words_count_alt2", "file_words_count");
    aka!("file_writable_alt2", "file_writable");
    aka!("find_files_alt2", "find_files");
    aka!("find_index_alt2", "find_index");
    aka!("first_alt2", "first");
    aka!("first_word_alt2", "first_word");
    aka!("floor_alt2", "floor");
    aka!("fmax_alt2", "fmax");
    aka!("fmin_alt2", "fmin");
    aka!("foreach_alt2", "foreach");
    aka!("format_alt2", "format");
    aka!("format_bytes_alt2", "format_bytes");
    aka!("format_duration_alt2", "format_duration");
    aka!("format_number_alt2", "format_number");
    aka!("form_encode_alt2", "form_encode");
    aka!("from_bin_alt2", "from_bin");
    aka!("from_hex_alt2", "from_hex");
    aka!("from_unix_alt2", "from_unix");
    aka!("func_alt2", "func");
    aka!("gcd_alt2", "gcd");
    aka!("gcd3_alt2", "gcd3");
    aka!("get_alt2", "get");
    aka!("getenv_alt2", "getenv");
    aka!("getf_alt2", "getf");
    aka!("gethome_alt2", "gethome");
    aka!("getuser_alt2", "getuser");
    aka!("gotoxy_alt2", "gotoxy");
    aka!("gui_alpha_pixel_alt2", "gui_alpha_pixel");
    aka!("gui_blit_ppm_alt2", "gui_blit_ppm");
    aka!("gui_circle_alt2", "gui_circle");
    aka!("gui_clear_alt2", "gui_clear");
    aka!("gui_clear_rect_alt2", "gui_clear_rect");
    aka!("gui_ellipse_alt2", "gui_ellipse");
    aka!("gui_fill_circle_alt2", "gui_fill_circle");
    aka!("gui_fill_rect_alt2", "gui_fill_rect");
    aka!("gui_fill_triangle_alt2", "gui_fill_triangle");
    aka!("gui_fps_alt2", "gui_fps");
    aka!("gui_get_pixel_alt2", "gui_get_pixel");
    aka!("gui_gradient_rect_alt2", "gui_gradient_rect");
    aka!("gui_is_focused_alt2", "gui_is_focused");
    aka!("gui_key_down_alt2", "gui_key_down");
    aka!("gui_line_alt2", "gui_line");
    aka!("gui_mouse_down_alt2", "gui_mouse_down");
    aka!("gui_mouse_wheel_alt2", "gui_mouse_wheel");
    aka!("gui_mouse_x_alt2", "gui_mouse_x");
    aka!("gui_mouse_y_alt2", "gui_mouse_y");
    aka!("gui_native_alt2", "gui_native");
    aka!("gui_open_alt2", "gui_open");
    aka!("gui_pixel_alt2", "gui_pixel");
    aka!("gui_polygon_alt2", "gui_polygon");
    aka!("gui_rect_alt2", "gui_rect");
    aka!("gui_screenshot_alt2", "gui_screenshot");
    aka!("gui_set_title_alt2", "gui_set_title");
    aka!("gui_show_alt2", "gui_show");
    aka!("gui_text_alt2", "gui_text");
    aka!("gui_text_big_alt2", "gui_text_big");
    aka!("gui_text_width_alt2", "gui_text_width");
    aka!("gui_thick_line_alt2", "gui_thick_line");
    aka!("gui_window_alt2", "gui_window");
    aka!("gui_window_h_alt2", "gui_window_h");
    aka!("gui_window_w_alt2", "gui_window_w");
    aka!("hamming_distance_alt2", "hamming_distance");
    aka!("has_var_alt2", "has_var");
    aka!("hex_decode_alt2", "hex_decode");
    aka!("hex_encode_alt2", "hex_encode");
    aka!("hmac_sha256_alt2", "hmac_sha256");
    aka!("hostname_alt2", "hostname");
    aka!("hour_now_alt2", "hour_now");
    aka!("hr_alt2", "hr");
    aka!("html_escape_alt2", "html_escape");
    aka!("http_delete_alt2", "http_delete");
    aka!("http_get_alt2", "http_get");
    aka!("http_post_alt2", "http_post");
    aka!("http_put_alt2", "http_put");
    aka!("hypot_alt2", "hypot");
    aka!("if_alt2", "if");
    aka!("implements_alt2", "implements");
    aka!("importayaan_alt2", "importayaan");
    aka!("importpkg_alt2", "importpkg");
    aka!("incr_alt2", "incr");
    aka!("inspect_alt2", "inspect");
    aka!("instanceof_alt2", "instanceof");
    aka!("interface_alt2", "interface");
    aka!("int_to_ip_alt2", "int_to_ip");
    aka!("ip_to_int_alt2", "ip_to_int");
    aka!("ip_v4_check_alt2", "ip_v4_check");
    aka!("iqr_alt2", "iqr");
    aka!("is_alnum_alt2", "is_alnum");
    aka!("is_alpha_alt2", "is_alpha");
    aka!("is_anagram_alt2", "is_anagram");
    aka!("is_ascii_alt2", "is_ascii");
    aka!("is_digit_alt2", "is_digit");
    aka!("is_dir_alt2", "is_dir");
    aka!("is_even_alt2", "is_even");
    aka!("is_file_alt2", "is_file");
    aka!("is_leap_year_alt2", "is_leap_year");
    aka!("is_lower_alt2", "is_lower");
    aka!("is_odd_alt2", "is_odd");
    aka!("is_palindrome_alt2", "is_palindrome");
    aka!("is_prime_alt2", "is_prime");
    aka!("is_root_alt2", "is_root");
    aka!("is_today_alt2", "is_today");
    aka!("is_upper_alt2", "is_upper");
    aka!("is_weekend_alt2", "is_weekend");
    aka!("is_whitespace_alt2", "is_whitespace");
    aka!("jaccard_alt2", "jaccard");
    aka!("joinpath_alt2", "joinpath");
    aka!("jscall_alt2", "jscall");
    aka!("json_alt2", "json");
    aka!("json_escape_str_alt2", "json_escape_str");
    aka!("json_get_path_alt2", "json_get_path");
    aka!("json_parse_alt2", "json_parse");
    aka!("json_pretty_alt2", "json_pretty");
    aka!("json_stringify_alt2", "json_stringify");
    aka!("lall_neg_alt2", "lall_neg");
    aka!("lall_pos_alt2", "lall_pos");
    aka!("lall_zero_alt2", "lall_zero");
    aka!("lambda_alt2", "lambda");




    if let Some(rest) = line.strip_prefix("lerp ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let var = parts[0].trim().to_string();
            let args = split_args(parts[1]);
            if args.len() == 3 {
                let a: f64 = resolve_arg(&args[0], vars, oop).parse().unwrap_or(0.0);
                let b: f64 = resolve_arg(&args[1], vars, oop).parse().unwrap_or(0.0);
                let t: f64 = resolve_arg(&args[2], vars, oop).parse().unwrap_or(0.0);
                oop.string_vars.insert(var, (a + (b - a) * t).to_string());
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ffi ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let name = parts[0].trim().to_string();
            let cmd = interpolate(strip_outer_quotes(parts[1].trim()), vars, oop);
            match Command::new("sh").arg("-c").arg(&cmd).output() {
                Ok(out) => {
                    let s = String::from_utf8_lossy(&out.stdout).trim_end().to_string();
                    oop.string_vars.insert(name, s);
                }
                Err(e) => println!("ffi failed: {}", e),
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("pycall ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let name = parts[0].trim().to_string();
            let code = interpolate(strip_outer_quotes(parts[1].trim()), vars, oop);
            let wrapped = format!("print({})", code);
            match Command::new("python3").arg("-c").arg(&wrapped).output() {
                Ok(out) if out.status.success() => {
                    let s = String::from_utf8_lossy(&out.stdout).trim_end().to_string();
                    oop.string_vars.insert(name, s);
                }
                Ok(out) => {
                    let err = String::from_utf8_lossy(&out.stderr);
                    println!("pycall failed: {}", err.trim());
                }
                Err(e) => println!("pycall failed: {}", e),
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("jscall ") {
        let parts: Vec<&str> = rest.splitn(2, '=').collect();
        if parts.len() == 2 {
            let name = parts[0].trim().to_string();
            let code = interpolate(strip_outer_quotes(parts[1].trim()), vars, oop);
            let wrapped = format!("console.log({})", code);
            match Command::new("node").arg("-e").arg(&wrapped).output() {
                Ok(out) if out.status.success() => {
                    let s = String::from_utf8_lossy(&out.stdout).trim_end().to_string();
                    oop.string_vars.insert(name, s);
                }
                Ok(out) => {
                    let err = String::from_utf8_lossy(&out.stderr);
                    println!("jscall failed: {}", err.trim());
                }
                Err(e) => println!("jscall failed: {}", e),
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("ffiload ") {
        let mut split = rest.splitn(2, char::is_whitespace);
        let alias = split.next().unwrap_or("").trim().to_string();
        let path_part = split.next().unwrap_or("");
        let path = interpolate(strip_outer_quotes(path_part.trim()), vars, oop);

        if alias.is_empty() || path.is_empty() {
            println!("ffiload syntax: ffiload <alias> \"path\"");
            return true;
        }

        unsafe {
            match libloading::Library::new(&path) {
                Ok(lib) => {
                    oop.loaded_libs.insert(alias, lib);
                }
                Err(e) => println!("ffiload failed: {}", e),
            }
        }
        return true;
    }

    if let Some(rest) = line.strip_prefix("fficall ") {
        let split: Vec<&str> = rest.splitn(2, "->").collect();
        if split.len() != 2 {
            println!("fficall syntax: fficall alias.func args... -> result");
            return true;
        }
        let result_var = split[1].trim().to_string();
        let call_part = split[0].trim();

        let mut tokens = call_part.split_whitespace();
        let target = tokens.next().unwrap_or("");
        let mut dot = target.splitn(2, '.');
        let alias = dot.next().unwrap_or("").to_string();
        let funcname = dot.next().unwrap_or("").to_string();

        if alias.is_empty() || funcname.is_empty() {
            println!("fficall syntax: fficall alias.func args... -> result");
            return true;
        }

        let args: Vec<i64> = tokens
            .map(|s| {
                if let Ok(n) = s.parse::<i64>() {
                    n
                } else if let Some(v) = vars.get(s) {
                    *v
                } else {
                    0
                }
            })
            .collect();

        let lib = match oop.loaded_libs.get(&alias) {
            Some(l) => l,
            None => {
                println!("fficall: library '{}' not loaded", alias);
                return true;
            }
        };

        unsafe {
            let sym_name = funcname.as_bytes();
            let res: Result<i64, libloading::Error> = match args.len() {
                0 => lib
                    .get::<unsafe extern "C" fn() -> i64>(sym_name)
                    .map(|f| f()),
                1 => lib
                    .get::<unsafe extern "C" fn(i64) -> i64>(sym_name)
                    .map(|f| f(args[0])),
                2 => lib
                    .get::<unsafe extern "C" fn(i64, i64) -> i64>(sym_name)
                    .map(|f| f(args[0], args[1])),
                3 => lib
                    .get::<unsafe extern "C" fn(i64, i64, i64) -> i64>(sym_name)
                    .map(|f| f(args[0], args[1], args[2])),
                4 => lib
                    .get::<unsafe extern "C" fn(i64, i64, i64, i64) -> i64>(sym_name)
                    .map(|f| f(args[0], args[1], args[2], args[3])),
                _ => {
                    println!("fficall: max 4 args supported");
                    return true;
                }
            };

            match res {
                Ok(r) => {
                    vars.insert(result_var, r);
                }
                Err(e) => println!("fficall: {}", e),
            }
        }

        return true;
    }

    if let Some(args) = line.strip_prefix("writefile ") {
        let mut parts = args.split('"').filter(|s| !s.trim().is_empty());

        if let (Some(filename), Some(content)) = (parts.next(), parts.next()) {
            let fname = interpolate(strip_outer_quotes(filename.trim()), vars, oop);
            let body = interpolate(content, vars, oop);
            let path = expand_path(&fname);
            match fs::write(&path, body) {
                Ok(_) => println!("File written: {}", path.display()),
                Err(e) => println!("Write failed: {}", e),
            }
        } else {
            println!("Invalid writefile syntax.");
        }

        return true;
    }

    if let Some(args) = line.strip_prefix("readfile ") {
        let mut split = args.split_whitespace();
        if let Some(var_name) = split.next() {
            let mut parts = args.split('"').filter(|s| !s.trim().is_empty());
            parts.next();

            if let Some(filename) = parts.next() {
                let fname = interpolate(strip_outer_quotes(filename.trim()), vars, oop);
                let path = expand_path(&fname);
                match fs::read_to_string(&path) {
                    Ok(data) => {
                        println!("{}", data);
                        vars.insert(var_name.into(), data.len() as i64);
                    }
                    Err(e) => println!("Read failed: {}", e),
                }
            } else {
                println!("Invalid readfile syntax.");
            }
        }
        return true;
    }

    if line.starts_with("serport =") {
        let port = line[9..].trim().parse().unwrap_or(3000);

        *server_cfg = Some(ServerConfig {
            port,
            default_body: Vec::new(),
            default_content_type: "text/html; charset=utf-8".into(),
            static_dir: None,
            routes: HashMap::new(),
            dynamic_routes: Vec::new(),
            current_route: None,
            capturing_route_body: None,
        });

        return true;
    }

    if let Some(cfg) = server_cfg.as_mut() {
        if line == "beginroute" {
            cfg.capturing_route_body = Some(Vec::new());
            return true;
        }

        if let Some(path_part) = line.strip_prefix("static ") {
            if let Some(dir) = first_quoted(path_part) {
                cfg.static_dir = Some(expand_path(&interpolate(&dir, vars, oop)));
            } else {
                cfg.static_dir =
                    Some(expand_path(&interpolate(strip_outer_quotes(path_part.trim()), vars, oop)));
            }
            return true;
        }

        if let Some(p) = line.strip_prefix("route ") {
            if let Some(path) = first_quoted(p) {
                cfg.current_route = Some(("GET".into(), interpolate(&path, vars, oop)));
            }
            return true;
        }

        if let Some(p) = line.strip_prefix("get ") {
            if let Some(path) = first_quoted(p) {
                cfg.current_route = Some(("GET".into(), interpolate(&path, vars, oop)));
            }
            return true;
        }

        if let Some(p) = line.strip_prefix("post ") {
            if let Some(path) = first_quoted(p) {
                cfg.current_route = Some(("POST".into(), interpolate(&path, vars, oop)));
            }
            return true;
        }

        if let Some(p) = line.strip_prefix("put ") {
            if let Some(path) = first_quoted(p) {
                cfg.current_route = Some(("PUT".into(), interpolate(&path, vars, oop)));
            }
            return true;
        }

        if let Some(p) = line.strip_prefix("delete ") {
            if let Some(path) = first_quoted(p) {
                cfg.current_route = Some(("DELETE".into(), interpolate(&path, vars, oop)));
            }
            return true;
        }

        if let Some(t) = line.strip_prefix("serve ") {
            let body = interpolate(strip_outer_quotes(t), vars, oop);

            if let Some((m, p)) = cfg.current_route.clone() {
                cfg.routes.insert((m, p), RouteResponse::text(body));
            } else {
                cfg.default_body = body.into_bytes();
                cfg.default_content_type = "text/html; charset=utf-8".into();
            }

            return true;
        }

        if let Some(t) = line.strip_prefix("servefile ") {
            let raw = interpolate(strip_outer_quotes(t), vars, oop);
            let file = expand_path(&raw);
            let data = fs::read(&file).unwrap_or_default();
            let mime = guess_mime(&file);

            if let Some((m, p)) = cfg.current_route.clone() {
                cfg.routes.insert(
                    (m, p),
                    RouteResponse {
                        kind: RouteKind::Text,
                        status_code: 200,
                        body: data,
                        content_type: Some(mime),
                        location: None,
                    },
                );
            } else {
                cfg.default_body = data;
                cfg.default_content_type = mime;
            }

            return true;
        }

        if let Some(j) = line.strip_prefix("json ") {
            let body = interpolate(strip_outer_quotes(j.trim()), vars, oop);

            if let Some((m, p)) = cfg.current_route.clone() {
                cfg.routes.insert((m, p), RouteResponse::json(body));
            } else {
                cfg.default_body = body.into_bytes();
                cfg.default_content_type = "application/json; charset=utf-8".into();
            }

            return true;
        }

        if let Some(r) = line.strip_prefix("redirect ") {
            let to = interpolate(strip_outer_quotes(r), vars, oop);

            if let Some((m, p)) = cfg.current_route.clone() {
                cfg.routes.insert((m, p), RouteResponse::redirect(to));
            } else {
                cfg.routes
                    .insert(("GET".into(), "/".into()), RouteResponse::redirect(to));
            }

            return true;
        }

        if line == "end" {
            let cfg_take = server_cfg.take().unwrap();
            run_server_blocking(cfg_take, vars, oop);
            return true;
        }
    }

    // Unified `import` — accepts BOTH packages (bare name, no extension)
    // and ayaan files (path or name ending in .ayaan). `importpkg` is kept
    // as a strict alias for the package case.
    let is_strict_pkg = line.starts_with("importpkg ");
    let import_line = line.strip_prefix("import ").or_else(|| line.strip_prefix("importpkg "));
    if let Some(arg_raw) = import_line {
        let mut arg = arg_raw.trim().to_string();
        // strip surrounding quotes if user wrote   import "file.ayaan"
        if arg.starts_with('"') && arg.ends_with('"') && arg.len() >= 2 {
            arg = arg[1..arg.len() - 1].to_string();
        }

        // File-style imports are detected by extension or path separators.
        let looks_like_file = !is_strict_pkg
            && (arg.ends_with(".ayaan") || arg.contains('/') || arg.contains('\\'));

        if looks_like_file {
            // Delegate to the existing importayaan logic:
            // resolve path relative to the script's directory and source it.
            if let Some(bundle) = oop.bundle_stack.last() {
                if let Some(content) = bundle.files.get(&arg).cloned() {
                    if !run_script_content(&content, PathBuf::from("."), vars, server_cfg, oop) {
                        return false;
                    }
                    return true;
                }
            }
            let resolved = resolve_import_path(&arg, &oop.script_dir_stack);
            if !run_script_file(&resolved, vars, server_cfg, oop) {
                return false;
            }
            return true;
        }

        // Otherwise — package import.
        let pkg_name = arg.as_str();
        let pkg_dir = package_dir().join(pkg_name);
        let cfg_path = pkg_dir.join("package.aspkg");
        let single = package_dir().join(format!("{}.aspkg", pkg_name));

        let parse_meta = |text: &str| -> std::collections::HashMap<String, String> {
            let mut meta: std::collections::HashMap<String, String> = std::collections::HashMap::new();
            let mut current: Option<String> = None;
            for cfg_line in text.lines() {
                let t = cfg_line.trim();
                if t.eq_ignore_ascii_case("---code---") || t.starts_with("---file:") {
                    break;
                }
                if let Some(rest) = t.strip_prefix('@') {
                    let (k, v) = if let Some((k, v)) = rest.split_once(' ') {
                        (k.trim().to_lowercase(), v.trim().to_string())
                    } else {
                        (rest.trim().to_lowercase(), String::new())
                    };
                    meta.insert(k.clone(), v);
                    current = Some(k);
                } else if t.is_empty() {
                    current = None;
                } else if let Some(ref k) = current {
                    if let Some(existing) = meta.get_mut(k) {
                        if !existing.is_empty() { existing.push('\n'); }
                        existing.push_str(cfg_line);
                    }
                }
            }
            meta
        };

        let mut loaded_meta: Option<std::collections::HashMap<String, String>> = None;
        if cfg_path.exists() {
            let cfg = fs::read_to_string(&cfg_path).unwrap_or_default();
            let meta = parse_meta(&cfg);
            let main_file = meta.get("main").cloned().unwrap_or_else(|| "main.ayaan".to_string());
            let entry = pkg_dir.join(&main_file);
            if entry.exists() {
                if !run_script_file(&entry, vars, server_cfg, oop) {
                    return false;
                }
                loaded_meta = Some(meta);
            } else {
                println!(
                    "ASPkg: main file '{}' not found for '{}'",
                    main_file, pkg_name
                );
            }
        } else if single.exists() {
            if !run_script_file(&single, vars, server_cfg, oop) {
                return false;
            }
            let txt = fs::read_to_string(&single).unwrap_or_default();
            loaded_meta = Some(parse_meta(&txt));
        } else {
            println!("ASPkg '{}' not installed.", pkg_name);
            return true;
        }

        // Show @help as a YELLOW WARNING block whenever the package is imported.
        // Author requirement: every package MUST ship a non-empty @help; we still
        // run the script if it's missing but warn loudly.
        if let Some(meta) = loaded_meta {
            let version = meta.get("version").cloned().unwrap_or_else(|| "?".into());
            match meta.get("help") {
                Some(h) if !h.is_empty() => {
                    println!("\x1b[33m⚠ \x1b[1m{}\x1b[0m\x1b[33m v{} — @help:\x1b[0m", pkg_name, version);
                    for hline in h.lines() {
                        println!("\x1b[33m│\x1b[0m {}", hline);
                    }
                }
                _ => {
                    println!("\x1b[31m⚠ ERROR:\x1b[0m package '{}' is missing the required @help directive.", pkg_name);
                    println!("  Every package MUST document its commands. Continuing anyway...");
                }
            }
        }

        return true;
    }

    if let Some(rest) = line.strip_prefix("importayaan ") {
        let raw = interpolate(strip_outer_quotes(rest.trim()), vars, oop);

        if let Some(bundle) = oop.bundle_stack.last() {
            if let Some(content) = bundle.files.get(&raw).cloned() {
                if !run_script_content(&content, PathBuf::from("."), vars, server_cfg, oop) {
                    return false;
                }
                return true;
            }
        }

        let resolved = resolve_import_path(&raw, &oop.script_dir_stack);
        if !run_script_file(&resolved, vars, server_cfg, oop) {
            return false;
        }
        return true;
    }

    if line == "help" || line == "?" || line == "commands" {
        print_command_help();
        return true;
    }

    let first_word = line.split_whitespace().next().unwrap_or("");
    let suggestion: Option<&'static str> = match find_similar(first_word) {
        Some(s) if s != first_word => Some(s),
        _ => None,
    };
    print_source_error(
        oop,
        line,
        &format!("unknown command '{}'", first_word),
        first_word,
        suggestion,
    );
    true
}

// Modern compiler-style error: red banner, file:line:col, source-line with a
// caret pointing at the bad token, and an optional "did you mean" suggestion.
//
// Falls back gracefully when running in the REPL (no file path / line no).
fn print_source_error(
    oop: &OopState,
    line: &str,
    msg: &str,
    bad_token: &str,
    suggestion: Option<&str>,
) {
    let red = "\x1b[31m";
    let dim = "\x1b[2m";
    let blue = "\x1b[34m";
    let yellow = "\x1b[33m";
    let green = "\x1b[32m";
    let reset = "\x1b[0m";

    // The bad token sits at the first non-whitespace position in `line`.
    let col_offset = line.chars().take_while(|c| c.is_whitespace()).count();
    let token_width = bad_token.chars().count().max(1);
    let line_no = oop.current_line_no;
    let file = oop
        .current_file
        .as_deref()
        .map(|s| s.to_string())
        .unwrap_or_else(|| "<repl>".to_string());

    println!("{}error:{} {}", red, reset, msg);
    if line_no > 0 {
        println!(" {}-->{} {}:{}:{}", blue, reset, file, line_no, col_offset + 1);
    } else {
        println!(" {}-->{} {}", blue, reset, file);
    }

    // The width of the line-number gutter — at least 2 chars so single-digit
    // line numbers line up with the empty "  |" separator rows.
    let gutter_width = std::cmp::max(2, line_no.to_string().len());
    let gutter_blank: String = " ".repeat(gutter_width);

    println!("{} {}|{}", gutter_blank, blue, reset);
    if line_no > 0 {
        println!("{:>w$} {}|{} {}", line_no, blue, reset, line, w = gutter_width);
    } else {
        println!("{} {}|{} {}", gutter_blank, blue, reset, line);
    }
    let caret_padding: String = " ".repeat(col_offset);
    let carets: String = "^".repeat(token_width);
    match suggestion {
        Some(sug) => println!(
            "{} {}|{} {}{}{}{} {}did you mean '{}{}{}'?{}",
            gutter_blank, blue, reset,
            caret_padding, red, carets, reset,
            yellow, green, sug, reset, reset,
        ),
        None => println!(
            "{} {}|{} {}{}{}{}",
            gutter_blank, blue, reset, caret_padding, red, carets, reset,
        ),
    }
    println!("{} {}={} {}note:{} type {}help{} for the full command list",
        gutter_blank, blue, reset, dim, reset, green, reset);

    if !oop.call_trace.is_empty() {
        println!("{}", dim);
        for entry in oop.call_trace.iter().rev() {
            println!("  in {}", entry);
        }
        print!("{}", reset);
    }
}

fn print_repl_banner() {
    let cyan = "\x1b[36m";
    let yellow = "\x1b[1;33m";
    let dim = "\x1b[2m";
    let reset = "\x1b[0m";

    println!();
    println!("{cyan}    █████   █   █  █████   █████   █   █ {reset}");
    println!("{cyan}   ██   ██   █ █  ██   ██ ██   ██  ██  █ {reset}");
    println!("{cyan}   ███████    █   ███████ ███████  █ █ █ {reset}");
    println!("{cyan}   ██   ██    █   ██   ██ ██   ██  █  ██ {reset}");
    println!("{cyan}   ██   ██    █   ██   ██ ██   ██  █   █ {reset}");
    println!();
    println!("   {yellow}▌▌▌  AyaanScript+ REPL  ▐▐▐{reset}    {dim}v{}{reset}", CURRENT_VERSION);
    println!("   {yellow}▛▀▘ ▛▀▖ ▛▀▘ ▛▀▘ ▛▀▘ ▛▀▘  MAJOR RELEASE 2.0  ▘▀▟{reset}");
    println!("   {dim}new: lambdas · match/case · slicing · audio · ranges · self.field{reset}");
    println!();
    println!("   {dim}↑/↓{reset} history   {dim}←/→{reset} edit   {dim}Ctrl-R{reset} search   {dim}Ctrl-C{reset} cancel");
    println!("   Type {yellow}.help{reset} for commands, {yellow}exit{reset} or {dim}Ctrl-D{reset} to quit.");
    println!();
}

fn print_status_strip(vars: &Vars, oop: &OopState, block_label: &str) {
    let dim = "\x1b[2m";
    let yellow = "\x1b[33m";
    let green = "\x1b[32m";
    let reset = "\x1b[0m";

    let block = if block_label.is_empty() {
        format!("{green}ready{reset}")
    } else {
        format!("{yellow}{}{reset}", block_label)
    };

    println!(
        "{dim}── {reset}vars{dim}:{reset}{} {dim}·{reset} strs{dim}:{reset}{} {dim}·{reset} classes{dim}:{reset}{} {dim}·{reset} instances{dim}:{reset}{} {dim}·{reset} {} {dim}──{reset}",
        vars.len(),
        oop.string_vars.len(),
        oop.classes.len(),
        oop.instances.len(),
        block
    );
}

fn current_block_label(oop: &OopState, server_cfg: &Option<ServerConfig>) -> String {
    if let Some(method) = &oop.current_method {
        return format!("class.method {}", method);
    }
    if let Some(c) = &oop.current_class {
        return format!("class {}", c);
    }
    if !oop.repeat_stack.is_empty() {
        return format!("repeat (depth {})", oop.repeat_stack.len());
    }
    if !oop.if_stack.is_empty() {
        return format!("if (depth {})", oop.if_stack.len());
    }
    if server_cfg.is_some() {
        return String::from("server block");
    }
    String::new()
}

fn print_repl_help() {
    let g = "\x1b[32m";
    let d = "\x1b[2m";
    let y = "\x1b[33m";
    let r = "\x1b[0m";

    println!();
    println!("{y}REPL meta-commands{r} (start with a dot):");
    println!("  {g}.help{r}        Show this help");
    println!("  {g}.vars{r}        Show all variables (numeric + string)");
    println!("  {g}.classes{r}     List defined classes with field/method counts");
    println!("  {g}.instances{r}   List instances with their class");
    println!("  {g}.reset{r}       Wipe all state without leaving the REPL");
    println!("  {g}.clear{r}       Clear the screen, redraw banner");
    println!("  {g}.load FILE{r}   Run a .ayaan file in this session");
    println!();
    println!("{y}Editing{r}:");
    println!("  {d}↑/↓{r}     history    {d}←/→{r}    move cursor");
    println!("  {d}Ctrl-R{r}  search     {d}Ctrl-A/E{r} line start/end");
    println!("  {d}Ctrl-C{r}  cancel     {d}Ctrl-D{r}  exit on empty line");
    println!();
    println!("Any other line is AyaanScript+ code.");
    println!("Block constructs ({y}class{r}/{y}repeat{r}/{y}if{r}/{y}server{r}) work across lines.");
    println!("Use {g}exit{r} to quit.");
    println!();
}

fn print_vars(vars: &Vars, oop: &OopState) {
    if vars.is_empty() && oop.string_vars.is_empty() {
        println!("  (no variables yet)");
        return;
    }
    if !vars.is_empty() {
        println!("Numeric vars:");
        let mut keys: Vec<_> = vars.keys().collect();
        keys.sort();
        for k in keys {
            println!("  {} = {}", k, vars[k]);
        }
    }
    if !oop.string_vars.is_empty() {
        println!("String vars:");
        let mut keys: Vec<_> = oop.string_vars.keys().collect();
        keys.sort();
        for k in keys {
            println!("  {} = {:?}", k, oop.string_vars[k]);
        }
    }
}

fn run_repl() {
    use rustyline::error::ReadlineError;
    use rustyline::DefaultEditor;

    let mut rl = match DefaultEditor::new() {
        Ok(r) => r,
        Err(e) => {
            println!("REPL init failed: {} — falling back to plain mode", e);
            run_repl_plain();
            return;
        }
    };

    let mut vars = Vars::new();
    let mut server_cfg: Option<ServerConfig> = None;
    let mut oop = OopState::default();
    let cwd = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
    oop.script_dir_stack.push(cwd);

    print_repl_banner();

    loop {
        let block_label = current_block_label(&oop, &server_cfg);
        print_status_strip(&vars, &oop, &block_label);

        let prompt = if block_label.is_empty() {
            "\x01\x1b[32m\x02>>>\x01\x1b[0m\x02 "
        } else {
            "\x01\x1b[33m\x02...\x01\x1b[0m\x02 "
        };

        match rl.readline(prompt) {
            Ok(input) => {
                if !input.trim().is_empty() {
                    let _ = rl.add_history_entry(input.as_str());
                }
                let line = input.trim();

                if line.is_empty() {
                    continue;
                }

                if line == ".help" || line == ".?" {
                    print_repl_help();
                    continue;
                }
                if line == ".vars" {
                    print_vars(&vars, &oop);
                    continue;
                }
                if line == ".classes" {
                    if oop.classes.is_empty() {
                        println!("  (no classes defined)");
                    } else {
                        let mut keys: Vec<_> = oop.classes.keys().collect();
                        keys.sort();
                        for name in keys {
                            let c = &oop.classes[name];
                            println!(
                                "  \x1b[36m{}\x1b[0m  ({} field{}, {} method{})",
                                name,
                                c.fields.len(),
                                if c.fields.len() == 1 { "" } else { "s" },
                                c.methods.len(),
                                if c.methods.len() == 1 { "" } else { "s" }
                            );
                        }
                    }
                    continue;
                }
                if line == ".instances" {
                    if oop.instances.is_empty() {
                        println!("  (no instances)");
                    } else {
                        let mut keys: Vec<_> = oop.instances.keys().collect();
                        keys.sort();
                        for name in keys {
                            println!(
                                "  \x1b[36m{}\x1b[0m : \x1b[2m{}\x1b[0m",
                                name, oop.instances[name].class_name
                            );
                        }
                    }
                    continue;
                }
                if line == ".reset" {
                    vars.clear();
                    server_cfg = None;
                    oop = OopState::default();
                    oop.script_dir_stack
                        .push(env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
                    println!("\x1b[33mState cleared.\x1b[0m");
                    continue;
                }
                if line == ".clear" || line == ".cls" {
                    print!("\x1b[2J\x1b[1;1H");
                    let _ = io::stdout().flush();
                    print_repl_banner();
                    continue;
                }
                if line == ".load" {
                    println!("\x1b[33mUsage:\x1b[0m .load <path/to/file.ayaan>");
                    continue;
                }
                if let Some(path) = line.strip_prefix(".load ") {
                    let trimmed = path.trim();
                    if trimmed.is_empty() {
                        println!("\x1b[33mUsage:\x1b[0m .load <path/to/file.ayaan>");
                        continue;
                    }
                    let p = expand_path(trimmed);
                    if !p.exists() {
                        println!("\x1b[31mFile not found:\x1b[0m {}", p.display());
                        continue;
                    }
                    println!("\x1b[2mloading {}...\x1b[0m", p.display());
                    run_script_file(&p, &mut vars, &mut server_cfg, &mut oop);
                    continue;
                }

                if !execute(line, &mut vars, &mut server_cfg, &mut oop) {
                    break;
                }
            }
            Err(ReadlineError::Interrupted) => {
                println!("\x1b[2m(Ctrl-C — use 'exit' or Ctrl-D to quit)\x1b[0m");
                continue;
            }
            Err(ReadlineError::Eof) => break,
            Err(e) => {
                println!("Input error: {}", e);
                break;
            }
        }
    }

    println!("\x1b[36mBye!\x1b[0m");
}

fn run_repl_plain() {
    let mut vars = Vars::new();
    let mut server_cfg: Option<ServerConfig> = None;
    let mut oop = OopState::default();
    let cwd = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
    oop.script_dir_stack.push(cwd);

    print_repl_banner();
    loop {
        let block_label = current_block_label(&oop, &server_cfg);
        if block_label.is_empty() {
            print!(">>> ");
        } else {
            print!("... ");
        }
        io::stdout().flush().unwrap();
        let mut input = String::new();
        if io::stdin().read_line(&mut input).unwrap_or(0) == 0 {
            break;
        }
        let line = input.trim_end();
        if !execute(line, &mut vars, &mut server_cfg, &mut oop) {
            break;
        }
    }
}

const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");

// Easter egg: base64-encoded JPEG of Theo the cat. Embedded at compile time
// so it travels inside the binary. The `theothecat` command opens it as a
// pure data: URL — no temp file is written to disk.
const THEOTHECAT_B64: &str = include_str!("theothecat.b64");

fn version_is_newer(latest: &str, current: &str) -> bool {
    fn parse(s: &str) -> Vec<u32> {
        s.split(|c: char| c == '.' || c == '-' || c == '+')
            .filter_map(|p| p.parse::<u32>().ok())
            .collect()
    }
    let a = parse(latest);
    let b = parse(current);
    let n = a.len().max(b.len());
    for i in 0..n {
        let av = *a.get(i).unwrap_or(&0);
        let bv = *b.get(i).unwrap_or(&0);
        if av != bv {
            return av > bv;
        }
    }
    false
}

fn cache_path() -> PathBuf {
    let home = env::var("HOME").unwrap_or_default();
    PathBuf::from(home).join(".cache").join("aspkg").join("version_check.txt")
}

fn check_for_update() {
    let now: u64 = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0);

    let cache = cache_path();
    if let Ok(content) = fs::read_to_string(&cache) {
        let lines: Vec<&str> = content.lines().collect();
        if lines.len() >= 2 {
            let last: u64 = lines[0].parse().unwrap_or(0);
            let latest = lines[1].to_string();
            if now.saturating_sub(last) < 86400 {
                show_upgrade_message(&latest);
                return;
            }
        }
    }

    let body = match reqwest::blocking::Client::builder()
        .timeout(Duration::from_secs(2))
        .build()
        .and_then(|c| c.get("https://crates.io/api/v1/crates/ayaan").send())
        .and_then(|r| r.text())
    {
        Ok(b) => b,
        Err(_) => return,
    };

    let latest = match serde_json::from_str::<serde_json::Value>(&body) {
        Ok(v) => v
            .get("crate")
            .and_then(|c| c.get("max_stable_version"))
            .and_then(|v| v.as_str())
            .map(String::from),
        Err(_) => None,
    };

    if let Some(latest) = latest {
        if let Some(parent) = cache.parent() {
            let _ = fs::create_dir_all(parent);
        }
        let _ = fs::write(&cache, format!("{}\n{}", now, latest));
        show_upgrade_message(&latest);
    }
}

fn show_upgrade_message(latest: &str) {
    if version_is_newer(latest, CURRENT_VERSION) {
        eprintln!(
            "\x1b[33m[ayaan]\x1b[0m A newer version is available: \x1b[36m{} \x1b[2m>>\x1b[0m \x1b[1;32m{}\x1b[0m",
            CURRENT_VERSION, latest
        );
        eprintln!(
            "        Upgrade with: \x1b[1mcargo install ayaan --force\x1b[0m"
        );
    }
}

fn run_script_once(script_path: &Path) {
    let script = match fs::read_to_string(script_path) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("\x1b[31mfailed to read {}: {}\x1b[0m", script_path.display(), e);
            return;
        }
    };
    let mut vars = Vars::new();
    let mut server_cfg: Option<ServerConfig> = None;
    let mut oop = OopState::default();
    let initial_dir = script_path
        .parent()
        .map(|p| p.to_path_buf())
        .unwrap_or_else(|| PathBuf::from("."));
    oop.top_script_path = Some(script_path.to_path_buf());
    oop.current_file = Some(script_path.display().to_string());
    run_top_level(&script, initial_dir, &mut vars, &mut server_cfg, &mut oop);
}

fn run_watch_mode(script_path: &Path) {
    use notify::{Event, RecursiveMode, Watcher};
    println!(
        "\x1b[36m[watch]\x1b[0m running {} on every save (Ctrl-C to stop)",
        script_path.display()
    );
    println!("\x1b[2m─── first run ───\x1b[0m");
    run_script_once(script_path);

    let (tx, rx) = std::sync::mpsc::channel();
    let mut watcher = match notify::recommended_watcher(move |res| {
        let _ = tx.send(res);
    }) {
        Ok(w) => w,
        Err(e) => {
            eprintln!("watch init failed: {}", e);
            return;
        }
    };
    if let Err(e) = watcher.watch(script_path, RecursiveMode::NonRecursive) {
        eprintln!("watch failed: {}", e);
        return;
    }

    let mut last = std::time::Instant::now();
    loop {
        match rx.recv_timeout(Duration::from_millis(500)) {
            Ok(Ok(Event { .. })) => {
                if last.elapsed() < Duration::from_millis(250) {
                    continue;
                }
                last = std::time::Instant::now();
                println!();
                println!("\x1b[36m─── reloaded ───\x1b[0m");
                run_script_once(script_path);
            }
            Ok(Err(_)) | Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => break,
            Err(std::sync::mpsc::RecvTimeoutError::Timeout) => continue,
        }
    }
}

// =============================================================
//  AYAAN ART — built-in pixel art editor for making 3D textures
// =============================================================
//
// Usage:  ayaan art [output.png]
//
// Controls:
//   Left mouse  - paint with selected color
//   Right mouse - erase (paint transparent / background)
//   1-9, 0      - select palette color (numbered)
//   [/]         - decrease / increase brush size
//   C           - clear canvas
//   S           - save to PNG
//   ESC         - quit
fn run_art_editor(out_path: &str) {
    use std::time::Duration;

    let canvas_w: usize = 64;
    let canvas_h: usize = 64;
    let cell_size: usize = 12;          // each canvas pixel = 12 screen pixels
    let palette_height: usize = 60;
    let win_w: usize = canvas_w * cell_size;
    let win_h: usize = canvas_h * cell_size + palette_height;

    // 10-color palette
    let palette: [u32; 10] = [
        0x000000, 0xFFFFFF, 0xFF4444, 0x44FF44,
        0x4488FF, 0xFFDD44, 0xFF44FF, 0x44FFFF,
        0xFFA000, 0x884422,
    ];

    let mut canvas: Vec<u32> = vec![0xFFFFFF; canvas_w * canvas_h]; // start white
    let mut frame: Vec<u32> = vec![0; win_w * win_h];
    let mut brush: i32 = 1;
    let mut color_idx: usize = 0;
    let mut last_mouse: Option<(i32, i32)> = None;

    let mut window = match suppress_stderr(|| minifb::Window::new(
        &format!("AyaanScript+ Art - saves to {}", out_path),
        win_w, win_h,
        minifb::WindowOptions { resize: false, ..Default::default() },
    )) {
        Ok(w) => w,
        Err(e) => { println!("art: failed to open window: {}", e); return; }
    };
    window.set_target_fps(60);

    println!("ayaan art - canvas {}x{} - saving to {}", canvas_w, canvas_h, out_path);
    println!("  LMB paint | RMB erase | 1-9,0 colors | [/] brush | C clear | S save | ESC quit");

    while window.is_open() && !window.is_key_down(minifb::Key::Escape) {
        // ---- input ----
        if let Some((mx, my)) = window.get_mouse_pos(minifb::MouseMode::Discard) {
            let mx_i = mx as i32;
            let my_i = my as i32;
            // canvas hit test (top section)
            if my_i >= 0 && (my_i as usize) < canvas_h * cell_size {
                let cx = (mx_i as usize) / cell_size;
                let cy = (my_i as usize) / cell_size;
                if cx < canvas_w && cy < canvas_h {
                    let lmb = window.get_mouse_down(minifb::MouseButton::Left);
                    let rmb = window.get_mouse_down(minifb::MouseButton::Right);
                    if lmb || rmb {
                        let color = if rmb { 0xFFFFFF } else { palette[color_idx] };
                        let r = brush.max(1);
                        // brush as a disk in canvas coords
                        let cxi = cx as i32;
                        let cyi = cy as i32;
                        for dy in -r..=r {
                            for dx in -r..=r {
                                if dx*dx + dy*dy <= r*r {
                                    let nx = cxi + dx;
                                    let ny = cyi + dy;
                                    if nx >= 0 && ny >= 0
                                        && (nx as usize) < canvas_w
                                        && (ny as usize) < canvas_h {
                                        canvas[ny as usize * canvas_w + nx as usize] = color;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            // palette hit test (bottom section): 10 swatches across
            if my_i >= (canvas_h * cell_size) as i32 {
                if window.get_mouse_down(minifb::MouseButton::Left) {
                    let swatch_w = win_w / 10;
                    let idx = (mx_i as usize / swatch_w).min(9);
                    color_idx = idx;
                }
            }
            last_mouse = Some((mx_i, my_i));
        }

        // number keys 1-9 (Key1..Key9) and 0 (Key0)
        let num_keys = [
            (minifb::Key::Key1, 0), (minifb::Key::Key2, 1), (minifb::Key::Key3, 2),
            (minifb::Key::Key4, 3), (minifb::Key::Key5, 4), (minifb::Key::Key6, 5),
            (minifb::Key::Key7, 6), (minifb::Key::Key8, 7), (minifb::Key::Key9, 8),
            (minifb::Key::Key0, 9),
        ];
        for (k, idx) in num_keys.iter() {
            if window.is_key_pressed(*k, minifb::KeyRepeat::No) { color_idx = *idx; }
        }
        if window.is_key_pressed(minifb::Key::LeftBracket, minifb::KeyRepeat::No) {
            brush = (brush - 1).max(0);
        }
        if window.is_key_pressed(minifb::Key::RightBracket, minifb::KeyRepeat::No) {
            brush = (brush + 1).min(8);
        }
        if window.is_key_pressed(minifb::Key::C, minifb::KeyRepeat::No) {
            for p in canvas.iter_mut() { *p = 0xFFFFFF; }
        }
        if window.is_key_pressed(minifb::Key::S, minifb::KeyRepeat::No) {
            match save_canvas_png(&canvas, canvas_w, canvas_h, out_path) {
                Ok(_) => println!("\x1b[36m[art]\x1b[0m saved {} ({}x{})", out_path, canvas_w, canvas_h),
                Err(e) => println!("\x1b[31m[art]\x1b[0m save failed: {}", e),
            }
        }

        // ---- render ----
        // canvas — each pixel is cell_size × cell_size
        for cy in 0..canvas_h {
            for cx in 0..canvas_w {
                let color = canvas[cy * canvas_w + cx];
                for dy in 0..cell_size {
                    for dx in 0..cell_size {
                        let sx = cx * cell_size + dx;
                        let sy = cy * cell_size + dy;
                        if sx < win_w && sy < win_h {
                            frame[sy * win_w + sx] = color;
                        }
                    }
                }
            }
        }
        // light grid every 8 cells
        for gy in 0..canvas_h {
            for gx in 0..canvas_w {
                if gx % 8 == 0 || gy % 8 == 0 {
                    let sx = gx * cell_size;
                    let sy = gy * cell_size;
                    if sx < win_w && sy < win_h {
                        let idx = sy * win_w + sx;
                        let c = frame[idx];
                        // darken slightly
                        let r = ((c >> 16) & 0xFF) * 3 / 4;
                        let g = ((c >> 8) & 0xFF) * 3 / 4;
                        let b = (c & 0xFF) * 3 / 4;
                        frame[idx] = (r << 16) | (g << 8) | b;
                    }
                }
            }
        }
        // palette strip
        let palette_y = canvas_h * cell_size;
        let swatch_w = win_w / 10;
        for i in 0..10 {
            let color = palette[i];
            let sel = i == color_idx;
            for y in palette_y..win_h {
                for x in 0..swatch_w {
                    let sx = i * swatch_w + x;
                    if sx < win_w {
                        let border = sel && (y == palette_y || y == win_h - 1
                            || x == 0 || x == swatch_w - 1
                            || y == palette_y + 1 || y == win_h - 2
                            || x == 1 || x == swatch_w - 2);
                        frame[y * win_w + sx] = if border { 0x00FFFF } else { color };
                    }
                }
            }
        }
        // brush size indicator: small disc in lower-left corner
        let r = brush as i32;
        for dy in -r..=r {
            for dx in -r..=r {
                if dx*dx + dy*dy <= r*r {
                    let sx = 8 + dx as i64;
                    let sy = (win_h - 10) as i64 + dy as i64;
                    if sx >= 0 && sy >= 0 && (sx as usize) < win_w && (sy as usize) < win_h {
                        frame[sy as usize * win_w + sx as usize] = 0xFF00FF;
                    }
                }
            }
        }

        let _ = window.update_with_buffer(&frame, win_w, win_h);
        let _ = last_mouse;
        std::thread::sleep(Duration::from_millis(5));
    }

    // final auto-save on quit
    let _ = save_canvas_png(&canvas, canvas_w, canvas_h, out_path);
    println!("\x1b[36m[art]\x1b[0m saved to {} on exit", out_path);
}

fn save_canvas_png(canvas: &[u32], w: usize, h: usize, path: &str) -> std::io::Result<()> {
    let file = std::fs::File::create(path)?;
    let mut writer = std::io::BufWriter::new(file);
    let mut encoder = png::Encoder::new(&mut writer, w as u32, h as u32);
    encoder.set_color(png::ColorType::Rgb);
    encoder.set_depth(png::BitDepth::Eight);
    let mut png_writer = encoder.write_header()
        .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
    let mut bytes = Vec::with_capacity(w * h * 3);
    for &p in canvas {
        bytes.push(((p >> 16) & 0xFF) as u8);
        bytes.push(((p >> 8) & 0xFF) as u8);
        bytes.push((p & 0xFF) as u8);
    }
    png_writer.write_image_data(&bytes)
        .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
    Ok(())
}

// Enable ANSI escape sequences on Windows by setting
// ENABLE_VIRTUAL_TERMINAL_PROCESSING on the stdout console mode. Windows 10+
// supports this; older Windows just prints the escapes as garbage. No-op on
// Unix where ANSI works natively.
#[cfg(windows)]
fn enable_ansi_on_windows() {
    extern "system" {
        fn GetStdHandle(handle: u32) -> *mut std::ffi::c_void;
        fn GetConsoleMode(handle: *mut std::ffi::c_void, mode: *mut u32) -> i32;
        fn SetConsoleMode(handle: *mut std::ffi::c_void, mode: u32) -> i32;
    }
    const STD_OUTPUT_HANDLE: u32 = 0xfffffff5; // (DWORD)-11
    const STD_ERROR_HANDLE: u32 = 0xfffffff4;  // (DWORD)-12
    const ENABLE_VT: u32 = 0x0004;
    unsafe {
        for h_id in [STD_OUTPUT_HANDLE, STD_ERROR_HANDLE] {
            let h = GetStdHandle(h_id);
            if !h.is_null() {
                let mut mode = 0u32;
                if GetConsoleMode(h, &mut mode) != 0 {
                    SetConsoleMode(h, mode | ENABLE_VT);
                }
            }
        }
    }
}
#[cfg(not(windows))]
fn enable_ansi_on_windows() {}

// Marker file that lives next to package_dir so we know we've shown the
// tutorial. Stored in the same XDG/AppData area as the packages.
fn first_run_marker() -> PathBuf {
    package_dir()
        .parent()
        .map(|p| p.to_path_buf())
        .unwrap_or_else(|| PathBuf::from("."))
        .join(".first_run_done")
}

fn run_tutorial(is_first_run: bool) {
    use std::io::{stdin, stdout, Write};
    let pause = || {
        print!("\n\x1b[2m  ↵ Press Enter to continue (or Ctrl+C to skip)...\x1b[0m");
        let _ = stdout().flush();
        let mut s = String::new();
        let _ = stdin().read_line(&mut s);
    };

    println!();
    println!("\x1b[36m╔══════════════════════════════════════════════════════════════════╗\x1b[0m");
    println!("\x1b[36m║\x1b[0m  \x1b[1mWelcome to AyaanScript+ v{}!\x1b[0m                            \x1b[36m║\x1b[0m", CURRENT_VERSION);
    println!("\x1b[36m║\x1b[0m  Classes, FFI, GUI, 2D + 3D engines, tests, and packages.       \x1b[36m║\x1b[0m");
    println!("\x1b[36m╚══════════════════════════════════════════════════════════════════╝\x1b[0m");
    println!();
    if is_first_run {
        println!("This is your first time running ayaan. Let's take a quick tour.");
        println!("(This tutorial only shows once. Re-run with \x1b[36mayaan help\x1b[0m at any time.)");
    } else {
        println!("AyaanScript+ tutorial — a tour of the whole language.");
    }
    pause();

    println!();
    println!("\x1b[33m1.  Printing + variables\x1b[0m");
    println!();
    println!("    \x1b[36mpsyska -/ \"Hello, world!\"\x1b[0m");
    println!();
    println!("    \x1b[2m# psyska is the print command. -/ prints a line.\x1b[0m");
    println!();
    println!("    \x1b[36mset name = \"Ayaan\"\x1b[0m");
    println!("    \x1b[36mset age = 16\x1b[0m");
    println!("    \x1b[36mpsyska -/ \"{{name}} is {{age}} years old.\"\x1b[0m");
    println!();
    println!("    \x1b[2m# Variables interpolate inside \"strings\" using {{name}}.\x1b[0m");
    println!("    \x1b[2m# `set` infers int / float / string automatically.\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m2.  Math + expressions\x1b[0m");
    println!();
    println!("    \x1b[36mset x = {{3 * (4 + 5)}}\x1b[0m            \x1b[2m# 27\x1b[0m");
    println!("    \x1b[36mset h = {{sqrt(3*3 + 4*4)}}\x1b[0m         \x1b[2m# 5\x1b[0m");
    println!("    \x1b[36mset s = {{sin(3.14159 / 4)}}\x1b[0m        \x1b[2m# ~0.707\x1b[0m");
    println!();
    println!("    \x1b[2m# Math expressions go inside {{ ... }}.\x1b[0m");
    println!("    \x1b[2m# Built-ins: + - * / %, sin cos tan, sqrt, pow, abs, floor,\x1b[0m");
    println!("    \x1b[2m#  ceil, round, exp, log, min, max, atan2, hypot, cbrt, int.\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m3.  Control flow — if / while / repeat\x1b[0m");
    println!();
    println!("    \x1b[36mif age >= 18\x1b[0m");
    println!("    \x1b[36m    psyska -/ \"adult\"\x1b[0m");
    println!("    \x1b[36melse\x1b[0m");
    println!("    \x1b[36m    psyska -/ \"minor\"\x1b[0m");
    println!("    \x1b[36mendif\x1b[0m");
    println!();
    println!("    \x1b[36mset i = 0\x1b[0m");
    println!("    \x1b[36mwhile i < 5\x1b[0m");
    println!("    \x1b[36m    psyska -/ \"i = {{i}}\"\x1b[0m");
    println!("    \x1b[36m    set i = {{i + 1}}\x1b[0m");
    println!("    \x1b[36mendwhile\x1b[0m");
    println!();
    println!("    \x1b[36mrepeat 3 n\x1b[0m");
    println!("    \x1b[36m    psyska -/ \"tick {{n}}\"   # n: 1, 2, 3\x1b[0m");
    println!("    \x1b[36mendrepeat\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m4.  Functions\x1b[0m");
    println!();
    println!("    \x1b[36mfunc add a b\x1b[0m");
    println!("    \x1b[36m    set result = {{a + b}}\x1b[0m");
    println!("    \x1b[36mendfunc\x1b[0m");
    println!();
    println!("    \x1b[36mcall add 5 7\x1b[0m");
    println!("    \x1b[36mpsyska -/ \"sum = {{result}}\"       # 12\x1b[0m");
    println!();
    println!("    \x1b[2m# Convention: return values go in the `result` variable.\x1b[0m");
    println!("    \x1b[2m# Functions see global vars and can mutate them.\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m5.  Lists + dicts\x1b[0m");
    println!();
    println!("    \x1b[36mlist xs = [10, 20, 30, 40]\x1b[0m");
    println!("    \x1b[36mpush xs 50\x1b[0m");
    println!("    \x1b[36mlsize xs -> n\x1b[0m             \x1b[2m# n = 5\x1b[0m");
    println!("    \x1b[36mlist_at xs 2 -> v\x1b[0m          \x1b[2m# v = 30\x1b[0m");
    println!("    \x1b[36mforeach v in xs\x1b[0m");
    println!("    \x1b[36m    psyska -/ \"got {{v}}\"\x1b[0m");
    println!("    \x1b[36mendforeach\x1b[0m");
    println!();
    println!("    \x1b[36mdict scores\x1b[0m");
    println!("    \x1b[36mdset scores \"alice\" 95\x1b[0m");
    println!("    \x1b[36mdset scores \"bob\" 82\x1b[0m");
    println!("    \x1b[36mdget scores \"alice\" -> v   # 95\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m6.  Strings\x1b[0m");
    println!();
    println!("    \x1b[36mset s = \"hello world\"\x1b[0m");
    println!("    \x1b[36mupper s\x1b[0m                  \x1b[2m# HELLO WORLD\x1b[0m");
    println!("    \x1b[36mstrlen s -> n\x1b[0m            \x1b[2m# 11\x1b[0m");
    println!("    \x1b[36msubstr part = s 0 5\x1b[0m      \x1b[2m# \"hello\"\x1b[0m");
    println!("    \x1b[36mreplace s2 = s \"world\" \"AS+\"\x1b[0m");
    println!();
    println!("    \x1b[2m# Lots more: trim, lower, reverse, split, join,\x1b[0m");
    println!("    \x1b[2m#  pad_left, pad_right, center_str, repeat_str, etc.\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m7.  File I/O + JSON\x1b[0m");
    println!();
    println!("    \x1b[36mwritefile \"out.txt\" \"some content\"\x1b[0m");
    println!("    \x1b[36mreadall \"out.txt\" -> body\x1b[0m");
    println!("    \x1b[36mfile_exists \"out.txt\" -> ok\x1b[0m");
    println!();
    println!("    \x1b[36mset payload = \"{{\\\"name\\\":\\\"hi\\\"}}\"\x1b[0m");
    println!("    \x1b[36mjson_pretty payload -> pp\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m8.  Classes + OOP\x1b[0m");
    println!();
    println!("    \x1b[36mclass Greeter\x1b[0m");
    println!("    \x1b[36m    field name\x1b[0m");
    println!("    \x1b[36m    method sayHi\x1b[0m");
    println!("    \x1b[36m        psyska -/ \"Hi from {{self.name}}\"\x1b[0m");
    println!("    \x1b[36m    endmethod\x1b[0m");
    println!("    \x1b[36mendclass\x1b[0m");
    println!();
    println!("    \x1b[36mnew g = Greeter\x1b[0m");
    println!("    \x1b[36mset g.name = \"Ayaan\"\x1b[0m");
    println!("    \x1b[36mg.sayHi\x1b[0m");
    println!();
    println!("    \x1b[2m# Supports inheritance (class B extends A), super calls,\x1b[0m");
    println!("    \x1b[2m# static methods, instanceof, and more.\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m9.  Error handling — try / catch\x1b[0m");
    println!();
    println!("    \x1b[36mtry\x1b[0m");
    println!("    \x1b[36m    set x = {{1 / 0}}\x1b[0m");
    println!("    \x1b[36mcatch e\x1b[0m");
    println!("    \x1b[36m    psyska -/ \"caught: {{e}}\"\x1b[0m");
    println!("    \x1b[36mendtry\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m10. Tests + assertions\x1b[0m");
    println!();
    println!("    \x1b[2m# In a file like math_tests.ayaan:\x1b[0m");
    println!("    \x1b[36mfunc test_addition\x1b[0m");
    println!("    \x1b[36m    set x = {{2 + 3}}\x1b[0m");
    println!("    \x1b[36m    assert x 5\x1b[0m");
    println!("    \x1b[36mendfunc\x1b[0m");
    println!();
    println!("    Run: \x1b[36m$ ayaan test math_tests.ayaan\x1b[0m");
    println!("    Any function named \x1b[1mtest_*\x1b[0m runs as a test. \x1b[1mfail \"msg\"\x1b[0m");
    println!("    inside a test marks it failed.");
    pause();

    println!();
    println!("\x1b[33m11. Packages (npm-style)\x1b[0m");
    println!();
    println!("    \x1b[36m$ aspkg create\x1b[0m            \x1b[2m# interactive wizard\x1b[0m");
    println!("    \x1b[36m$ aspkg build mylib\x1b[0m       \x1b[2m# scaffold OR bundle\x1b[0m");
    println!("    \x1b[36m$ aspkg link mylib\x1b[0m        \x1b[2m# install locally\x1b[0m");
    println!("    \x1b[36m$ aspkg install mylib\x1b[0m     \x1b[2m# install from registry\x1b[0m");
    println!("    \x1b[36m$ aspkg recent\x1b[0m            \x1b[2m# 10 newest packages\x1b[0m");
    println!();
    println!("    In a script:");
    println!("    \x1b[36mimport mylib\x1b[0m              \x1b[2m# package by name\x1b[0m");
    println!("    \x1b[36mimport \"helpers.ayaan\"\x1b[0m   \x1b[2m# local file\x1b[0m");
    println!();
    println!("    Every package MUST declare an \x1b[33m@help\x1b[0m block listing its");
    println!("    commands. The help text auto-shows on import as a warning.");
    pause();

    println!();
    println!("\x1b[33m12. GUI — open a native window\x1b[0m");
    println!();
    println!("    \x1b[36mgui_native \"My Window\" 800 600\x1b[0m");
    println!("    \x1b[36mgui_fps 60\x1b[0m");
    println!("    \x1b[36mset running = 1\x1b[0m");
    println!("    \x1b[36mwhile running == 1\x1b[0m");
    println!("    \x1b[36m    gui_open running\x1b[0m");
    println!("    \x1b[36m    gui_clear \"#0a0a25\"\x1b[0m");
    println!("    \x1b[36m    gui_fill_circle 400 300 50 \"red\"\x1b[0m");
    println!("    \x1b[36m    gui_text 10 10 \"Hello!\" \"white\"\x1b[0m");
    println!("    \x1b[36m    gui_update\x1b[0m");
    println!("    \x1b[36mendwhile\x1b[0m");
    println!("    \x1b[36mgui_close\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m13. 2D engine — images + scaling + rotation\x1b[0m");
    println!();
    println!("    \x1b[36mgui_2d_load_image \"hero\" \"hero.png\"\x1b[0m");
    println!("    \x1b[36mgui_2d_smooth on\x1b[0m                 \x1b[2m# bilinear\x1b[0m");
    println!("    \x1b[36mgui_2d_draw_image_scaled 100 100 64 64 \"hero\"\x1b[0m");
    println!("    \x1b[36mgui_2d_draw_image_rotated 200 100 64 64 \"hero\" 0.5\x1b[0m");
    println!("    \x1b[36mgui_2d_draw_image_tinted 300 100 64 64 \"hero\" \"#ff8866\"\x1b[0m");
    println!("    \x1b[36mgui_2d_camera player_x player_y 1.0\x1b[0m  \x1b[2m# pan + zoom\x1b[0m");
    println!();
    println!("    Plus tilesets, color-key transparency, text outline, and more.");
    pause();

    println!();
    println!("\x1b[33m14. 3D engine — hardware-style pipeline\x1b[0m");
    println!();
    println!("    \x1b[36mgui_3d_setup 800 400 300\x1b[0m");
    println!("    \x1b[36mgui_3d_camera_pos 0 0 -5\x1b[0m");
    println!("    \x1b[36mgui_3d_light -0.3 -0.6 -0.5\x1b[0m");
    println!("    \x1b[36mgui_3d_fog 10 30 \"#0a0a14\"\x1b[0m");
    println!("    \x1b[36mgui_3d_cube 0 0 0 2 \"#ff5577\"\x1b[0m");
    println!("    \x1b[36mgui_3d_sphere 3 0 0 1 16 \"#44aaff\"\x1b[0m");
    println!("    \x1b[36mgui_3d_load_obj \"ship\" \"ship.obj\"\x1b[0m");
    println!("    \x1b[36mgui_3d_draw_mesh \"ship\" 0 1 0 0.5 \"#ffaa44\"\x1b[0m");
    println!();
    println!("    Z-buffer, Lambertian + multi-light, shadows, PNG textures.");
    pause();

    println!();
    println!("\x1b[33m15. Particles, audio, web\x1b[0m");
    println!();
    println!("    \x1b[36mgui_particle_burst x y 60 \"#ffaa33\" 5 80\x1b[0m");
    println!("    \x1b[36mgui_particle_update\x1b[0m");
    println!("    \x1b[36mgui_particle_draw\x1b[0m");
    println!();
    println!("    \x1b[36mbeep_tone 440 200\x1b[0m              \x1b[2m# audio beep\x1b[0m");
    println!("    \x1b[36mcurl \"https://...\" \"/tmp/x.png\"\x1b[0m \x1b[2m# download\x1b[0m");
    println!("    \x1b[36mgui_2d_load_image_url \"x\" \"https://...\"\x1b[0m");
    pause();

    println!();
    println!("\x1b[33m16. CLI shortcuts\x1b[0m");
    println!();
    println!("    \x1b[36m$ ayaan\x1b[0m                      \x1b[2m# REPL\x1b[0m");
    println!("    \x1b[36m$ ayaan file.ayaan\x1b[0m            \x1b[2m# run a script\x1b[0m");
    println!("    \x1b[36m$ ayaan --watch file.ayaan\x1b[0m    \x1b[2m# auto-rerun on save\x1b[0m");
    println!("    \x1b[36m$ ayaan test file.ayaan\x1b[0m       \x1b[2m# run test_* funcs\x1b[0m");
    println!("    \x1b[36m$ ayaan fmt file.ayaan\x1b[0m        \x1b[2m# normalize whitespace\x1b[0m");
    println!("    \x1b[36m$ ayaan art picture.png\x1b[0m       \x1b[2m# pixel art editor\x1b[0m");
    println!("    \x1b[36m$ ayaan help\x1b[0m                 \x1b[2m# this tutorial\x1b[0m");
    pause();

    println!();
    println!("\x1b[32mYou're all set. Try these next:\x1b[0m");
    println!();
    println!("  • \x1b[36mhelp\x1b[0m              — list all 5000+ runtime commands");
    println!("  • \x1b[36maspkg help\x1b[0m        — package manager tutorial");
    println!("  • \x1b[36maspkg recent\x1b[0m      — see what others have shipped");
    println!("  • https://crates.io/crates/ayaan — docs + source");
    println!();
    if is_first_run {
        println!("Dropping you into the REPL now. Type \x1b[36mexit\x1b[0m to quit, \x1b[36mhelp\x1b[0m for commands.");
    } else {
        println!("Run \x1b[36mayaan\x1b[0m to enter the REPL, or \x1b[36mayaan myfile.ayaan\x1b[0m to execute a script.");
    }
    println!();

    if is_first_run {
        let marker = first_run_marker();
        if let Some(parent) = marker.parent() {
            let _ = fs::create_dir_all(parent);
        }
        let _ = fs::write(&marker, "1\n");
    }
}

// Backwards-compat wrapper
fn show_first_run_tutorial() {
    run_tutorial(true);
}

fn main() {
    enable_ansi_on_windows();
    ensure_dirs();
    check_for_update();

    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        // First-ever launch? Run the tutorial before dropping into REPL.
        if !first_run_marker().exists() {
            show_first_run_tutorial();
        }
        run_repl();
        return;
    }

    // Handle --watch flag
    if args[1] == "--watch" || args[1] == "-w" {
        if args.len() < 3 {
            eprintln!("Usage: ayaan --watch <script.ayaan>");
            return;
        }
        run_watch_mode(Path::new(&args[2]));
        return;
    }

    if args[1] == "--version" || args[1] == "-V" {
        println!("ayaan {}", CURRENT_VERSION);
        return;
    }

    if args[1] == "--help" || args[1] == "-h" {
        println!("Usage:");
        println!("  ayaan                          start REPL");
        println!("  ayaan <file.ayaan>             run a script");
        println!("  ayaan --watch <file.ayaan>     run + re-run on save");
        println!("  ayaan test <file.ayaan>        run test_* functions");
        println!("  ayaan fmt <file.ayaan>         normalize whitespace");
        println!("  ayaan art [output.png]         launch the art editor");
        println!("  ayaan starter [template]       scaffold a starter project (interactive)");
        println!("  ayaan help                     run the interactive tutorial");
        println!("  ayaan --version                print version");
        println!("  ayaan --help                   show this message");
        return;
    }

    if args[1] == "art" {
        let out = args.get(2).map(|s| s.as_str()).unwrap_or("art_output.png");
        run_art_editor(out);
        return;
    }

    if args[1] == "help" {
        run_tutorial(false);
        return;
    }

    if args[1] == "test" {
        if args.len() < 3 {
            eprintln!("Usage: ayaan test <file.ayaan>");
            return;
        }
        run_tests(Path::new(&args[2]));
        return;
    }

    if args[1] == "fmt" {
        if args.len() < 3 {
            eprintln!("Usage: ayaan fmt <file.ayaan>");
            return;
        }
        run_fmt(Path::new(&args[2]));
        return;
    }

    // `ayaan starter [template]` — delegates to `aspkg starter`.
    // Both bins ship together, so this is a friendly alias for users who
    // haven't discovered aspkg yet.
    if args[1] == "starter" {
        run_ayaan_starter(&args[2..]);
        return;
    }

    let script_path = PathBuf::from(&args[1]);
    run_script_once(&script_path);
}

// === Built-in test runner ===
// Finds functions named test_* in the script, runs each, reports pass/fail.
// A test passes if it completes without invoking `fail`, `assert`, or panicking.
fn run_tests(path: &Path) {
    let source = match fs::read_to_string(path) {
        Ok(s) => s,
        Err(e) => { eprintln!("ayaan test: {}", e); return; }
    };

    // Discover test_* function names
    let mut tests: Vec<String> = Vec::new();
    for line in source.lines() {
        let t = line.trim();
        if let Some(rest) = t.strip_prefix("func ") {
            let name = rest.split_whitespace().next().unwrap_or("");
            if name.starts_with("test_") {
                tests.push(name.to_string());
            }
        }
    }
    if tests.is_empty() {
        println!("ayaan test: no test_* functions found in {}", path.display());
        return;
    }

    println!("\x1b[36mRunning {} test{} in {}\x1b[0m",
        tests.len(),
        if tests.len() == 1 { "" } else { "s" },
        path.display());
    println!();

    let mut passed = 0;
    let mut failed = 0;

    for tname in &tests {
        // Build a one-shot script: <source> + `call <tname>`
        let test_src = format!("{}\ncall {}\n", source, tname);
        let tmp = std::env::temp_dir().join(format!("__ayaan_test_{}.ayaan", tname));
        if let Err(e) = fs::write(&tmp, &test_src) {
            eprintln!("test setup failed: {}", e);
            continue;
        }
        let exe = std::env::current_exe()
            .unwrap_or_else(|_| PathBuf::from("ayaan"));
        let output = std::process::Command::new(&exe)
            .arg(&tmp)
            .output();
        let _ = fs::remove_file(&tmp);
        match output {
            Ok(o) => {
                let stdout = String::from_utf8_lossy(&o.stdout);
                let stderr = String::from_utf8_lossy(&o.stderr);
                let failed_signal = stdout.contains("[TEST FAIL]")
                    || stderr.contains("panic")
                    || !o.status.success();
                if failed_signal {
                    println!("  \x1b[31mFAIL\x1b[0m {}", tname);
                    if !stdout.is_empty() {
                        for line in stdout.lines().take(5) {
                            println!("        {}", line);
                        }
                    }
                    failed += 1;
                } else {
                    println!("  \x1b[32mPASS\x1b[0m {}", tname);
                    passed += 1;
                }
            }
            Err(e) => {
                println!("  \x1b[31mFAIL\x1b[0m {} (couldn't run: {})", tname, e);
                failed += 1;
            }
        }
    }
    println!();
    println!("\x1b[36m{}/{} passed\x1b[0m   \x1b[31m{} failed\x1b[0m",
        passed, tests.len(), failed);
}

// === Tiny formatter ===
// Just normalizes trailing whitespace and trims empty trailing newlines.
// Useful as a sanity pre-commit step; doesn't try to re-indent code.
// `ayaan starter` — delegates to `aspkg starter` (which ships in the same
// package). Looks for aspkg next to the current binary first, then on PATH.
fn run_ayaan_starter(extra_args: &[String]) {
    use std::process::Command;

    // Prefer the aspkg binary that ships with THIS ayaan (same install dir).
    let mut aspkg_path: Option<PathBuf> = None;
    if let Ok(exe) = std::env::current_exe() {
        if let Some(parent) = exe.parent() {
            let candidate = parent.join(if cfg!(windows) { "aspkg.exe" } else { "aspkg" });
            if candidate.exists() {
                aspkg_path = Some(candidate);
            }
        }
    }
    let program: PathBuf = aspkg_path.unwrap_or_else(|| PathBuf::from("aspkg"));

    let status = Command::new(&program)
        .arg("starter")
        .args(extra_args)
        .status();
    match status {
        Ok(s) if s.success() => {}
        Ok(s) => {
            std::process::exit(s.code().unwrap_or(1));
        }
        Err(e) => {
            eprintln!("ayaan starter: couldn't run aspkg ({}).", e);
            eprintln!("  Is aspkg installed? Try: cargo install ayaan --force");
            std::process::exit(1);
        }
    }
}

fn run_fmt(path: &Path) {
    let source = match fs::read_to_string(path) {
        Ok(s) => s,
        Err(e) => { eprintln!("ayaan fmt: {}", e); return; }
    };
    let mut out = String::with_capacity(source.len());
    for line in source.lines() {
        out.push_str(line.trim_end());
        out.push('\n');
    }
    // collapse trailing blank lines to one
    while out.ends_with("\n\n") {
        out.pop();
    }
    if let Err(e) = fs::write(path, &out) {
        eprintln!("ayaan fmt: failed to write: {}", e);
    } else {
        println!("formatted: {}", path.display());
    }
}
