<%+cbi/valueheader%>
<script type="text/javascript">
//<![CDATA[
function padright(str, cnt, pad) {
    return str + Array(cnt + 1).join(pad);
}

function b64EncodeUnicode(str) {
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
        return String.fromCharCode('0x' + p1);
    }));
}

function b64encutf8safe(str) {
    return b64EncodeUnicode(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '');
}

function b64DecodeUnicode(str) {
    return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
}

function b64decutf8safe(str) {
    var l;
    str = str.replace(/-/g, "+").replace(/_/g, "/");
    l = str.length;
    l = (4 - l % 4) % 4;
    if (l) str = padright(str, l, "=");
    return b64DecodeUnicode(str);
}

function b64encsafe(str) {
    return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '')
}

function b64decsafe(str) {
    var l;
    str = str.replace(/-/g, "+").replace(/_/g, "/");
    l = str.length;
    l = (4 - l % 4) % 4;
    if (l) str = padright(str, l, "=");
    return atob(str);
}

function dictvalue(d, key) {
    var v = d[key];
    if (typeof (v) == 'undefined' || v == '') return '';
    return b64decsafe(v);
}

function parseUrl(url) {
    var m = url.match(/^(([^:\/?#]+:)?(?:\/\/((?:([^\/?#:]*)([^\/?#:]*)@)?([^\/?#:]*)(?::([^\/?#:]*))?)))?([^?#]*)(\?[^#]*)?(#.*)?$/);
    if (!m) return null;
    return {
        hash: m[10] || "",
        host: m[3] || "",
        hostname: m[6] || "",
        href: m[0] || "",
        origin: m[1] || "",
        pathname: m[8] || (m[1] ? "/" : ""),
        port: m[7] || "",
        protocol: m[2] || "",
        search: m[9] || "",
        username: m[4] || "",
        password: m[5] || ""
    };
}

function decodeFragment(fragment) {
    if (!fragment) return '';
    try {
        var decoded = decodeURIComponent(fragment);
        while (decoded !== fragment) {
            fragment = decoded;
            decoded = decodeURIComponent(fragment);
        }
        return fragment;
    } catch (e) {
        return fragment;
    }
}

function parseQuery(search) {
    var query = {};
    if (search && search.length > 1) {
        var params = search.substring(1).split('&');
        for (var i = 0; i < params.length; i++) {
            var eqIndex = params[i].indexOf('=');
            if (eqIndex !== -1) {
                var key = params[i].substring(0, eqIndex);
                var value = params[i].substring(eqIndex + 1);
                try {
                    key = decodeURIComponent(key);
                    query[key] = value;
                } catch (e) {
                    query[key] = value;
                }
            }
        }
    }
    return query;
}

function setFormValue(sid, field, value) {
    var element = document.getElementsByName('cbid.openclash.' + sid + '.' + field)[0];
    if (element) {
        element.value = value;
        var event = document.createEvent("HTMLEvents");
        event.initEvent("change", true, true);
        element.dispatchEvent(event);
    }
}

function export_url(btn, urlname, sid) {
    var s = document.getElementById(urlname + '-status');
    if (!s) return false;

    var v_type = document.getElementsByName('cbid.openclash.' + sid + '.type')[0];
    if (!v_type) return false;

    var type = v_type.value.toLowerCase();
    var url = null;

    try {
        switch (type) {
            case "ss":
                url = exportSS(sid);
                break;
            case "ssr":
                url = exportSSR(sid);
                break;
            case "vmess":
                url = exportVmess(sid);
                break;
            case "vless":
                url = exportVless(sid);
                break;
            case "trojan":
                url = exportTrojan(sid);
                break;
            case "hysteria":
                url = exportHysteria(sid);
                break;
            case "hysteria2":
                url = exportHysteria2(sid);
                break;
            case "tuic":
                url = exportTuic(sid);
                break;
            case "socks5":
                url = exportSocks(sid);
                break;
            case "http":
                url = exportHttp(sid);
                break;
            case "anytls":
                url = exportAnyTLS(sid);
                break;
            default:
                s.innerHTML = "<font style=\"color:red\"><%:Unsupported protocol type%></font>";
                return false;
        }

        if (url) {
            var textarea = document.createElement("textarea");
            textarea.textContent = url;
            textarea.style.position = "fixed";
            document.body.appendChild(textarea);
            textarea.select();
            try {
                document.execCommand("copy");
                s.innerHTML = "<font style=\"color:green\"><%:Copy%> " + type.toUpperCase() + " <%:to clipboard successfully%></font>";
            } catch (ex) {
                s.innerHTML = "<font style=\"color:red\"><%:Unable to copy%> " + type.toUpperCase() + " <%:to clipboard%></font>";
            } finally {
                document.body.removeChild(textarea);
            }
        } else {
            s.innerHTML = "<font style=\"color:red\"><%:Export failed%></font>";
        }
    } catch (e) {
        s.innerHTML = "<font style=\"color:red\"><%:Export error%></font>";
        return false;
    }

    return false;
}

function getFormValue(sid, field) {
    var element = document.getElementsByName('cbid.openclash.' + sid + '.' + field)[0];
    return element ? element.value : '';
}

function exportSS(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var password = getFormValue(sid, 'password');
    var cipher = getFormValue(sid, 'cipher');
    var name = getFormValue(sid, 'name');
    var obfs = getFormValue(sid, 'obfs');
    var host = getFormValue(sid, 'host');
    var path = getFormValue(sid, 'path');
    var tls = getFormValue(sid, 'tls');

    if (!server || !port || !password || !cipher) {
        return null;
    }

    // SIP002 format
    var userInfo = b64encsafe(cipher + ':' + password);
    var url = userInfo + '@' + server + ':' + port + '/?';

    var params = [];

    if (obfs && obfs !== 'none') {
        var plugin = '';
        if (obfs === 'http' || obfs === 'tls') {
            plugin = 'obfs-local;obfs=' + obfs;
            if (host) {
                plugin += ';obfs-host=' + host;
            }
        } else if (obfs === 'websocket') {
            plugin = 'v2ray-plugin;mode=websocket';
            if (host) {
                plugin += ';host=' + host;
            }
            if (path) {
                plugin += ';path=' + path;
            }
            if (tls === 'true') {
                plugin += ';tls=true';
            }
        }
        if (plugin) {
            params.push('plugin=' + encodeURIComponent(plugin));
        }
    }

    url += params.join('&');

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'ss://' + url;
}

function exportSSR(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var protocol = getFormValue(sid, 'protocol');
    var method = getFormValue(sid, 'cipher_ssr');
    var obfs = getFormValue(sid, 'obfs_ssr');
    var password = getFormValue(sid, 'password');
    var obfs_param = getFormValue(sid, 'obfs_param');
    var protocol_param = getFormValue(sid, 'protocol_param');
    var name = getFormValue(sid, 'name');

    if (!server || !port || !password || !method) {
        return null;
    }

    var ssr_str = server + ":" + port + ":" + protocol + ":" + method + ":" + obfs + ":" + 
                  b64encsafe(password) + "/?obfsparam=" + b64encsafe(obfs_param) + 
                  "&protoparam=" + b64encsafe(protocol_param) + "&remarks=" + b64encutf8safe(name);

    return "ssr://" + b64encsafe(ssr_str);
}

function exportVmess(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var uuid = getFormValue(sid, 'uuid');
    var alterId = getFormValue(sid, 'alterId');
    var security = getFormValue(sid, 'securitys');
    var name = getFormValue(sid, 'name');
    var obfs = getFormValue(sid, 'obfs_vmess');
    var tls = getFormValue(sid, 'tls');
    var servername = getFormValue(sid, 'servername');

    if (!server || !port || !uuid) {
        return null;
    }

    var info = {
        "v": "2",
        "ps": name || "",
        "add": server,
        "port": port,
        "id": uuid,
        "aid": alterId || "0",
        "scy": security || "auto",
        "net": "tcp",
        "type": "none",
        "host": "",
        "path": "",
        "tls": tls === 'true' ? "tls" : ""
    };

    if (tls === 'true' && servername) {
        info.sni = servername;
    }

    // Handle network type
    if (obfs === 'websocket') {
        info.net = "ws";
        info.path = getFormValue(sid, 'ws_opts_path') || '/';
        var headers = getFormValue(sid, 'ws_opts_headers');
        if (headers && headers.includes('Host:')) {
            info.host = headers.split('Host:')[1].trim();
        }
    } else if (obfs === 'h2') {
        info.net = "h2";
        info.path = getFormValue(sid, 'h2_path') || '/';
        info.host = getFormValue(sid, 'h2_host') || '';
    } else if (obfs === 'grpc') {
        info.net = "grpc";
        info.path = getFormValue(sid, 'grpc_service_name') || '';
    }

    return "vmess://" + b64EncodeUnicode(JSON.stringify(info));
}

function exportVless(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var uuid = getFormValue(sid, 'uuid');
    var name = getFormValue(sid, 'name');
    var tls = getFormValue(sid, 'tls');
    var servername = getFormValue(sid, 'servername');
    var obfs = getFormValue(sid, 'obfs_vless');
    var flow = getFormValue(sid, 'vless_flow');

    if (!server || !port || !uuid) {
        return null;
    }

    var url = uuid + '@' + server + ':' + port + '?';
    var params = [];

    params.push('encryption=none');

    if (tls === 'true') {
        if (flow && flow.includes('xtls')) {
            params.push('security=xtls');
            params.push('flow=' + flow);
        } else {
            params.push('security=tls');
        }
        if (servername) {
            params.push('sni=' + encodeURIComponent(servername));
        }
    }

    if (obfs === 'ws') {
        params.push('type=ws');
        var path = getFormValue(sid, 'ws_opts_path');
        if (path) {
            params.push('path=' + encodeURIComponent(path));
        }
        var headers = getFormValue(sid, 'ws_opts_headers');
        if (headers && headers.includes('Host:')) {
            var host = headers.split('Host:')[1].trim();
            params.push('host=' + encodeURIComponent(host));
        }
    } else if (obfs === 'grpc') {
        params.push('type=grpc');
        var serviceName = getFormValue(sid, 'grpc_service_name');
        if (serviceName) {
            params.push('serviceName=' + encodeURIComponent(serviceName));
        }
    } else {
        params.push('type=tcp');
    }

    url += params.join('&');

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'vless://' + url;
}

function exportTrojan(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var password = getFormValue(sid, 'password');
    var name = getFormValue(sid, 'name');
    var sni = getFormValue(sid, 'sni');
    var alpn = getFormValue(sid, 'alpn');
    var skip_cert = getFormValue(sid, 'skip_cert_verify');

    if (!server || !port || !password) {
        return null;
    }

    var url = encodeURIComponent(password) + '@' + server + ':' + port + '/?';
    var params = [];

    if (sni) {
        params.push('sni=' + encodeURIComponent(sni));
    }

    if (alpn) {
        params.push('alpn=' + encodeURIComponent(alpn));
    }

    if (skip_cert === 'true') {
        params.push('allowInsecure=1');
    }

    url += params.join('&');

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'trojan://' + url;
}

function exportHysteria(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var auth = getFormValue(sid, 'hysteria_auth_str');
    var name = getFormValue(sid, 'name');
    var protocol = getFormValue(sid, 'hysteria_protocol');
    var up = getFormValue(sid, 'hysteria_up');
    var down = getFormValue(sid, 'hysteria_down');
    var obfs = getFormValue(sid, 'hysteria_obfs');
    var sni = getFormValue(sid, 'sni');
    var alpn = getFormValue(sid, 'hysteria_alpn');
    var skip_cert = getFormValue(sid, 'skip_cert_verify');

    if (!server || !port) {
        return null;
    }

    var url = server + ':' + port + '?';
    var params = [];

    if (auth) {
        params.push('auth=' + encodeURIComponent(auth));
    }

    if (protocol) {
        params.push('protocol=' + protocol);
    }

    if (up) {
        params.push('up=' + up);
    }

    if (down) {
        params.push('down=' + down);
    }

    if (obfs) {
        params.push('obfsParam=' + encodeURIComponent(obfs));
    }

    if (sni) {
        params.push('peer=' + encodeURIComponent(sni));
    }

    if (alpn) {
        params.push('alpn=' + encodeURIComponent(alpn));
    }

    if (skip_cert === 'true') {
        params.push('insecure=1');
    }

    url += params.join('&');

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'hysteria://' + url;
}

function exportHysteria2(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var password = getFormValue(sid, 'password');
    var name = getFormValue(sid, 'name');
    var obfs = getFormValue(sid, 'hysteria_obfs');
    var obfs_password = getFormValue(sid, 'hysteria_obfs_password');
    var up = getFormValue(sid, 'hysteria_up');
    var down = getFormValue(sid, 'hysteria_down');
    var sni = getFormValue(sid, 'sni');
    var alpn = getFormValue(sid, 'hysteria_alpn');
    var skip_cert = getFormValue(sid, 'skip_cert_verify');

    if (!server || !port) {
        return null;
    }

    var url = '';
    if (password) {
        url += encodeURIComponent(password) + '@';
    }
    url += server + ':' + port + '?';

    var params = [];

    if (obfs) {
        params.push('obfs=' + encodeURIComponent(obfs));
    }

    if (obfs_password) {
        params.push('obfs-password=' + encodeURIComponent(obfs_password));
    }

    if (up) {
        params.push('up=' + up);
    }

    if (down) {
        params.push('down=' + down);
    }

    if (sni) {
        params.push('sni=' + encodeURIComponent(sni));
    }

    if (alpn) {
        params.push('alpn=' + encodeURIComponent(alpn));
    }

    if (skip_cert === 'true') {
        params.push('insecure=1');
    }

    url += params.join('&');

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'hysteria2://' + url;
}

function exportTuic(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var uuid = getFormValue(sid, 'uuid');
    var password = getFormValue(sid, 'password');
    var token = getFormValue(sid, 'tc_token');
    var name = getFormValue(sid, 'name');
    var cc = getFormValue(sid, 'congestion_controller');
    var alpn = getFormValue(sid, 'tc_alpn');
    var sni = getFormValue(sid, 'sni');
    var disable_sni = getFormValue(sid, 'disable_sni');
    var udp_relay = getFormValue(sid, 'udp_relay_mode');

    if (!server || !port) {
        return null;
    }

    var url = '';
    if (password) {
        // TUIC v5
        url += encodeURIComponent(uuid) + ':' + encodeURIComponent(password) + '@';
    } else if (token) {
        // TUIC v4
        url += encodeURIComponent(token) + '@';
    }

    url += server + ':' + port + '?';

    var params = [];

    if (cc) {
        params.push('congestion_control=' + encodeURIComponent(cc));
    }

    if (alpn) {
        params.push('alpn=' + encodeURIComponent(alpn));
    }

    if (sni) {
        params.push('sni=' + encodeURIComponent(sni));
    }

    if (disable_sni === 'true') {
        params.push('disable_sni=1');
    }

    if (udp_relay) {
        params.push('udp_relay_mode=' + encodeURIComponent(udp_relay));
    }

    url += params.join('&');

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'tuic://' + url;
}

function exportSocks(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var username = getFormValue(sid, 'auth_name');
    var password = getFormValue(sid, 'auth_pass');
    var name = getFormValue(sid, 'name');

    if (!server || !port) {
        return null;
    }

    var url = '';
    if (username && password) {
        url += encodeURIComponent(username) + ':' + encodeURIComponent(password) + '@';
    }
    url += server + ':' + port;

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'socks5://' + url;
}

function exportHttp(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var username = getFormValue(sid, 'auth_name');
    var password = getFormValue(sid, 'auth_pass');
    var name = getFormValue(sid, 'name');
    var tls = getFormValue(sid, 'tls');

    if (!server || !port) {
        return null;
    }

    var scheme = tls === 'true' ? 'https' : 'http';
    var url = '';

    if (username && password) {
        url += encodeURIComponent(username) + ':' + encodeURIComponent(password) + '@';
    }
    url += server + ':' + port;

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return scheme + '://' + url;
}

function exportAnyTLS(sid) {
    var server = getFormValue(sid, 'server');
    var port = getFormValue(sid, 'port');
    var username = getFormValue(sid, 'auth_name');
    var password = getFormValue(sid, 'password');
    var name = getFormValue(sid, 'name');
    var sni = getFormValue(sid, 'sni');
    var fingerprint = getFormValue(sid, 'fingerprint');
    var skip_cert = getFormValue(sid, 'skip_cert_verify');

    if (!server || !port) {
        return null;
    }

    var url = '';
    if (username) {
        url += encodeURIComponent(username);
        if (password) {
            url += ':' + encodeURIComponent(password);
        }
        url += '@';
    }
    url += server + ':' + port + '?';

    var params = [];

    if (sni) {
        params.push('sni=' + encodeURIComponent(sni));
    }

    if (fingerprint) {
        params.push('hpkp=' + encodeURIComponent(fingerprint));
    }

    if (skip_cert === 'true') {
        params.push('insecure=1');
    }

    url += params.join('&');

    if (name) {
        url += '#' + encodeURIComponent(name);
    }

    return 'anytls://' + url;
}

function import_url(btn, urlname, sid) {
    var s = document.getElementById(urlname + '-status');
    if (!s) return false;

    var ssrurl = prompt("<%:Paste sharing link here%>", "");
    if (ssrurl == null || ssrurl == "") {
        s.innerHTML = "<font style=\"color:red\"><%:User cancelled%></font>";
        return false;
    }
    s.innerHTML = "";

    var ssu = ssrurl.split('://');
    if (ssu.length < 2) {
        s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
        return false;
    }

    var scheme = ssu[0].toLowerCase();
    var event = document.createEvent("HTMLEvents");
    event.initEvent("change", true, true);

    try {
        switch (scheme) {
            case "ss":
                if (parseSS(ssu[1], sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "ssr":
                if (parseSSR(ssu[1], sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "vmess":
                if (parseVmess(ssu[1], sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "vless":
                if (parseVless(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "trojan":
                if (parseTrojan(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "hysteria":
                if (parseHysteria(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "hysteria2":
            case "hy2":
                if (parseHysteria2(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "tuic":
                if (parseTuic(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "socks":
            case "socks5":
            case "socks5h":
                if (parseSocks(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "http":
            case "https":
                if (parseHttp(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            case "anytls":
                if (parseAnyTLS(ssrurl, sid)) {
                    s.innerHTML = "<font style=\"color:green\"><%:Import configuration information successfully%></font>";
                } else {
                    s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                }
                break;

            default:
                s.innerHTML = "<font style=\"color:red\"><%:Invalid format%></font>";
                return false;
        }
    } catch (e) {
        s.innerHTML = "<font style=\"color:red\"><%:Parse error%></font>";
        return false;
    }

    return false;
}

function parseSS(body, sid) {
    var url0, param = "";
    var sipIndex = body.indexOf("@");
    var ploc = body.indexOf("#");

    if (ploc > 0) {
        url0 = body.substr(0, ploc);
        param = body.substr(ploc + 1);
    } else {
        url0 = body;
    }

    setFormValue(sid, 'type', 'ss');

    if (sipIndex !== -1) {
        // SIP002 format
        var userInfo = b64decsafe(url0.substr(0, sipIndex));
        var temp = url0.substr(sipIndex + 1).split("/?");
        var serverInfo = temp[0].split(":");
        var server = serverInfo[0];
        var port = serverInfo[1];
        var method, password;

        if (temp[1]) {
            var query = parseQuery("?" + temp[1]);

            if (query.plugin) {
                var decodedPlugin = decodeURIComponent(query.plugin);

                var pluginParts = decodedPlugin.split(';');
                var pluginName = pluginParts[0];

                // obfs-local
                if (pluginName === 'obfs-local' || pluginName.includes('obfs')) {
                    var obfsMode = 'http';
                    var obfsHost = '';

                    for (var i = 1; i < pluginParts.length; i++) {
                        var opt = pluginParts[i];
                        var eqIndex = opt.indexOf('=');
                        if (eqIndex !== -1) {
                            var key = opt.substring(0, eqIndex).trim();
                            var value = opt.substring(eqIndex + 1).trim();

                            if (key === 'obfs') {
                                obfsMode = value;
                            } else if (key === 'obfs-host') {
                                obfsHost = value;
                            }
                        }
                    }

                    setFormValue(sid, 'obfs', obfsMode);
                    if (obfsHost) {
                        setFormValue(sid, 'host', obfsHost);
                    }
                }

                // v2ray-plugin
                if (pluginName === 'v2ray-plugin') {
                    var v2rayMode = 'websocket';
                    var v2rayHost = '';
                    var v2rayPath = '/';
                    var v2rayTls = false;

                    for (var i = 1; i < pluginParts.length; i++) {
                        var opt = pluginParts[i];
                        var eqIndex = opt.indexOf('=');
                        if (eqIndex !== -1) {
                            var key = opt.substring(0, eqIndex).trim();
                            var value = opt.substring(eqIndex + 1).trim();

                            if (key === 'mode') {
                                v2rayMode = value;
                            } else if (key === 'host') {
                                v2rayHost = value;
                            } else if (key === 'path') {
                                v2rayPath = value;
                            } else if (key === 'tls') {
                                v2rayTls = value === 'true' || value === '1';
                            }
                        }
                    }

                    setFormValue(sid, 'obfs', 'websocket');
                    if (v2rayHost) {
                        setFormValue(sid, 'host', v2rayHost);
                    }
                    if (v2rayPath) {
                        setFormValue(sid, 'path', v2rayPath);
                    }
                    if (v2rayTls) {
                        setFormValue(sid, 'tls', 'true');
                    }
                }
            }

            if (query['udp-over-tcp'] === 'true' || query['uot'] === '1') {
                setFormValue(sid, 'udp_over_tcp', 'true');
            }
        }

        var userInfoSplitIndex = userInfo.indexOf(":");
        if (userInfoSplitIndex !== -1) {
            method = userInfo.substr(0, userInfoSplitIndex);
            password = userInfo.substr(userInfoSplitIndex + 1);
        }

        setFormValue(sid, 'server', server);
        setFormValue(sid, 'port', port);
        setFormValue(sid, 'password', password || "");
        setFormValue(sid, 'cipher', method || "");
    } else {
        // Legacy format
        var sstr = b64decsafe(url0);
        var team = sstr.split('@');
        var part1 = team[0].split(':');
        var part2 = team[1].split(':');

        setFormValue(sid, 'server', part2[0]);
        setFormValue(sid, 'port', part2[1]);
        setFormValue(sid, 'password', part1[1]);
        setFormValue(sid, 'cipher', part1[0]);
    }

    if (param) {
        setFormValue(sid, 'name', decodeURIComponent(param));
    }

    return true;
}

function parseSSR(body, sid) {
    var dcBuf;
    try {
        dcBuf = b64decsafe(body);
    } catch (e) {
        return false;
    }

    setFormValue(sid, 'type', 'ssr');

    // ssr://host:port:protocol:method:obfs:urlsafebase64pass/?obfsparam=...
    var before, after;
    var queryIndex = dcBuf.indexOf('/?');
    if (queryIndex > 0) {
        before = dcBuf.substr(0, queryIndex);
        after = dcBuf.substr(queryIndex + 2);
    } else {
        before = dcBuf;
        after = "";
    }

    var parts = before.split(':');
    if (parts.length !== 6) {
        return false;
    }

    var host = parts[0];
    var port = parts[1];
    var protocol = parts[2];
    var method = parts[3];
    var obfs = parts[4];
    var password = b64decsafe(parts[5]);

    setFormValue(sid, 'server', host);
    setFormValue(sid, 'port', port);
    setFormValue(sid, 'protocol', protocol);
    setFormValue(sid, 'cipher_ssr', method);
    setFormValue(sid, 'obfs_ssr', obfs);
    setFormValue(sid, 'password', password);

    if (after) {
        var params = {};
        var paramPairs = after.split('&');
        for (var i = 0; i < paramPairs.length; i++) {
            var pair = paramPairs[i].split('=');
            if (pair.length === 2) {
                var key = decodeURIComponent(pair[0]);
                var value = pair[1];
                params[key] = value;
            }
        }

        if (params.obfsparam) {
            setFormValue(sid, 'obfs_param', b64decsafe(params.obfsparam));
        }

        if (params.protoparam) {
            setFormValue(sid, 'protocol_param', b64decsafe(params.protoparam));
        }

        if (params.remarks) {
            setFormValue(sid, 'name', b64decutf8safe(params.remarks));
        }
    }

    return true;
}

function parseVmess(body, sid) {
    try {
        // Try V2rayN format first
        var sstr = b64DecodeUnicode(body);
        var ssm = JSON.parse(sstr);

        setFormValue(sid, 'type', 'vmess');
        setFormValue(sid, 'name', ssm.ps || '');
        setFormValue(sid, 'server', ssm.add);
        setFormValue(sid, 'port', ssm.port);
        setFormValue(sid, 'alterId', ssm.aid || 0);
        setFormValue(sid, 'uuid', ssm.id);

        if (ssm.scy) {
            setFormValue(sid, 'securitys', ssm.scy);
        }

        if (ssm.tls === "tls") {
            setFormValue(sid, 'tls', 'true');
            if (ssm.sni) {
                setFormValue(sid, 'servername', ssm.sni);
            }
        }

        var network = (ssm.net || 'tcp').toLowerCase();
        if (network === 'ws') {
            setFormValue(sid, 'obfs_vmess', 'websocket');
            setFormValue(sid, 'ws_opts_path', ssm.path || '/');
            if (ssm.host) {
                setFormValue(sid, 'ws_opts_headers', 'Host: ' + ssm.host);
            }
        } else if (network === 'h2') {
            setFormValue(sid, 'obfs_vmess', 'h2');
            setFormValue(sid, 'h2_path', ssm.path || '/');
            if (ssm.host) {
                setFormValue(sid, 'h2_host', ssm.host);
            }
        } else if (network === 'tcp') {
            if (ssm.type === 'http') {
                setFormValue(sid, 'obfs_vmess', 'http');
                if (ssm.path) {
                    setFormValue(sid, 'http_path', ssm.path);
                }
                if (ssm.host) {
                    setFormValue(sid, 'http_host', ssm.host);
                }
            } else {
                setFormValue(sid, 'obfs_vmess', 'none');
            }
        } else if (network === 'grpc') {
            setFormValue(sid, 'obfs_vmess', 'grpc');
            setFormValue(sid, 'grpc_service_name', ssm.path || '');
        }

        return true;
    } catch (e) {
        // Try Xray VMessAEAD format
        try {
            var parsed = parseUrl('vmess://' + body);
            if (!parsed) return false;

            var query = parseQuery(parsed.search);

            setFormValue(sid, 'type', 'vmess');
            setFormValue(sid, 'server', parsed.hostname);
            setFormValue(sid, 'port', parsed.port || '443');
            setFormValue(sid, 'uuid', parsed.username);
            setFormValue(sid, 'alterId', 0);
            setFormValue(sid, 'securitys', query.encryption || 'auto');

            if (parsed.hash) {
                setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
            }

            return true;
        } catch (e2) {
            return false;
        }
    }
}

function parseVless(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    var query = parseQuery(parsed.search);

    setFormValue(sid, 'type', 'vless');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || '443');
    setFormValue(sid, 'uuid', parsed.username);

    if (query.security) {
        if (query.security === 'tls' || query.security === 'xtls') {
            setFormValue(sid, 'tls', 'true');
            if (query.sni) {
                setFormValue(sid, 'servername', decodeURIComponent(query.sni));
            }
            if (query.security === 'xtls') {
                setFormValue(sid, 'vless_flow', query.flow || 'xtls-rprx-direct');
            }
        } else if (query.security === 'reality') {
            setFormValue(sid, 'tls', 'true');
            if (query.sni) {
                setFormValue(sid, 'servername', decodeURIComponent(query.sni));
            }
            if (query.pbk || query['public-key']) {
                setFormValue(sid, 'reality_public_key', query.pbk || query['public-key']);
            }
            if (query.sid || query['short-id']) {
                setFormValue(sid, 'reality_short_id', query.sid || query['short-id']);
            }
        }
    }

    var network = (query.type || 'tcp').toLowerCase();
    if (network === 'ws') {
        setFormValue(sid, 'obfs_vless', 'ws');
        setFormValue(sid, 'ws_opts_path', decodeURIComponent(query.path || '/'));
        if (query.host) {
            setFormValue(sid, 'ws_opts_headers', 'Host: ' + decodeURIComponent(query.host));
        }
    } else if (network === 'grpc') {
        setFormValue(sid, 'obfs_vless', 'grpc');
        setFormValue(sid, 'grpc_service_name', decodeURIComponent(query.serviceName || query.path || ''));
    } else {
        setFormValue(sid, 'obfs_vless', 'tcp');
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    }

    return true;
}

function parseTrojan(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    var query = parseQuery(parsed.search);

    setFormValue(sid, 'type', 'trojan');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || '443');
    setFormValue(sid, 'password', parsed.username);

    if (query.sni) {
        setFormValue(sid, 'sni', decodeURIComponent(query.sni));
    }

    if (query.alpn) {
        // Handle ALPN - multiple values support, decode properly
        setFormValue(sid, 'alpn', decodeURIComponent(query.alpn));
    }

    var network = (query.type || '').toLowerCase();
    if (network === 'ws') {
        setFormValue(sid, 'obfs_trojan', 'ws');
        setFormValue(sid, 'trojan_ws_path', decodeURIComponent(query.path || '/'));
        if (query.host) {
            setFormValue(sid, 'trojan_ws_headers', 'Host: ' + decodeURIComponent(query.host));
        }
    } else if (network === 'grpc') {
        setFormValue(sid, 'obfs_trojan', 'grpc');
        setFormValue(sid, 'grpc_service_name', decodeURIComponent(query.serviceName || ''));
    }

    if (query.allowInsecure === '1') {
        setFormValue(sid, 'skip_cert_verify', 'true');
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    }

    return true;
}

function parseHysteria(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    var query = parseQuery(parsed.search);

    setFormValue(sid, 'type', 'hysteria');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || '443');

    if (query.auth) {
        setFormValue(sid, 'hysteria_auth_str', decodeURIComponent(query.auth));
    }

    if (query.protocol) {
        setFormValue(sid, 'flag_transport', '1');
        setFormValue(sid, 'hysteria_protocol', query.protocol);
    }

    if (query.up || query.upmbps) {
        var upSpeed = decodeURIComponent(query.up || query.upmbps);
        upSpeed = upSpeed.replace(/[^0-9]/g, '');
        setFormValue(sid, 'hysteria_up', upSpeed);
    }

    if (query.down || query.downmbps) {
        var downSpeed = decodeURIComponent(query.down || query.downmbps);
        downSpeed = downSpeed.replace(/[^0-9]/g, '');
        setFormValue(sid, 'hysteria_down', downSpeed);
    }

    if (query.obfs || query.obfsParam) {
        setFormValue(sid, 'hysteria_obfs', decodeURIComponent(query.obfs || query.obfsParam));
    }

    if (query.peer) {
        setFormValue(sid, 'sni', decodeURIComponent(query.peer));
    }

    if (query.alpn) {
        setFormValue(sid, 'hysteria_alpn', decodeURIComponent(query.alpn));
    }

    if (query.insecure === '1') {
        setFormValue(sid, 'skip_cert_verify', 'true');
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    }

    return true;
}

function parseHysteria2(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    var query = parseQuery(parsed.search);

    setFormValue(sid, 'type', 'hysteria2');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || '443');

    if (parsed.username) {
        setFormValue(sid, 'password', parsed.username);
    }

    if (query.obfs) {
        setFormValue(sid, 'hysteria_obfs', decodeURIComponent(query.obfs));
    }

    if (query['obfs-password']) {
        setFormValue(sid, 'hysteria_obfs_password', decodeURIComponent(query['obfs-password']));
    }

    if (query.up) {
        setFormValue(sid, 'hysteria_up', decodeURIComponent(query.up));
    }

    if (query.down) {
        setFormValue(sid, 'hysteria_down', decodeURIComponent(query.down));
    }

    if (query.sni) {
        setFormValue(sid, 'sni', decodeURIComponent(query.sni));
    }

    if (query.alpn) {
        setFormValue(sid, 'hysteria_alpn', decodeURIComponent(query.alpn));
    }

    if (query.insecure === '1') {
        setFormValue(sid, 'skip_cert_verify', 'true');
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    }

    return true;
}

function parseTuic(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    var query = parseQuery(parsed.search);

    setFormValue(sid, 'type', 'tuic');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || '443');

    // Check if it's v5 (has password) or v4 (token only)
    if (parsed.password) {
        setFormValue(sid, 'uuid', parsed.username);
        setFormValue(sid, 'password', parsed.password);
    } else {
        setFormValue(sid, 'tc_token', parsed.username);
    }

    if (query.congestion_control) {
        setFormValue(sid, 'congestion_controller', decodeURIComponent(query.congestion_control));
    }

    if (query.alpn) {
        setFormValue(sid, 'tc_alpn', decodeURIComponent(query.alpn));
    }

    if (query.sni) {
        setFormValue(sid, 'sni', decodeURIComponent(query.sni));
    }

    if (query.disable_sni === '1') {
        setFormValue(sid, 'disable_sni', 'true');
    }

    if (query.udp_relay_mode) {
        setFormValue(sid, 'udp_relay_mode', decodeURIComponent(query.udp_relay_mode));
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    }

    return true;
}

function parseSocks(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    setFormValue(sid, 'type', 'socks5');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || '1080');

    if (parsed.username) {
        try {
            var decoded = atob(parsed.username);
            var parts = decoded.split(':');
            setFormValue(sid, 'auth_name', parts[0] || '');
            setFormValue(sid, 'auth_pass', parts[1] || '');
        } catch (e) {
            setFormValue(sid, 'auth_name', parsed.username);
            if (parsed.password) {
                setFormValue(sid, 'auth_pass', parsed.password);
            }
        }
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    } else {
        setFormValue(sid, 'name', parsed.hostname + ':' + parsed.port);
    }

    return true;
}

function parseHttp(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    setFormValue(sid, 'type', 'http');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || (parsed.protocol === 'https:' ? '443' : '80'));

    if (parsed.protocol === 'https:') {
        setFormValue(sid, 'tls', 'true');
    }

    if (parsed.username) {
        try {
            var decoded = atob(parsed.username);
            var parts = decoded.split(':');
            setFormValue(sid, 'auth_name', parts[0] || '');
            setFormValue(sid, 'auth_pass', parts[1] || '');
        } catch (e) {
            setFormValue(sid, 'auth_name', parsed.username);
            if (parsed.password) {
                setFormValue(sid, 'auth_pass', parsed.password);
            }
        }
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    } else {
        setFormValue(sid, 'name', parsed.hostname + ':' + parsed.port);
    }

    return true;
}

function parseAnyTLS(url, sid) {
    var parsed = parseUrl(url);
    if (!parsed) return false;

    var query = parseQuery(parsed.search);

    setFormValue(sid, 'type', 'anytls');
    setFormValue(sid, 'server', parsed.hostname);
    setFormValue(sid, 'port', parsed.port || '443');
    setFormValue(sid, 'auth_name', parsed.username);
    setFormValue(sid, 'password', parsed.password || parsed.username);

    if (query.sni) {
        setFormValue(sid, 'sni', query.sni);
    }

    if (query.hpkp) {
        setFormValue(sid, 'fingerprint', query.hpkp);
    }

    if (query.insecure === '1') {
        setFormValue(sid, 'skip_cert_verify', 'true');
    }

    if (parsed.hash) {
        setFormValue(sid, 'name', decodeFragment(parsed.hash.substr(1)));
    } else {
        setFormValue(sid, 'name', parsed.hostname + ':' + parsed.port);
    }

    return true;
}

//]]>
</script>
<input type="button" class="btn cbi-button cbi-button-apply" value="<%:Import%>" onclick="return import_url(this, '<%=self.option%>', '<%=self.value%>')" />
<input type="button" class="btn cbi-button cbi-button-apply" value="<%:Export%>" onclick="return export_url(this, '<%=self.option%>', '<%=self.value%>')" />
<span id="<%=self.option%>-status"></span>
<%+cbi/valuefooter%>